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 &param = 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 &param) :
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 &&param) :
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 &region_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 &region_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 &region_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