|
|
|
#include <cassert>
|
|
|
|
|
|
|
|
#include "system/camerad/cameras/camera_common.h"
|
|
|
|
#include "system/camerad/cameras/camera_qcom2.h"
|
|
|
|
#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 DC_GAIN_AR0231 = 2.5;
|
|
|
|
|
|
|
|
const float DC_GAIN_ON_GREY_AR0231 = 0.2;
|
|
|
|
const float DC_GAIN_OFF_GREY_AR0231 = 0.3;
|
|
|
|
|
|
|
|
const int DC_GAIN_MIN_WEIGHT_AR0231 = 0;
|
|
|
|
const int DC_GAIN_MAX_WEIGHT_AR0231 = 1;
|
|
|
|
|
|
|
|
const float TARGET_GREY_FACTOR_AR0231 = 1.0;
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
const int ANALOG_GAIN_MIN_IDX_AR0231 = 0x1; // 0.25x
|
|
|
|
const int ANALOG_GAIN_REC_IDX_AR0231 = 0x6; // 0.8x
|
|
|
|
const int ANALOG_GAIN_MAX_IDX_AR0231 = 0xD; // 4.0x
|
|
|
|
const int ANALOG_GAIN_COST_DELTA_AR0231 = 0;
|
|
|
|
const float ANALOG_GAIN_COST_LOW_AR0231 = 0.1;
|
|
|
|
const float ANALOG_GAIN_COST_HIGH_AR0231 = 5.0;
|
|
|
|
|
|
|
|
const int EXPOSURE_TIME_MIN_AR0231 = 2; // with HDR, fastest ss
|
|
|
|
const int EXPOSURE_TIME_MAX_AR0231 = 0x0855; // with HDR, slowest ss, 40ms
|
|
|
|
|
|
|
|
std::map<uint16_t, std::pair<int, int>> ar0231_build_register_lut(CameraState *c, uint8_t *data) {
|
|
|
|
// This function builds a lookup table from register address, to a pair of indices in the
|
|
|
|
// buffer where to read this address. The buffer contains padding bytes,
|
|
|
|
// as well as markers to indicate the type of the next byte.
|
|
|
|
//
|
|
|
|
// 0xAA is used to indicate the MSB of the address, 0xA5 for the LSB of the address.
|
|
|
|
// Every byte of data (MSB and LSB) is preceded by 0x5A. Specifying an address is optional
|
|
|
|
// for contiguous ranges. See page 27-29 of the AR0231 Developer guide for more information.
|
|
|
|
|
|
|
|
int max_i[] = {1828 / 2 * 3, 1500 / 2 * 3};
|
|
|
|
auto get_next_idx = [](int cur_idx) {
|
|
|
|
return (cur_idx % 3 == 1) ? cur_idx + 2 : cur_idx + 1; // Every third byte is padding
|
|
|
|
};
|
|
|
|
|
|
|
|
std::map<uint16_t, std::pair<int, int>> registers;
|
|
|
|
for (int register_row = 0; register_row < 2; register_row++) {
|
|
|
|
uint8_t *registers_raw = data + c->ci->frame_stride * register_row;
|
|
|
|
assert(registers_raw[0] == 0x0a); // Start of line
|
|
|
|
|
|
|
|
int value_tag_count = 0;
|
|
|
|
int first_val_idx = 0;
|
|
|
|
uint16_t cur_addr = 0;
|
|
|
|
|
|
|
|
for (int i = 1; i <= max_i[register_row]; i = get_next_idx(get_next_idx(i))) {
|
|
|
|
int val_idx = get_next_idx(i);
|
|
|
|
|
|
|
|
uint8_t tag = registers_raw[i];
|
|
|
|
uint16_t val = registers_raw[val_idx];
|
|
|
|
|
|
|
|
if (tag == 0xAA) { // Register MSB tag
|
|
|
|
cur_addr = val << 8;
|
|
|
|
} else if (tag == 0xA5) { // Register LSB tag
|
|
|
|
cur_addr |= val;
|
|
|
|
cur_addr -= 2; // Next value tag will increment address again
|
|
|
|
} else if (tag == 0x5A) { // Value tag
|
|
|
|
|
|
|
|
// First tag
|
|
|
|
if (value_tag_count % 2 == 0) {
|
|
|
|
cur_addr += 2;
|
|
|
|
first_val_idx = val_idx;
|
|
|
|
} else {
|
|
|
|
registers[cur_addr] = std::make_pair(first_val_idx + c->ci->frame_stride * register_row, val_idx + c->ci->frame_stride * register_row);
|
|
|
|
}
|
|
|
|
|
|
|
|
value_tag_count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return registers;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::map<uint16_t, uint16_t> ar0231_parse_registers(CameraState *c, uint8_t *data, std::initializer_list<uint16_t> addrs) {
|
|
|
|
if (c->ar0231_register_lut.empty()) {
|
|
|
|
c->ar0231_register_lut = ar0231_build_register_lut(c, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::map<uint16_t, uint16_t> registers;
|
|
|
|
for (uint16_t addr : addrs) {
|
|
|
|
auto offset = c->ar0231_register_lut[addr];
|
|
|
|
registers[addr] = ((uint16_t)data[offset.first] << 8) | data[offset.second];
|
|
|
|
}
|
|
|
|
return registers;
|
|
|
|
}
|
|
|
|
|
|
|
|
float ar0231_parse_temp_sensor(uint16_t calib1, uint16_t calib2, uint16_t data_reg) {
|
|
|
|
// See AR0231 Developer Guide - page 36
|
|
|
|
float slope = (125.0 - 55.0) / ((float)calib1 - (float)calib2);
|
|
|
|
float t0 = 55.0 - slope * (float)calib2;
|
|
|
|
return t0 + slope * (float)data_reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
CameraAR0231::CameraAR0231() {
|
|
|
|
frame_width = FRAME_WIDTH;
|
|
|
|
frame_height = FRAME_HEIGHT;
|
|
|
|
frame_stride = FRAME_STRIDE;
|
|
|
|
extra_height = AR0231_REGISTERS_HEIGHT + AR0231_STATS_HEIGHT;
|
|
|
|
|
|
|
|
registers_offset = 0;
|
|
|
|
frame_offset = AR0231_REGISTERS_HEIGHT;
|
|
|
|
stats_offset = AR0231_REGISTERS_HEIGHT + FRAME_HEIGHT;
|
|
|
|
|
|
|
|
dc_gain_factor = DC_GAIN_AR0231;
|
|
|
|
dc_gain_min_weight = DC_GAIN_MIN_WEIGHT_AR0231;
|
|
|
|
dc_gain_max_weight = DC_GAIN_MAX_WEIGHT_AR0231;
|
|
|
|
dc_gain_on_grey = DC_GAIN_ON_GREY_AR0231;
|
|
|
|
dc_gain_off_grey = DC_GAIN_OFF_GREY_AR0231;
|
|
|
|
exposure_time_min = EXPOSURE_TIME_MIN_AR0231;
|
|
|
|
exposure_time_max = EXPOSURE_TIME_MAX_AR0231;
|
|
|
|
analog_gain_min_idx = ANALOG_GAIN_MIN_IDX_AR0231;
|
|
|
|
analog_gain_rec_idx = ANALOG_GAIN_REC_IDX_AR0231;
|
|
|
|
analog_gain_max_idx = ANALOG_GAIN_MAX_IDX_AR0231;
|
|
|
|
analog_gain_cost_delta = ANALOG_GAIN_COST_DELTA_AR0231;
|
|
|
|
analog_gain_cost_low = ANALOG_GAIN_COST_LOW_AR0231;
|
|
|
|
analog_gain_cost_high = ANALOG_GAIN_COST_HIGH_AR0231;
|
|
|
|
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 = TARGET_GREY_FACTOR_AR0231;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ar0231_process_registers(MultiCameraState *s, CameraState *c, cereal::FrameData::Builder &framed) {
|
|
|
|
const uint8_t expected_preamble[] = {0x0a, 0xaa, 0x55, 0x20, 0xa5, 0x55};
|
|
|
|
uint8_t *data = (uint8_t *)c->buf.cur_camera_buf->addr + c->ci->registers_offset;
|
|
|
|
|
|
|
|
if (memcmp(data, expected_preamble, std::size(expected_preamble)) != 0) {
|
|
|
|
LOGE("unexpected register data found");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto registers = ar0231_parse_registers(c, data, {0x2000, 0x2002, 0x20b0, 0x20b2, 0x30c6, 0x30c8, 0x30ca, 0x30cc});
|
|
|
|
|
|
|
|
uint32_t frame_id = ((uint32_t)registers[0x2000] << 16) | registers[0x2002];
|
|
|
|
framed.setFrameIdSensor(frame_id);
|
|
|
|
|
|
|
|
float temp_0 = ar0231_parse_temp_sensor(registers[0x30c6], registers[0x30c8], registers[0x20b0]);
|
|
|
|
float temp_1 = ar0231_parse_temp_sensor(registers[0x30ca], registers[0x30cc], registers[0x20b2]);
|
|
|
|
framed.setTemperaturesC({temp_0, temp_1});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<struct i2c_random_wr_payload> ar0231_get_exp_registers(const CameraInfo *ci, int exposure_time, int new_exp_g, bool dc_gain_enabled) {
|
|
|
|
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},
|
|
|
|
};
|
|
|
|
}
|