Skip to content

Commit 75a883d

Browse files
luk1337moetayuko
authored andcommitted
sensors: fusionlight: Support black-frame V2.1 profiles
Profiles with BlackFrame30Support skip screen captures and report lux from the raw channels, as do V2.1 profiles without a leakage model. Default CWBScreenshotPeriod to 250ms, implement IR ratio formula 2, select V2.1 IR brightness levels by upper bound, treat brightness below 2 as screen off and apply LowLightAccuracy on every profile, like stock. Assisted-by: LLM Change-Id: Ic3987598501f102317535c2bc82e1b2a12f4f6d5
1 parent 0eb7b3b commit 75a883d

3 files changed

Lines changed: 87 additions & 29 deletions

File tree

‎sensors/fusionlight/FusionLightProcessor.cpp‎

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,18 @@ int FindViewSegment(const FusionConfig& config, int32_t brightness) {
7373
return brightness <= config.segment_brightness[1] ? 1 : 0;
7474
}
7575

76+
// V2.1 selects the first IR brightness range whose upper bound covers the
77+
// brightness, ignoring lower bounds. Unmatched brightness falls back to the
78+
// first range.
79+
int FindUpperRange(const std::vector<ValueRange>& ranges, double value) {
80+
for (int level = 0; level < ranges.size(); ++level) {
81+
if (value <= ranges[level].max) {
82+
return level;
83+
}
84+
}
85+
return 0;
86+
}
87+
7688
// Stock compares IR ratios and lux in fixed point with 1e-7 resolution.
7789
int64_t ToFixedPoint(double value) {
7890
constexpr double kLimit = 9.2e18;
@@ -126,17 +138,33 @@ bool HasAbsoluteIrRatio(int32_t sensor_module_id) {
126138
}
127139

128140
double IrRatio(const FusionConfig& config, const Channels& channels) {
129-
if (ToFixedPoint(channels[3]) <= 0) {
141+
const bool has_clear = ToFixedPoint(channels[3]) > 0;
142+
if (config.ir_ratio_formula == 2) {
143+
if (!has_clear) {
144+
return 1.0;
145+
}
146+
return std::max(1.0 - (channels[0] * 0.4379 + channels[1] * 0.243 + channels[2] * 0.2435) /
147+
channels[3],
148+
0.0);
149+
}
150+
if (!has_clear) {
130151
return 0.0;
131152
}
132153
double ratio = (channels[0] + channels[1] + channels[2] - channels[3]) / channels[3] * 0.5;
133-
// Stock folds negative view model ratios back for these sensor modules.
134-
if (!config.screenshot_v2_1_supported && HasAbsoluteIrRatio(config.sensor_module_id)) {
154+
// Stock folds negative ratios back for these sensor modules.
155+
if (HasAbsoluteIrRatio(config.sensor_module_id)) {
135156
ratio = std::abs(ratio);
136157
}
137158
return std::max(ratio, 0.0);
138159
}
139160

161+
// Black-frame profiles, and V2.1 profiles without a leakage model, report lux
162+
// from the raw channels without screen captures.
163+
bool UsesScreenCapture(const FusionConfig& config) {
164+
return !config.black_frame_supported &&
165+
(!config.screenshot_v2_1_supported || !config.leakage.empty());
166+
}
167+
140168
double EvaluatePolynomial(const Polynomial& polynomial, double x) {
141169
return ((polynomial[0] * x + polynomial[1]) * x + polynomial[2]) * x + polynomial[3];
142170
}
@@ -159,7 +187,7 @@ std::optional<double> CalculateLux(const FusionConfig& config, const Channels& c
159187
table = &config.channel_count_coefficients[band];
160188
} else if (config.screenshot_v2_1_supported) {
161189
table = &config.lux_coefficients[band];
162-
level = FindRange(config.ir_brightness, brightness);
190+
level = FindUpperRange(config.ir_brightness, brightness);
163191
} else {
164192
const auto& segment = config.segments[FindViewSegment(config, brightness)];
165193
table = &segment.lux_coefficients[band];
@@ -174,8 +202,7 @@ std::optional<double> CalculateLux(const FusionConfig& config, const Channels& c
174202
if (!std::isfinite(lux)) {
175203
return std::nullopt;
176204
}
177-
if (!config.screenshot_v2_1_supported &&
178-
ToFixedPoint(lux) < ToFixedPoint(config.low_light_accuracy)) {
205+
if (ToFixedPoint(lux) < ToFixedPoint(config.low_light_accuracy)) {
179206
lux = 0.0;
180207
}
181208
return std::max(lux, 0.0);
@@ -448,7 +475,9 @@ bool FusionLightProcessor::initializeLocked() {
448475

449476
std::vector<Channels> calibration;
450477
std::vector<ViewCalibration> view_calibration;
451-
if (config->screenshot_v2_1_supported) {
478+
if (!UsesScreenCapture(*config)) {
479+
LOG(INFO) << "FusionLight profile does not use screen captures";
480+
} else if (config->screenshot_v2_1_supported) {
452481
calibration = LoadCalibration(*config);
453482
} else {
454483
view_calibration = LoadViewCalibration(*config);
@@ -554,19 +583,33 @@ void FusionLightProcessor::process(const Event& event, int32_t fusion_light_hand
554583
return;
555584
}
556585
}
557-
const int32_t brightness = event.u.data[3];
586+
int32_t brightness = event.u.data[3];
587+
// Stock treats brightness below 2 as screen off.
588+
if (brightness < 2) {
589+
brightness = 0;
590+
}
558591
// Bit 1 of the event flags reports DC dimming.
559592
const bool dc_mode = static_cast<int32_t>(event.u.data[2]) & 0x2;
560593

561594
bool available;
595+
bool screen_capture = false;
562596
{
563597
std::lock_guard lock(state_->mutex);
564598
if (!state_->active) {
565599
return;
566600
}
567601
available = state_->available;
602+
if (available && brightness > 0) {
603+
screen_capture = UsesScreenCapture(state_->config);
604+
const auto lux =
605+
screen_capture ? std::nullopt
606+
: CalculateLux(state_->config, raw_channels, brightness, false);
607+
if (lux.has_value()) {
608+
fusion_light_event.u.scalar = *lux;
609+
}
610+
}
568611
}
569-
if (!available) {
612+
if (!available || (brightness > 0 && !screen_capture)) {
570613
enqueueReady(std::move(fusion_light_event));
571614
return;
572615
}

‎sensors/fusionlight/FusionLightUtils.cpp‎

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ constexpr int32_t kPanelInfoFeature = 9;
3434
constexpr int32_t kMainPanelStageFeature = 0x22;
3535
constexpr int32_t kDefaultPanelStage = 4;
3636
constexpr auto kCwbWeightsPath = "/odm/etc/display/cwb_weightspos.json";
37+
constexpr auto kDefaultScreenshotPeriod = 250ms;
3738

3839
bool ReadNumber(const Json::Value& value, double& result) {
3940
if (value.isString()) {
@@ -377,15 +378,27 @@ bool ParseV21Model(const Json::Value& root, FusionConfig& config, std::string& e
377378
!ParseRanges(root["IRBrightness_V2_1"], "BrightnessMin", "BrightnessMax",
378379
config.ir_brightness) ||
379380
!ParseRanges(root["IRThreshold_V2_1"], "IR_Ratio_Min", "IR_Ratio_Max",
380-
config.ir_thresholds) ||
381-
!ParseChannelModels(root["LinearityCompensation"], config.linearity) ||
382-
!ParseChannelModels(root["LightLeakageCalculation"], config.leakage) ||
383-
!ParseChannelModels(root["LightLeakageRatio"], config.leakage_ratio) ||
384-
!ParseGolden(root["LightLeakageGolden"], config.leakage_golden)) {
381+
config.ir_thresholds)) {
385382
error = "invalid V2.1 model";
386383
return false;
387384
}
388385

386+
// Profiles may omit the leakage model entirely. Stock then keeps zeroed
387+
// tables, which leaves the raw channels uncompensated.
388+
constexpr const char* kLeakageTables[] = {"LinearityCompensation", "LightLeakageCalculation",
389+
"LightLeakageRatio", "LightLeakageGolden"};
390+
const bool has_leakage_model =
391+
std::any_of(std::begin(kLeakageTables), std::end(kLeakageTables),
392+
[&](const char* name) { return !root[name].isNull(); });
393+
if (has_leakage_model &&
394+
(!ParseChannelModels(root["LinearityCompensation"], config.linearity) ||
395+
!ParseChannelModels(root["LightLeakageCalculation"], config.leakage) ||
396+
!ParseChannelModels(root["LightLeakageRatio"], config.leakage_ratio) ||
397+
!ParseGolden(root["LightLeakageGolden"], config.leakage_golden))) {
398+
error = "invalid V2.1 leakage model";
399+
return false;
400+
}
401+
389402
constexpr std::array<const char*, kIrBandCount> kDefaultTables = {
390403
"LuxCoeffLIR_V2_1", "LuxCoeffHIR_V2_1", "LuxCoeffSuperHIR_V2_1"};
391404
for (int band = 0; band < kIrBandCount; ++band) {
@@ -396,8 +409,9 @@ bool ParseV21Model(const Json::Value& root, FusionConfig& config, std::string& e
396409
}
397410

398411
const size_t levels = config.linearity_brightness.size();
399-
if (config.linearity.size() != levels || config.leakage.size() != levels ||
400-
config.leakage_ratio.size() != levels || config.leakage_golden.size() != levels ||
412+
if ((has_leakage_model &&
413+
(config.linearity.size() != levels || config.leakage.size() != levels ||
414+
config.leakage_ratio.size() != levels || config.leakage_golden.size() != levels)) ||
401415
config.ir_brightness.empty()) {
402416
error = "inconsistent V2.1 model dimensions";
403417
return false;
@@ -412,18 +426,6 @@ bool ParseV21Model(const Json::Value& root, FusionConfig& config, std::string& e
412426
}
413427

414428
bool ParseViewModel(const Json::Value& root, FusionConfig& config, std::string& error) {
415-
const auto& common = root["CommonConfig"];
416-
int32_t ir_ratio_formula = 0;
417-
if (common.isMember("IRRatioFormulaType") &&
418-
!ReadInt(common["IRRatioFormulaType"], ir_ratio_formula)) {
419-
error = "invalid IRRatioFormulaType";
420-
return false;
421-
}
422-
if (ir_ratio_formula != 0) {
423-
error = "unsupported IR ratio formula " + std::to_string(ir_ratio_formula);
424-
return false;
425-
}
426-
427429
if (!ParseRanges(root["LinearityBrightnessRange"], "BrightnessMin", "BrightnessMax",
428430
config.linearity_brightness) ||
429431
!ParseRanges(root["IRThreshold"], "IR_Ratio_Min", "IR_Ratio_Max", config.ir_thresholds) ||
@@ -478,17 +480,28 @@ bool ParseConfig(std::istream& stream, FusionConfig& config, std::string& error)
478480
!ReadRequiredInt(crop, "RightBottomY", config.cwb.crop_bottom) ||
479481
!ReadRequiredInt(resolution, "Width", config.cwb.reference_width) ||
480482
!ReadRequiredInt(resolution, "Height", config.cwb.reference_height) ||
481-
!ReadRequiredDuration(common, "CWBScreenshotPeriod", config.cwb.screenshot_period) ||
483+
(common.isMember("CWBScreenshotPeriod") &&
484+
!ReadRequiredDuration(common, "CWBScreenshotPeriod", config.cwb.screenshot_period)) ||
485+
(common.isMember("IRRatioFormulaType") &&
486+
!ReadInt(common["IRRatioFormulaType"], config.ir_ratio_formula)) ||
482487
(common.isMember("LowLightAccuracy") &&
483488
!ReadNumber(common["LowLightAccuracy"], config.low_light_accuracy)) ||
484489
(common["SensorModule"].isMember("SensorModuleId") &&
485490
!ReadInt(common["SensorModule"]["SensorModuleId"], config.sensor_module_id))) {
486491
error = "invalid CommonConfig";
487492
return false;
488493
}
494+
if (!common.isMember("CWBScreenshotPeriod")) {
495+
config.cwb.screenshot_period = kDefaultScreenshotPeriod;
496+
}
497+
if (config.ir_ratio_formula != 0 && config.ir_ratio_formula != 2) {
498+
error = "unsupported IR ratio formula " + std::to_string(config.ir_ratio_formula);
499+
return false;
500+
}
489501

490502
config.fusion_rgb_supported = common["FusionRGBSupported"].asBool();
491503
config.cwb_supported = common["CWBSupported"].asBool();
504+
config.black_frame_supported = common["BlackFrame30Support"].asBool();
492505
config.cwb.screenshot_weighted = common["SupportCWBScreenshotWeighted"].asBool();
493506
config.screenshot_v2_1_supported = common["SupportScreenshotAlgorithm_V2_1"].asBool();
494507
config.screen_off_lux_supported = common["ScreenOffCalLuxSupported"].asBool();

‎sensors/fusionlight/FusionLightUtils.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,12 @@ struct ViewSegment {
6060

6161
struct FusionConfig {
6262
int32_t sensor_module_id = 0;
63+
int32_t ir_ratio_formula = 0;
6364
double low_light_accuracy = 0.0;
6465

6566
bool fusion_rgb_supported = false;
6667
bool cwb_supported = false;
68+
bool black_frame_supported = false;
6769
bool screenshot_v2_1_supported = false;
6870
bool screen_off_lux_supported = false;
6971
bool channel_count_policy_supported = false;

0 commit comments

Comments
 (0)