• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "edidparse.h"
17 #include "window_manager_hilog.h"
18 
19 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, OHOS::Rosen::HILOG_DOMAIN_DISPLAY, "EdidParse"};
20 constexpr uint32_t EDID_BLOCK_SIZE = 128;
21 constexpr uint32_t EDID_MAX_BLOCK = 4;
22 constexpr uint32_t EDID_MAX_SIZE = EDID_BLOCK_SIZE * EDID_MAX_BLOCK;
23 constexpr uint32_t ONE_NUMBER_OF_BYTES = 8;
24 constexpr uint32_t TWO_NUMBER_OF_BYTES = 16;
25 constexpr uint32_t THREE_NUMBER_OF_BYTES = 24;
26 constexpr uint8_t EDID_VENDOR_START = 0x8;
27 constexpr uint8_t EDID_VENDOR_END = 0x11;
28 constexpr size_t BASE_YEAR = 1990;
29 constexpr size_t SN_SECOND_NUM = 2;
30 constexpr size_t SN_THIRD_NUM = 3;
31 constexpr uint8_t BASE_MINOR = 4;
32 constexpr size_t EDID_MINOR_OFFSET = 0x13;
33 constexpr size_t MANUFACTURE_WEEK_OFFSET = 0x10;
34 constexpr size_t MANUFACTURE_YEAR_OFFSET = 0x11;
35 
36 
37 template <size_t I>
GetLetter(uint16_t id)38 char GetLetter(uint16_t id)
39 {
40     static_assert(I < 3);
41     const char letter = 'A' + (static_cast<uint8_t>(id >> ((2 - I) * 5)) & 0b00011111) - 1;
42     return letter < 'A' || letter > 'Z' ? '\0' : letter;
43 }
44 
GetManufacturerNameFromNum(uint16_t manufacturerId)45 static std::string GetManufacturerNameFromNum(uint16_t manufacturerId)
46 {
47     std::string manufacturerName;
48     constexpr uint32_t secondLetter = 2;
49     manufacturerName.push_back(GetLetter<0>(manufacturerId));
50     manufacturerName.push_back(GetLetter<1>(manufacturerId));
51     manufacturerName.push_back(GetLetter<secondLetter>(manufacturerId));
52     return manufacturerName;
53 }
54 
CheckEdidValid(const std::vector<uint8_t> & edid)55 static bool CheckEdidValid(const std::vector<uint8_t>& edid)
56 {
57     if (edid.empty() || edid.size() % EDID_BLOCK_SIZE != 0) {
58         WLOGFE("edid is invalid, size = %{public}u", static_cast<uint32_t>(edid.size()));
59         return false;
60     }
61     const uint8_t magicStr[] = {0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0};
62     return std::equal(std::begin(magicStr), std::end(magicStr), edid.begin());
63 }
64 
ParseEdidText(const std::vector<uint8_t> & edid)65 static std::string ParseEdidText(const std::vector<uint8_t>& edid)
66 {
67     std::string text(reinterpret_cast<const char*>(edid.data()), edid.size());
68     text = text.substr(0, text.find('\n'));
69     if (!std::all_of(text.begin(), text.end(), ::isprint)) {
70         WLOGFW("edid text is empty");
71         return {};
72     }
73     return text;
74 }
75 
ParseDetailedTiming(const std::vector<uint8_t> & edid,struct baseEdid * outEdid)76 static void ParseDetailedTiming(const std::vector<uint8_t>& edid, struct baseEdid* outEdid)
77 {
78     constexpr size_t detailedTimingDescriptorStart = 0x36;
79     constexpr size_t detailedTimingDescriptorend = 0x6c;
80     constexpr size_t eachDetailedTimingDescriptorSize = 0x12;
81     constexpr size_t displayProductNameTag = 0xfc;
82     constexpr size_t alphanumericDataStringTag = 0xfe;
83     constexpr size_t displayProductSerialNumberTag = 0xff;
84     constexpr size_t displayDescriptorTagOffset = 3;
85     constexpr size_t displayDescriptorTagStart = 5;
86     constexpr size_t displayDescriptorTagEnd = 18;
87     for (size_t i = detailedTimingDescriptorStart; i <= detailedTimingDescriptorend;
88         i += eachDetailedTimingDescriptorSize) {
89         const size_t displayDescriptorTag = edid[i + displayDescriptorTagOffset];
90         std::vector<uint8_t> descriptorVec;
91         descriptorVec.assign(edid.begin() + i + displayDescriptorTagStart, edid.begin() + i + displayDescriptorTagEnd);
92         switch (displayDescriptorTag) {
93             case displayProductNameTag:
94                 outEdid->displayProductName = ParseEdidText(descriptorVec);
95                 break;
96             case alphanumericDataStringTag:
97                 outEdid->asciiText = ParseEdidText(descriptorVec);
98                 break;
99             case displayProductSerialNumberTag:
100                 outEdid->displayProductSerialNumber = ParseEdidText(descriptorVec);
101                 break;
102             default:
103                 break;
104         }
105     }
106     outEdid->modelName = outEdid->displayProductName;
107     if (outEdid->modelName.empty()) {
108         WLOGFW("display product name is empty");
109         outEdid->modelName = outEdid->displayProductSerialNumber;
110     }
111     if (outEdid->modelName.empty()) {
112         WLOGFW("display product serial number is empty");
113         outEdid->modelName = outEdid->asciiText;
114     }
115 }
116 
CheckParamsValid(const uint8_t * edidData,const uint32_t edidSize,BaseEdid * outEdid)117 static bool CheckParamsValid(const uint8_t* edidData, const uint32_t edidSize, BaseEdid* outEdid)
118 {
119     if (!edidData || !outEdid) {
120         WLOGFE("edid is nullptr or outEdid i nullptr");
121         return false;
122     }
123     WLOGFW("edid size is %{public}u", edidSize);
124     if (edidSize == 0 || edidSize % EDID_BLOCK_SIZE != 0 || edidSize > EDID_MAX_SIZE) {
125         return false;
126     }
127     return true;
128 }
129 
130 extern "C" {
ParseBaseEdid(const uint8_t * edidData,const uint32_t edidSize,struct baseEdid * outEdid)131 int ParseBaseEdid(const uint8_t* edidData, const uint32_t edidSize, struct baseEdid* outEdid)
132 {
133     if (!CheckParamsValid(edidData, edidSize, outEdid)) {
134         return -1;
135     }
136 
137     std::vector<uint8_t> edid(edidData, edidData + edidSize);
138     if (!CheckEdidValid(edid)) {
139         return -1;
140     }
141 
142     uint32_t vendorDataSum = 0;
143     for (uint32_t i = EDID_VENDOR_START; i <= EDID_VENDOR_END; i++) {
144         vendorDataSum += edid[i];
145     }
146     WLOGFW("parseBaseEdid vendorDataSum is %{public}u", vendorDataSum);
147 
148     // get the edid version
149     outEdid->edid_minor = edid[EDID_MINOR_OFFSET];
150 
151     // get the manufacturer name
152     constexpr size_t manufacturerNameOffset = 0x8;
153     outEdid->manufacturerName =
154             GetManufacturerNameFromNum(static_cast<uint16_t>((edid[manufacturerNameOffset] << ONE_NUMBER_OF_BYTES) |
155             edid[manufacturerNameOffset + 1]));
156 
157     // get the product code
158     constexpr size_t productIdOffset = 0xa;
159     outEdid->productCode = static_cast<uint16_t>(edid[productIdOffset] |
160         (edid[productIdOffset + 1] << ONE_NUMBER_OF_BYTES));
161 
162     //get the serial number
163     constexpr size_t serialNumberOffset = 0xc;
164 
165     outEdid->serialNumber = static_cast<uint32_t>(edid[serialNumberOffset] |
166         (edid[serialNumberOffset + 1] << ONE_NUMBER_OF_BYTES) |
167         (edid[serialNumberOffset + SN_SECOND_NUM] << TWO_NUMBER_OF_BYTES) |
168         (edid[serialNumberOffset + SN_THIRD_NUM] << THREE_NUMBER_OF_BYTES));
169 
170     // get the manufacture week and year
171     outEdid->weekOfManufactureOrModelYearFlag = edid[MANUFACTURE_WEEK_OFFSET];
172     outEdid->yearOfManufactureOrModelYear = edid[MANUFACTURE_YEAR_OFFSET] + BASE_YEAR;
173 
174     // get the bpc
175     constexpr size_t videoInputDefinitionOffset = 0x14;
176     uint8_t bpc = 0;
177     constexpr uint8_t bpcHighNum = 3;
178     constexpr uint8_t bpcNumOffset = 4;
179     if ((edid[videoInputDefinitionOffset] & 0x80) && (outEdid->edid_minor >= BASE_MINOR)) {
180         uint8_t colorBitDepth = edid[videoInputDefinitionOffset] & 0x70;
181         if (!(colorBitDepth == 0x00 || colorBitDepth == 0x70)) {
182             bpc = ((colorBitDepth >> bpcHighNum) + bpcNumOffset);
183         }
184     }
185     outEdid->bitsPerPrimaryColor = bpc;
186 
187     // get the screen size
188     constexpr size_t HorizontalSceenSizeOffset = 0x15;
189     constexpr size_t VerticalSceenSizeOffset = 0x16;
190     if (edid[HorizontalSceenSizeOffset] != 0 && edid[VerticalSceenSizeOffset] != 0) {
191         outEdid->hScreenSize = edid[HorizontalSceenSizeOffset];
192         outEdid->vScreenSize = edid[VerticalSceenSizeOffset];
193     }
194 
195     // get the detailed timing
196     ParseDetailedTiming(edid, outEdid);
197     WLOGFW("parseBaseEdid edid_minor is %{public}u, ScreenSize is %{public}u cm * %{public}u cm, bpc is %{public}u",
198         outEdid->edid_minor, outEdid->hScreenSize, outEdid->vScreenSize, outEdid->bitsPerPrimaryColor);
199     return 0;
200 }
201 }