1 /******************************************************************************
2 *
3 * Copyright (C) 2011-2012 Broadcom Corporation
4 * Copyright 2018-2019, 2023 NXP
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at:
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 ******************************************************************************/
19 //#define LOG_NDEBUG 0
20 #define LOG_TAG "NxpUwbConf"
21
22 #include <sys/stat.h>
23
24 #include <iomanip>
25 #include <memory>
26 #include <sstream>
27 #include <limits.h>
28 #include <stdio.h>
29 #include <sstream>
30 #include <string>
31 #include <unordered_map>
32 #include <unordered_set>
33 #include <vector>
34
35 #include <android-base/logging.h>
36 #include <cutils/properties.h>
37 #include <log/log.h>
38
39 #include "phNxpConfig.h"
40 #include "phNxpUciHal.h"
41 #include "phNxpUciHal_ext.h"
42 #include "phNxpUciHal_utils.h"
43 #include "phNxpLog.h"
44
45 static const char default_nxp_config_path[] = "/vendor/etc/libuwb-nxp.conf";
46 static const char country_code_config_name[] = "libuwb-countrycode.conf";
47 static const char nxp_uci_config_file[] = "libuwb-uci.conf";
48 static const char default_uci_config_path[] = "/vendor/etc/";
49
50 static const char country_code_specifier[] = "<country>";
51 static const char sku_specifier[] = "<sku>";
52
53 static const char prop_name_calsku[] = "persist.vendor.uwb.cal.sku";
54 static const char prop_default_calsku[] = "defaultsku";
55
56 using namespace::std;
57
58 class uwbParam
59 {
60 public:
61 enum class type { STRING, NUMBER, BYTEARRAY, STRINGARRAY };
62 uwbParam();
63 uwbParam(const uwbParam& param);
64 uwbParam(uwbParam&& param);
65
66 uwbParam(const string& value);
67 uwbParam(vector<uint8_t>&& value);
68 uwbParam(unsigned long value);
69 uwbParam(vector<string>&& value);
70
71 virtual ~uwbParam();
72
getType() const73 type getType() const { return m_type; }
numValue() const74 unsigned long numValue() const {return m_numValue;}
str_value() const75 const char* str_value() const {return m_str_value.c_str();}
str_len() const76 size_t str_len() const {return m_str_value.length();}
arr_value() const77 const uint8_t* arr_value() const { return m_arrValue.data(); }
arr_len() const78 size_t arr_len() const { return m_arrValue.size(); }
79
str_arr_len() const80 size_t str_arr_len() const { return m_arrStrValue.size(); }
str_arr_elem(const int index) const81 const char* str_arr_elem(const int index) const { return m_arrStrValue[index].c_str(); }
str_arr_elem_len(const int index) const82 size_t str_arr_elem_len(const int index) const { return m_arrStrValue[index].length(); }
83
84 void dump(const string &tag) const;
85 private:
86 unsigned long m_numValue;
87 string m_str_value;
88 vector<uint8_t> m_arrValue;
89 vector<string> m_arrStrValue;
90 type m_type;
91 };
92
93 class CUwbNxpConfig
94 {
95 public:
96 CUwbNxpConfig();
97 CUwbNxpConfig(CUwbNxpConfig&& config);
98 CUwbNxpConfig(const char *filepath);
99 virtual ~CUwbNxpConfig();
100 CUwbNxpConfig& operator=(CUwbNxpConfig&& config);
101
isValid() const102 bool isValid() const { return mValidFile; }
isCountrySpecific() const103 bool isCountrySpecific() const { return mCountrySpecific; }
reset()104 void reset() {
105 m_map.clear();
106 mValidFile = false;
107 }
108
109 const uwbParam* find(const char* p_name) const;
110 void setCountry(const string& strCountry);
111
112 void dump() const;
113
get_data() const114 const unordered_map<string, uwbParam>& get_data() const {
115 return m_map;
116 }
117 private:
118 bool readConfig();
119
120 unordered_map<string, uwbParam> m_map;
121 bool mValidFile;
122 string mFilePath;
123 string mCurrentFile;
124 bool mCountrySpecific;
125 };
126
127 /*******************************************************************************
128 **
129 ** Function: isPrintable()
130 **
131 ** Description: determine if 'c' is printable
132 **
133 ** Returns: 1, if printable, otherwise 0
134 **
135 *******************************************************************************/
isPrintable(char c)136 static inline bool isPrintable(char c)
137 {
138 return (c >= 'A' && c <= 'Z') ||
139 (c >= 'a' && c <= 'z') ||
140 (c >= '0' && c <= '9') ||
141 c == '/' || c == '_' || c == '-' || c == '.' || c == ',';
142 }
143
144 /*******************************************************************************
145 **
146 ** Function: isDigit()
147 **
148 ** Description: determine if 'c' is numeral digit
149 **
150 ** Returns: true, if numerical digit
151 **
152 *******************************************************************************/
isDigit(char c,int base)153 static inline bool isDigit(char c, int base)
154 {
155 if (base == 10) {
156 return isdigit(c);
157 } else if (base == 16) {
158 return isxdigit(c);
159 } else {
160 return false;
161 }
162 }
163
isArrayDelimeter(char c)164 static inline bool isArrayDelimeter(char c)
165 {
166 return (isspace(c) || c== ',' || c == ':' || c == '-' || c == '}');
167 }
168
169 /*******************************************************************************
170 **
171 ** Function: getDigitValue()
172 **
173 ** Description: return numerical value of a decimal or hex char
174 **
175 ** Returns: numerical value if decimal or hex char, otherwise 0
176 **
177 *******************************************************************************/
getDigitValue(char c,int base)178 inline int getDigitValue(char c, int base)
179 {
180 if ('0' <= c && c <= '9')
181 return c - '0';
182 if (base == 16)
183 {
184 if ('A' <= c && c <= 'F')
185 return c - 'A' + 10;
186 else if ('a' <= c && c <= 'f')
187 return c - 'a' + 10;
188 }
189 return 0;
190 }
191
192 /*******************************************************************************
193 **
194 ** Function: CUwbNxpConfig::readConfig()
195 **
196 ** Description: read Config settings and parse them into a linked list
197 ** move the element from linked list to a array at the end
198 **
199 ** Returns: 1, if there are any config data, 0 otherwise
200 **
201 *******************************************************************************/
readConfig()202 bool CUwbNxpConfig::readConfig()
203 {
204 enum {
205 BEGIN_LINE = 1,
206 TOKEN,
207 STR_VALUE,
208 NUM_VALUE,
209 ARR_SPACE,
210 ARR_STR,
211 ARR_STR_SPACE,
212 ARR_NUM,
213 BEGIN_HEX,
214 BEGIN_QUOTE,
215 END_LINE
216 };
217
218 FILE* fd;
219 string token;
220 string strValue;
221 unsigned long numValue = 0;
222 vector<uint8_t> arrValue;
223 vector<string> arrStr;
224 int base = 0;
225 int c;
226 const char *name = mCurrentFile.c_str();
227 unsigned long state = BEGIN_LINE;
228
229 mValidFile = false;
230 m_map.clear();
231
232 /* open config file, read it into a buffer */
233 if ((fd = fopen(name, "r")) == NULL)
234 {
235 ALOGD("%s Cannot open config file %s\n", __func__, name);
236 return false;
237 }
238 ALOGV("%s Opened config %s\n", __func__, name);
239
240 for (;;) {
241 c = fgetc(fd);
242
243 switch (state) {
244 case BEGIN_LINE:
245 if (isPrintable(c)) {
246 token.clear();
247 numValue = 0;
248 strValue.clear();
249 arrValue.clear();
250 arrStr.clear();
251 state = TOKEN;
252 token.push_back(c);
253 } else {
254 state = END_LINE;
255 }
256 break;
257 case TOKEN:
258 if (c == '=') {
259 state = BEGIN_QUOTE;
260 } else if (isPrintable(c)) {
261 token.push_back(c);
262 } else {
263 state = END_LINE;
264 }
265 break;
266 case BEGIN_QUOTE:
267 if (c == '"') {
268 state = STR_VALUE;
269 base = 0;
270 } else if (c == '0') {
271 state = BEGIN_HEX;
272 } else if (isDigit(c, 10)) {
273 state = NUM_VALUE;
274 base = 10;
275 numValue = getDigitValue(c, base);
276 } else if (c == '{') {
277 state = ARR_SPACE;
278 base = 16;
279 } else {
280 state = END_LINE;
281 }
282 break;
283 case BEGIN_HEX:
284 if (c == 'x' || c == 'X') {
285 state = NUM_VALUE;
286 base = 16;
287 numValue = 0;
288 } else if (isDigit(c, 10)) {
289 state = NUM_VALUE;
290 base = 10;
291 numValue = getDigitValue(c, base);
292 } else {
293 m_map.try_emplace(token, move(uwbParam(numValue)));
294 state = END_LINE;
295 }
296 break;
297 case NUM_VALUE:
298 if (isDigit(c, base)) {
299 numValue *= base;
300 numValue += getDigitValue(c, base);
301 } else {m_map.try_emplace(token, move(uwbParam(numValue)));
302 state = END_LINE;
303 }
304 break;
305 case ARR_SPACE:
306 if (isDigit(c, 16)) {
307 numValue = getDigitValue(c, base);
308 state = ARR_NUM;
309 } else if (c == '}') {
310 m_map.try_emplace(token, move(uwbParam(move(arrValue))));
311 state = END_LINE;
312 } else if (c == '"') {
313 state = ARR_STR;
314 } else if (c == EOF) {
315 state = END_LINE;
316 }
317 break;
318 case ARR_STR:
319 if (c == '"') {
320 arrStr.emplace_back(move(strValue));
321 strValue.clear();
322 state = ARR_STR_SPACE;
323 } else {
324 strValue.push_back(c);
325 }
326 break;
327 case ARR_STR_SPACE:
328 if (c == '}') {
329 m_map.try_emplace(token, move(uwbParam(move(arrStr))));
330 state = END_LINE;
331 } else if (c == '"') {
332 state = ARR_STR;
333 }
334 break;
335 case ARR_NUM:
336 if (isDigit(c, 16)) {
337 numValue *= 16;
338 numValue += getDigitValue(c, base);
339 } else if (isArrayDelimeter(c)) {
340 arrValue.push_back(numValue & 0xff);
341 state = ARR_SPACE;
342 } else {
343 state = END_LINE;
344 }
345 if (c == '}') {
346 m_map.try_emplace(token, move(uwbParam(move(arrValue))));
347 state = END_LINE;
348 }
349 break;
350 case STR_VALUE:
351 if (c == '"') {
352 state = END_LINE;
353 m_map.try_emplace(token, move(uwbParam(strValue)));
354 } else {
355 strValue.push_back(c);
356 }
357 break;
358 case END_LINE:
359 // do nothing
360 default:
361 break;
362 }
363 if (c == EOF)
364 break;
365 else if (state == END_LINE && (c == '\n' || c == '\r'))
366 state = BEGIN_LINE;
367 else if (c == '#')
368 state = END_LINE;
369 }
370
371 fclose(fd);
372
373 if (m_map.size() > 0) {
374 mValidFile = true;
375 }
376
377 return mValidFile;
378 }
379
380 /*******************************************************************************
381 **
382 ** Function: CUwbNxpConfig::CUwbNxpConfig()
383 **
384 ** Description: class constructor
385 **
386 ** Returns: none
387 **
388 *******************************************************************************/
CUwbNxpConfig()389 CUwbNxpConfig::CUwbNxpConfig() :
390 mValidFile(false),
391 mCountrySpecific(false)
392 {
393 }
394
395 /*******************************************************************************
396 **
397 ** Function: CUwbNxpConfig::~CUwbNxpConfig()
398 **
399 ** Description: class destructor
400 **
401 ** Returns: none
402 **
403 *******************************************************************************/
~CUwbNxpConfig()404 CUwbNxpConfig::~CUwbNxpConfig()
405 {
406 }
407
CUwbNxpConfig(const char * filepath)408 CUwbNxpConfig::CUwbNxpConfig(const char *filepath) :
409 mValidFile(false),
410 mFilePath(filepath),
411 mCountrySpecific(false)
412 {
413 auto pos = mFilePath.find(sku_specifier);
414 if (pos != string::npos) {
415 char prop_str[PROPERTY_VALUE_MAX];
416 property_get(prop_name_calsku, prop_str,prop_default_calsku);
417 mFilePath.replace(pos, strlen(sku_specifier), prop_str);
418 }
419
420 // country specifier will be evaluated later in setCountry() path
421 pos = mFilePath.find(country_code_specifier);
422 if (pos == string::npos) {
423 mCurrentFile = mFilePath;
424 readConfig();
425 } else {
426 mCountrySpecific = true;
427 }
428 }
429
CUwbNxpConfig(CUwbNxpConfig && config)430 CUwbNxpConfig::CUwbNxpConfig(CUwbNxpConfig&& config)
431 {
432 m_map = move(config.m_map);
433 mValidFile = config.mValidFile;
434 mFilePath = move(config.mFilePath);
435 mCurrentFile = move(config.mCurrentFile);
436 mCountrySpecific = config.mCountrySpecific;
437
438 config.mValidFile = false;
439 }
440
operator =(CUwbNxpConfig && config)441 CUwbNxpConfig& CUwbNxpConfig::operator=(CUwbNxpConfig&& config)
442 {
443 m_map = move(config.m_map);
444 mValidFile = config.mValidFile;
445 mFilePath = move(config.mFilePath);
446 mCurrentFile = move(config.mCurrentFile);
447 mCountrySpecific = config.mCountrySpecific;
448
449 config.mValidFile = false;
450 return *this;
451 }
452
setCountry(const string & strCountry)453 void CUwbNxpConfig::setCountry(const string& strCountry)
454 {
455 if (!isCountrySpecific())
456 return;
457
458 mCurrentFile = mFilePath;
459 auto pos = mCurrentFile.find(country_code_specifier);
460 if (pos == string::npos) {
461 return;
462 }
463
464 mCurrentFile.replace(pos, strlen(country_code_specifier), strCountry);
465 readConfig();
466 }
467
468 /*******************************************************************************
469 **
470 ** Function: CUwbNxpConfig::find()
471 **
472 ** Description: search if a setting exist in the setting array
473 **
474 ** Returns: pointer to the setting object
475 **
476 *******************************************************************************/
find(const char * p_name) const477 const uwbParam* CUwbNxpConfig::find(const char* p_name) const
478 {
479 const auto it = m_map.find(p_name);
480
481 if (it == m_map.cend()) {
482 return NULL;
483 }
484 return &it->second;
485 }
486
487 /*******************************************************************************
488 **
489 ** Function: CUwbNxpConfig::dump()
490 **
491 ** Description: prints all elements in the list
492 **
493 ** Returns: none
494 **
495 *******************************************************************************/
dump() const496 void CUwbNxpConfig::dump() const
497 {
498 ALOGV("Dump configuration file %s : %s, %zu entries", mCurrentFile.c_str(),
499 mValidFile ? "valid" : "invalid", m_map.size());
500
501 for (auto &it : m_map) {
502 auto &key = it.first;
503 auto ¶m = it.second;
504 param.dump(key);
505 }
506 }
507
508 /*******************************************************************************/
uwbParam()509 uwbParam::uwbParam() :
510 m_numValue(0),
511 m_type(type::NUMBER)
512 {
513 }
514
~uwbParam()515 uwbParam::~uwbParam()
516 {
517 }
518
uwbParam(const uwbParam & param)519 uwbParam::uwbParam(const uwbParam ¶m) :
520 m_numValue(param.m_numValue),
521 m_str_value(param.m_str_value),
522 m_arrValue(param.m_arrValue),
523 m_arrStrValue(param.m_arrStrValue),
524 m_type(param.m_type)
525 {
526 }
527
uwbParam(uwbParam && param)528 uwbParam::uwbParam(uwbParam &¶m) :
529 m_numValue(param.m_numValue),
530 m_str_value(move(param.m_str_value)),
531 m_arrValue(move(param.m_arrValue)),
532 m_arrStrValue(move(param.m_arrStrValue)),
533 m_type(param.m_type)
534 {
535 }
536
uwbParam(const string & value)537 uwbParam::uwbParam(const string& value) :
538 m_numValue(0),
539 m_str_value(value),
540 m_type(type::STRING)
541 {
542 }
543
uwbParam(unsigned long value)544 uwbParam::uwbParam(unsigned long value) :
545 m_numValue(value),
546 m_type(type::NUMBER)
547 {
548 }
549
uwbParam(vector<uint8_t> && value)550 uwbParam::uwbParam(vector<uint8_t> &&value) :
551 m_arrValue(move(value)),
552 m_type(type::BYTEARRAY)
553 {
554 }
555
uwbParam(vector<string> && value)556 uwbParam::uwbParam(vector<string> &&value) :
557 m_arrStrValue(move(value)),
558 m_type(type::STRINGARRAY)
559 {
560 }
561
562
dump(const string & tag) const563 void uwbParam::dump(const string &tag) const
564 {
565 if (m_type == type::NUMBER) {
566 ALOGV(" - %s = 0x%lx", tag.c_str(), m_numValue);
567 } else if (m_type == type::STRING) {
568 ALOGV(" - %s = %s", tag.c_str(), m_str_value.c_str());
569 } else if (m_type == type::BYTEARRAY) {
570 stringstream ss_hex;
571 ss_hex.fill('0');
572 for (auto b : m_arrValue) {
573 ss_hex << setw(2) << hex << (int)b << " ";
574 }
575 ALOGV(" - %s = { %s}", tag.c_str(), ss_hex.str().c_str());
576 } else if (m_type == type::STRINGARRAY) {
577 stringstream ss;
578 for (auto s : m_arrStrValue) {
579 ss << "\"" << s << "\", ";
580 }
581 ALOGV(" - %s = { %s}", tag.c_str(), ss.str().c_str());
582 }
583 }
584 /*******************************************************************************/
585 class RegionCodeMap {
586 public:
loadMapping(const char * filepath)587 void loadMapping(const char *filepath) {
588 CUwbNxpConfig config(filepath);
589 if (!config.isValid()) {
590 ALOGW("Region mapping was not provided.");
591 return;
592 }
593
594 ALOGI("Region mapping was provided by %s", filepath);
595 auto &all_params = config.get_data();
596 for (auto &it : all_params) {
597 const auto ®ion_str = it.first;
598 const uwbParam *param = &it.second;
599
600 // split space-separated strings into set
601 stringstream ss(param->str_value());
602 string cc;
603 unordered_set<string> cc_set;
604 while (ss >> cc) {
605 if (cc.length() == 2 && isupper(cc[0]) && isupper(cc[1])) {
606 cc_set.emplace(move(cc));
607 }
608 }
609 auto result = m_map.try_emplace(region_str, move(cc_set));
610 if (!result.second) {
611 // region conlifct : merge
612 result.first->second.merge(move(cc_set));
613 }
614 }
615 m_config = move(config);
616 }
xlateCountryCode(const char country_code[2])617 string xlateCountryCode(const char country_code[2]) {
618 string code{country_code[0], country_code[1]};
619 if (m_config.isValid()) {
620 for (auto &it : m_map) {
621 const auto ®ion_str = it.first;
622 const auto &cc_set = it.second;
623 if (cc_set.find(code) != cc_set.end()) {
624 ALOGV("map country code %c%c --> %s",
625 country_code[0], country_code[1], region_str.c_str());
626 return region_str;
627 }
628 }
629 }
630 return code;
631 }
reset()632 void reset() {
633 m_config.reset();
634 m_map.clear();
635 }
dump()636 void dump() {
637 ALOGV("Region mapping dump:");
638 for (auto &entry : m_map) {
639 const auto ®ion_str = entry.first;
640 const auto &cc_set = entry.second;
641 stringstream ss;
642 for (const auto s : cc_set) {
643 ss << "\"" << s << "\", ";
644 }
645 ALOGV("- %s = { %s}", region_str.c_str(), ss.str().c_str());
646 }
647 }
648 private:
649 CUwbNxpConfig m_config;
650 unordered_map<string, unordered_set<string>> m_map;
651 };
652
653 /*******************************************************************************/
654 class CascadeConfig {
655 public:
656 CascadeConfig();
657
658 void init(const char *main_config);
659 void deinit();
660 bool setCountryCode(const char country_code[2]);
661
662 const uwbParam* find(const char *name) const;
663 bool getValue(const char* name, char* pValue, size_t len) const;
664 bool getValue(const char* name, unsigned long& rValue) const;
665 bool getValue(const char* name, uint8_t* pValue, long len, long* readlen) const;
666 private:
667 // default_nxp_config_path
668 CUwbNxpConfig mMainConfig;
669
670 // uci config
671 CUwbNxpConfig mUciConfig;
672
673 // EXTRA_CONF_PATH[N]
674 vector<CUwbNxpConfig> mExtraConfig;
675
676 // [COUNTRY_CODE_CAP_FILE_LOCATION]/country_code_config_name
677 CUwbNxpConfig mCapsConfig;
678
679 // Region Code mapping
680 RegionCodeMap mRegionMap;
681
682 // Current region code
683 string mCurRegionCode;
684
dump()685 void dump() {
686 mMainConfig.dump();
687 mUciConfig.dump();
688
689 for (const auto &config : mExtraConfig)
690 config.dump();
691
692 mCapsConfig.dump();
693 mRegionMap.dump();
694 }
695 };
696
CascadeConfig()697 CascadeConfig::CascadeConfig()
698 {
699 }
700
init(const char * main_config)701 void CascadeConfig::init(const char *main_config)
702 {
703 ALOGV("CascadeConfig initialize with %s", main_config);
704
705 // Main config file
706 CUwbNxpConfig config(main_config);
707 if (!config.isValid()) {
708 ALOGW("Failed to load main config file");
709 return;
710 }
711 mMainConfig = move(config);
712
713 {
714 // UCI config file
715 std::string uciConfigFilePath = default_uci_config_path;
716 uciConfigFilePath += nxp_uci_config_file;
717
718 CUwbNxpConfig config(uciConfigFilePath.c_str());
719 if (!config.isValid()) {
720 ALOGW("Failed to load uci config file:%s",
721 uciConfigFilePath.c_str());
722 } else {
723 mUciConfig = move(config);
724 }
725 }
726
727 // Read EXTRA_CONF_PATH[N]
728 for (int i = 1; i <= 10; i++) {
729 char key[32];
730 snprintf(key, sizeof(key), "EXTRA_CONF_PATH_%d", i);
731 const uwbParam *param = mMainConfig.find(key);
732 if (!param)
733 continue;
734 CUwbNxpConfig config(param->str_value());
735 ALOGD("Extra calibration file %s : %svalid", param->str_value(), config.isValid() ? "" : "in");
736 if (config.isValid() || config.isCountrySpecific()) {
737 mExtraConfig.emplace_back(move(config));
738 }
739 }
740
741 // Pick one libuwb-countrycode.conf with the highest VERSION number
742 // from multiple directories specified by COUNTRY_CODE_CAP_FILE_LOCATION
743 unsigned long arrLen = 0;
744 if (NxpConfig_GetStrArrayLen(NAME_COUNTRY_CODE_CAP_FILE_LOCATION, &arrLen) && arrLen > 0) {
745 const long loc_max_len = 260;
746 auto loc = make_unique<char[]>(loc_max_len);
747 int version, max_version = -1;
748 string strPickedPath;
749 bool foundCapFile = false;
750 CUwbNxpConfig pickedConfig;
751
752 for (int i = 0; i < arrLen; i++) {
753 if (!NxpConfig_GetStrArrayVal(NAME_COUNTRY_CODE_CAP_FILE_LOCATION, i, loc.get(), loc_max_len)) {
754 continue;
755 }
756 string strPath(loc.get());
757 strPath += country_code_config_name;
758
759 ALOGV("Try to load %s", strPath.c_str());
760
761 CUwbNxpConfig config(strPath.c_str());
762
763 const uwbParam *param = config.find(NAME_NXP_COUNTRY_CODE_VERSION);
764 version = param ? atoi(param->str_value()) : -2;
765 if (version > max_version) {
766 foundCapFile = true;
767 pickedConfig = move(config);
768 strPickedPath = move(strPath);
769 max_version = version;
770 }
771 }
772 if (foundCapFile) {
773 mCapsConfig = move(pickedConfig);
774 ALOGI("CountryCodeCaps file %s loaded with VERSION=%d", strPickedPath.c_str(), max_version);
775 } else {
776 ALOGI("No CountryCodeCaps specified");
777 }
778 } else {
779 ALOGI(NAME_COUNTRY_CODE_CAP_FILE_LOCATION " was not specified, skip loading CountryCodeCaps");
780 }
781
782 // Load region mapping
783 const uwbParam *param = find(NAME_REGION_MAP_PATH);
784 if (param) {
785 mRegionMap.loadMapping(param->str_value());
786 }
787
788 ALOGD("CascadeConfig initialized");
789
790 dump();
791 }
792
deinit()793 void CascadeConfig::deinit()
794 {
795 mMainConfig.reset();
796 mExtraConfig.clear();
797 mCapsConfig.reset();
798 mRegionMap.reset();
799 mUciConfig.reset();
800 mCurRegionCode.clear();
801 }
802
setCountryCode(const char country_code[2])803 bool CascadeConfig::setCountryCode(const char country_code[2])
804 {
805 string strRegion = mRegionMap.xlateCountryCode(country_code);
806
807 if (strRegion == mCurRegionCode) {
808 ALOGI("Same region code(%c%c --> %s), per-country configuration not updated.",
809 country_code[0], country_code[1], strRegion.c_str());
810 return false;
811 }
812
813 ALOGI("Apply country code %c%c --> %s\n", country_code[0], country_code[1], strRegion.c_str());
814 mCurRegionCode = strRegion;
815 for (auto &x : mExtraConfig) {
816 if (x.isCountrySpecific()) {
817 x.setCountry(mCurRegionCode);
818 x.dump();
819 }
820 }
821 return true;
822 }
823
find(const char * name) const824 const uwbParam* CascadeConfig::find(const char *name) const
825 {
826 const uwbParam* param = NULL;
827
828 param = mCapsConfig.find(name);
829 if (param)
830 return param;
831
832 for (auto it = mExtraConfig.rbegin(); it != mExtraConfig.rend(); it++) {
833 param = it->find(name);
834 if (param)
835 break;
836 }
837 if (!param) {
838 param = mMainConfig.find(name);
839 }
840 if (!param) {
841 param = mUciConfig.find(name);
842 }
843 return param;
844 }
845
846 // TODO: move these getValue() helpers out of the class
getValue(const char * name,char * pValue,size_t len) const847 bool CascadeConfig::getValue(const char* name, char* pValue, size_t len) const
848 {
849 const uwbParam *param = find(name);
850 if (!param)
851 return false;
852 if (param->getType() != uwbParam::type::STRING)
853 return false;
854 if (len < (param->str_len() + 1))
855 return false;
856
857 strncpy(pValue, param->str_value(), len);
858 return true;
859 }
860
getValue(const char * name,uint8_t * pValue,long len,long * readlen) const861 bool CascadeConfig::getValue(const char* name, uint8_t* pValue, long len, long* readlen) const
862 {
863 const uwbParam *param = find(name);
864 if (!param)
865 return false;
866 if (param->getType() != uwbParam::type::BYTEARRAY)
867 return false;
868 if (len < param->arr_len())
869 return false;
870 memcpy(pValue, param->arr_value(), param->arr_len());
871 if (readlen)
872 *readlen = param->arr_len();
873 return true;
874 }
875
getValue(const char * name,unsigned long & rValue) const876 bool CascadeConfig::getValue(const char* name, unsigned long& rValue) const
877 {
878 const uwbParam *param = find(name);
879 if (!param)
880 return false;
881 if (param->getType() != uwbParam::type::NUMBER)
882 return false;
883
884 rValue = param->numValue();
885 return true;
886 }
887
888 /*******************************************************************************/
889
890 static CascadeConfig gConfig;
891
NxpConfig_Init(void)892 void NxpConfig_Init(void)
893 {
894 gConfig.init(default_nxp_config_path);
895 }
896
NxpConfig_Deinit(void)897 void NxpConfig_Deinit(void)
898 {
899 gConfig.deinit();
900 }
901
902 // return true if new per-country configuration file was load.
903 // false if it can stay at the current configuration.
NxpConfig_SetCountryCode(const char country_code[2])904 bool NxpConfig_SetCountryCode(const char country_code[2])
905 {
906 return gConfig.setCountryCode(country_code);
907 }
908
909 /*******************************************************************************
910 **
911 ** Function: NxpConfig_GetStr
912 **
913 ** Description: API function for getting a string value of a setting
914 **
915 ** Returns: True if found, otherwise False.
916 **
917 *******************************************************************************/
NxpConfig_GetStr(const char * name,char * pValue,unsigned long len)918 int NxpConfig_GetStr(const char* name, char* pValue, unsigned long len)
919 {
920 return gConfig.getValue(name, pValue, len);
921 }
922
923 /*******************************************************************************
924 **
925 ** Function: NxpConfig_GetByteArray()
926 **
927 ** Description: Read byte array value from the config file.
928 **
929 ** Parameters:
930 ** name - name of the config param to read.
931 ** pValue - pointer to input buffer.
932 ** bufflen - input buffer length.
933 ** len - out parameter to return the number of bytes read from config file,
934 ** return -1 in case bufflen is not enough.
935 **
936 ** Returns: TRUE[1] if config param name is found in the config file, else FALSE[0]
937 **
938 *******************************************************************************/
NxpConfig_GetByteArray(const char * name,uint8_t * pValue,long bufflen,long * len)939 int NxpConfig_GetByteArray(const char* name, uint8_t* pValue, long bufflen, long *len)
940 {
941 return gConfig.getValue(name, pValue, bufflen,len);
942 }
943
944 /*******************************************************************************
945 **
946 ** Function: NxpConfig_GetNum
947 **
948 ** Description: API function for getting a numerical value of a setting
949 **
950 ** Returns: true, if successful
951 **
952 *******************************************************************************/
NxpConfig_GetNum(const char * name,void * pValue,unsigned long len)953 int NxpConfig_GetNum(const char* name, void* pValue, unsigned long len)
954 {
955 if (pValue == NULL){
956 return false;
957 }
958 const uwbParam* pParam = gConfig.find(name);
959
960 if (pParam == NULL)
961 return false;
962 if (pParam->getType() != uwbParam::type::NUMBER)
963 return false;
964
965 unsigned long v = pParam->numValue();
966 switch (len)
967 {
968 case sizeof(unsigned long):
969 *(static_cast<unsigned long*>(pValue)) = (unsigned long)v;
970 break;
971 case sizeof(unsigned short):
972 *(static_cast<unsigned short*>(pValue)) = (unsigned short)v;
973 break;
974 case sizeof(unsigned char):
975 *(static_cast<unsigned char*> (pValue)) = (unsigned char)v;
976 break;
977 default:
978 return false;
979 }
980 return true;
981 }
982
983 // Get the length of a 'string-array' type parameter
NxpConfig_GetStrArrayLen(const char * name,unsigned long * pLen)984 int NxpConfig_GetStrArrayLen(const char* name, unsigned long* pLen)
985 {
986 const uwbParam* param = gConfig.find(name);
987 if (!param || param->getType() != uwbParam::type::STRINGARRAY)
988 return false;
989
990 *pLen = param->str_arr_len();
991 return true;
992 }
993
994 // Get a string value from 'string-array' type parameters, index zero-based
NxpConfig_GetStrArrayVal(const char * name,int index,char * pValue,unsigned long len)995 int NxpConfig_GetStrArrayVal(const char* name, int index, char* pValue, unsigned long len)
996 {
997 const uwbParam* param = gConfig.find(name);
998 if (!param || param->getType() != uwbParam::type::STRINGARRAY)
999 return false;
1000 if (index < 0 || index >= param->str_arr_len())
1001 return false;
1002
1003 if (len < param->str_arr_elem_len(index) + 1)
1004 return false;
1005 strncpy(pValue, param->str_arr_elem(index), len);
1006 return true;
1007 }
1008