1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "led_lut_calibrator.h"
18 
19 #include <android-base/logging.h>
20 #include <android-base/properties.h>
21 #include <fcntl.h>
22 
23 #include <iostream>
24 #include <sstream>
25 
26 using ::android::base::GetProperty;
27 
28 const char D_kCalibrationPath[] = "/mnt/vendor/persist/led/led_calibration_LUT.txt";
29 const char G_WHT_kCalibrationPath[] = "/vendor/etc/led_golden_calibration_LUT_white_CG.txt";
30 const char G_BLK_kCalibrationPath[] = "/vendor/etc/led_golden_calibration_LUT_black_CG.txt";
31 
LedLutCalibrator(PanelCalibrationStatus status)32 LedLutCalibrator::LedLutCalibrator(PanelCalibrationStatus status) {
33     cal_status_ = status;
34     if (!ReadCalibrationTable()) {
35         LOG(ERROR) << "Failed to read calibration table";
36         cal_table_.clear();
37     }
38 }
39 
GetByColorIntensity(const std::string & color,int intensity) const40 int LedLutCalibrator::GetByColorIntensity(const std::string &color, int intensity) const {
41     std::string key = MakeLutKey(color, intensity);
42     const auto cal_data = cal_table_.find(key);
43 
44     if (cal_data == cal_table_.end()) {
45         LOG(ERROR) << "Failed to get calibration data";
46         return -1;
47     }
48 
49     return cal_data->second;
50 }
51 
ReadCalibrationTable()52 bool LedLutCalibrator::ReadCalibrationTable() {
53     int fd;
54     int bytes;
55     bool ret = true;
56     const char *k_path = D_kCalibrationPath;
57     std::vector<uint8_t> buffer;
58     buffer.resize(512);
59 
60     fd = open(D_kCalibrationPath, O_RDONLY);
61     // If default calibration not found or display changed, deploy golen calibration.
62     if (fd < 0 || cal_status_ == PanelCalibrationStatus::GOLDEN) {
63         // Using golden white calibration as default
64         // even though bezel prooerty not found.
65         k_path = G_WHT_kCalibrationPath;
66         std::string cdt_hwid = GetProperty("ro.boot.cdt_hwid", "");
67         std::string hex_variant_str = cdt_hwid.substr(16, 2);
68         int bezel_color;
69         sscanf(hex_variant_str.c_str(), "%x", &bezel_color);
70         // 0: white, 2: black
71         if (bezel_color == 2)
72             k_path = G_BLK_kCalibrationPath;
73     }
74 
75     fd = open(k_path, O_RDONLY);
76     if (fd < 0) {
77         LOG(ERROR) << "Failed to open " << k_path;
78         ret = false;
79         goto ReadCalibrationTable_err;
80     }
81 
82     bytes = read(fd, buffer.data(), buffer.size());
83     if (bytes == -1) {
84         LOG(ERROR) << "Failed to read " << k_path;
85         ret = false;
86         goto ReadCalibrationTable_err;
87     }
88 
89     if (!ParseBlock(&buffer)) {
90         LOG(ERROR) << "Failed to parse calibration table ";
91         ret = false;
92         goto ReadCalibrationTable_err;
93     }
94 
95 ReadCalibrationTable_err:
96     if (fd != -1)
97         close(fd);
98 
99     return ret;
100 }
101 
ParseBlock(const std::vector<uint8_t> * table)102 bool LedLutCalibrator::ParseBlock(const std::vector<uint8_t> *table) {
103     std::string str(table->begin(), table->end());
104     auto result = std::vector<std::string>{};
105     auto ss = std::stringstream{str};
106 
107     for (std::string line; std::getline(ss, line, '\n');) {
108         size_t start;
109         size_t end = 0;
110         std::vector<std::string> colon_separated;
111         while ((start = line.find_first_not_of(':', end)) != std::string::npos) {
112             end = line.find(':', start);
113             if (end == std::string::npos) {
114                 end = line.size();
115             }
116             colon_separated.push_back(line.substr(start, end - start));
117         }
118         if (colon_separated.size() != 3) {
119             continue;
120         }
121         std::string color_name = colon_separated[0];
122         uint16_t intensity = atoi(colon_separated[1].c_str());
123         uint16_t pwm = atoi(colon_separated[2].c_str());
124         std::cout << color_name << intensity << pwm << std::endl;
125         std::string key = MakeLutKey(color_name, intensity);
126         cal_table_[key] = pwm;
127     }
128 
129     return true;
130 }
131 
MakeLutKey(const std::string & color,int intensity) const132 std::string LedLutCalibrator::MakeLutKey(const std::string &color, int intensity) const {
133     std::string intensity_str = std::to_string(intensity);
134     std::string terms{color};
135 
136     terms.append(intensity_str);
137 
138     return terms;
139 }
140