1/*
2 * Copyright (c) 2022-2023 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 "battery_config.h"
17
18#include "string_ex.h"
19#ifdef HAS_BATTERY_CONFIG_POLICY_PART
20#include "config_policy_utils.h"
21#endif
22#include "charger_log.h"
23
24namespace OHOS {
25namespace PowerMgr {
26namespace {
27#ifdef HAS_BATTERY_CONFIG_POLICY_PART
28constexpr const char* BATTERY_CONFIG_EXCEPTION_PATH = "";
29constexpr const char* BATTERY_CONFIG_PATH = "etc/battery/battery_config.json";
30#endif
31constexpr const char* SYSTEM_BATTERY_CONFIG_PATH = "/system/etc/battery/battery_config.json";
32constexpr const char* VENDOR_BATTERY_CONFIG_PATH = "/vendor/etc/battery/battery_config.json";
33constexpr int32_t MAP_KEY_INDEX = 0;
34constexpr int32_t BEGIN_SOC_INDEX = 0;
35constexpr int32_t END_SOC_INDEX = 1;
36constexpr int32_t MAX_SOC_RANGE = 2;
37constexpr int32_t RED_INDEX = 0;
38constexpr int32_t GREEN_INDEX = 1;
39constexpr int32_t BLUE_INDEX = 2;
40constexpr int32_t MAX_RGB_RANGE = 3;
41constexpr int32_t MAX_DEPTH = 5;
42constexpr int32_t MIN_DEPTH = 1;
43constexpr uint32_t MOVE_LEFT_16 = 16;
44constexpr uint32_t MOVE_LEFT_8 = 8;
45} // namespace
46std::shared_ptr<BatteryConfig> BatteryConfig::instance_ = nullptr;
47std::mutex BatteryConfig::mutex_;
48
49BatteryConfig& BatteryConfig::GetInstance()
50{
51    std::lock_guard<std::mutex> lock(mutex_);
52    if (instance_ == nullptr) {
53        instance_ = std::make_shared<BatteryConfig>();
54    }
55    return *(instance_.get());
56}
57
58#ifdef HAS_BATTERY_CONFIG_POLICY_PART
59bool BatteryConfig::ParseConfig()
60{
61    char buf[MAX_PATH_LEN];
62    char* path = GetOneCfgFile(BATTERY_CONFIG_PATH, buf, MAX_PATH_LEN);
63    if (path == nullptr || *path == '\0') {
64        BATTERY_HILOGW(FEATURE_CHARGING, "GetOneCfgFile battery_config.json is NULL");
65        path = const_cast<char*>(BATTERY_CONFIG_EXCEPTION_PATH);
66    }
67    BATTERY_HILOGD(FEATURE_CHARGING, "GetOneCfgFile battery_config.json");
68
69    Json::CharReaderBuilder readerBuilder;
70    std::ifstream ifsConf;
71    if (!OpenFile(ifsConf, path)) {
72        return false;
73    }
74
75    config_.clear();
76    readerBuilder["collectComments"] = false;
77    JSONCPP_STRING errs;
78
79    if (parseFromStream(readerBuilder, ifsConf, &config_, &errs) && !config_.empty()) {
80        ParseConfInner();
81    }
82    ifsConf.close();
83    return true;
84}
85#endif
86
87bool BatteryConfig::IsExist(std::string key) const
88{
89    return !GetValue(key).isNull();
90}
91
92int32_t BatteryConfig::GetInt(std::string key, int32_t defVal) const
93{
94    Json::Value value = GetValue(key);
95    return (value.isNull() || !value.isInt()) ? defVal : value.asInt();
96}
97
98std::string BatteryConfig::GetString(std::string key, std::string defVal) const
99{
100    Json::Value value = GetValue(key);
101    return (value.isNull() || !value.isString()) ? defVal : value.asString();
102}
103
104const std::vector<BatteryConfig::LightConf>& BatteryConfig::GetLightConf() const
105{
106    return lightConf_;
107}
108
109void BatteryConfig::DestroyInstance()
110{
111    std::lock_guard<std::mutex> lock(mutex_);
112    instance_ = nullptr;
113}
114
115bool BatteryConfig::OpenFile(std::ifstream& ifsConf, const std::string& configPath)
116{
117    bool isOpen = false;
118    if (!configPath.empty()) {
119        ifsConf.open(configPath);
120        isOpen = ifsConf.is_open();
121        BATTERY_HILOGD(FEATURE_CHARGING, "open configPath file is %{public}d", isOpen);
122    }
123    if (isOpen) {
124        return true;
125    }
126
127    ifsConf.open(VENDOR_BATTERY_CONFIG_PATH);
128    isOpen = ifsConf.is_open();
129    BATTERY_HILOGI(FEATURE_CHARGING, "open then vendor battery_config.json is %{public}d", isOpen);
130
131    if (isOpen) {
132        return true;
133    }
134
135    ifsConf.open(SYSTEM_BATTERY_CONFIG_PATH);
136    isOpen = ifsConf.is_open();
137    BATTERY_HILOGI(FEATURE_CHARGING, "open then system battery_config.json is %{public}d", isOpen);
138    return isOpen;
139}
140
141void BatteryConfig::ParseConfInner()
142{
143    lightConf_.clear();
144    ParseLightConf("low");
145    ParseLightConf("normal");
146    ParseLightConf("high");
147    BATTERY_HILOGD(FEATURE_CHARGING, "The battery light configuration size %{public}d",
148        static_cast<int32_t>(lightConf_.size()));
149}
150
151void BatteryConfig::ParseLightConf(std::string level)
152{
153    Json::Value soc = GetValue("light." + level + ".soc");
154    Json::Value rgb = GetValue("light." + level + ".rgb");
155    if (!soc.isArray() || !rgb.isArray()) {
156        BATTERY_HILOGW(FEATURE_CHARGING, "The battery light %{public}s configuration is invalid.", level.c_str());
157        return;
158    }
159
160    if (soc.size() != MAX_SOC_RANGE || !soc[BEGIN_SOC_INDEX].isInt() || !soc[END_SOC_INDEX].isInt()) {
161        BATTERY_HILOGW(FEATURE_CHARGING, "The battery light %{public}s soc data type error.", level.c_str());
162        return;
163    }
164    if (rgb.size() != MAX_RGB_RANGE || !rgb[RED_INDEX].isUInt() || !rgb[GREEN_INDEX].isUInt() ||
165        !rgb[BLUE_INDEX].isUInt()) {
166        BATTERY_HILOGW(FEATURE_CHARGING, "The battery light %{public}s rgb data type error.", level.c_str());
167        return;
168    }
169    BatteryConfig::LightConf lightConf = {
170        .beginSoc = soc[BEGIN_SOC_INDEX].asInt(),
171        .endSoc = soc[END_SOC_INDEX].asInt(),
172        .rgb = (rgb[RED_INDEX].asUInt() << MOVE_LEFT_16) |
173               (rgb[GREEN_INDEX].asUInt() << MOVE_LEFT_8) |
174               rgb[BLUE_INDEX].asUInt()
175    };
176    lightConf_.push_back(lightConf);
177}
178
179Json::Value BatteryConfig::FindConf(const std::string& key) const
180{
181    return (config_.isObject() && config_.isMember(key)) ? config_[key] : Json::Value();
182}
183
184bool BatteryConfig::SplitKey(const std::string& key, std::vector<std::string>& keys) const
185{
186    SplitStr(TrimStr(key), ".", keys);
187    return (keys.size() < MIN_DEPTH || keys.size() > MAX_DEPTH) ? false : true;
188}
189
190Json::Value BatteryConfig::GetValue(std::string key) const
191{
192    std::vector<std::string> keys;
193    if (!SplitKey(key, keys)) {
194        BATTERY_HILOGW(FEATURE_CHARGING, "The key does not meet the. key=%{public}s", key.c_str());
195        return Json::Value();
196    }
197
198    Json::Value value = FindConf(keys[MAP_KEY_INDEX]);
199    if (value.isNull()) {
200        BATTERY_HILOGD(FEATURE_CHARGING, "Value is empty. key=%{public}s", key.c_str());
201        return value;
202    }
203
204    for (size_t i = 1; i < keys.size(); ++i) {
205        if (!value.isObject() || !value.isMember(keys[i])) {
206            BATTERY_HILOGW(FEATURE_CHARGING, "The key is not configured. key=%{public}s", keys[i].c_str());
207            break;
208        }
209        value = value[keys[i]];
210    }
211    return value;
212}
213} // namespace PowerMgr
214} // namespace OHOS
215