1/* Copyright (c) 2011-2014,2016 The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 *     * Redistributions of source code must retain the above copyright
7 *       notice, this list of conditions and the following disclaimer.
8 *     * Redistributions in binary form must reproduce the above
9 *       copyright notice, this list of conditions and the following
10 *       disclaimer in the documentation and/or other materials provided
11 *       with the distribution.
12 *     * Neither the name of The Linux Foundation, nor the names of its
13 *       contributors may be used to endorse or promote products derived
14 *       from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29#define LOG_NDDEBUG 0
30#define LOG_TAG "LocSvc_LocApiBase"
31
32#include <dlfcn.h>
33#include <LocApiBase.h>
34#include <LocAdapterBase.h>
35#include <platform_lib_log_util.h>
36#include <LocDualContext.h>
37
38namespace loc_core {
39
40#define TO_ALL_LOCADAPTERS(call) TO_ALL_ADAPTERS(mLocAdapters, (call))
41#define TO_1ST_HANDLING_LOCADAPTERS(call) TO_1ST_HANDLING_ADAPTER(mLocAdapters, (call))
42
43int hexcode(char *hexstring, int string_size,
44            const char *data, int data_size)
45{
46   int i;
47   for (i = 0; i < data_size; i++)
48   {
49      char ch = data[i];
50      if (i*2 + 3 <= string_size)
51      {
52         snprintf(&hexstring[i*2], 3, "%02X", ch);
53      }
54      else {
55         break;
56      }
57   }
58   return i;
59}
60
61int decodeAddress(char *addr_string, int string_size,
62                   const char *data, int data_size)
63{
64    const char addr_prefix = 0x91;
65    int i, idxOutput = 0;
66
67    if (!data || !addr_string) { return 0; }
68
69    if (data[0] != addr_prefix)
70    {
71        LOC_LOGW("decodeAddress: address prefix is not 0x%x but 0x%x", addr_prefix, data[0]);
72        addr_string[0] = '\0';
73        return 0; // prefix not correct
74    }
75
76    for (i = 1; i < data_size; i++)
77    {
78        unsigned char ch = data[i], low = ch & 0x0F, hi = ch >> 4;
79        if (low <= 9 && idxOutput < string_size - 1) { addr_string[idxOutput++] = low + '0'; }
80        if (hi <= 9 && idxOutput < string_size - 1) { addr_string[idxOutput++] = hi + '0'; }
81    }
82
83    addr_string[idxOutput] = '\0'; // Terminates the string
84
85    return idxOutput;
86}
87
88struct LocSsrMsg : public LocMsg {
89    LocApiBase* mLocApi;
90    inline LocSsrMsg(LocApiBase* locApi) :
91        LocMsg(), mLocApi(locApi)
92    {
93        locallog();
94    }
95    inline virtual void proc() const {
96        mLocApi->close();
97        mLocApi->open(mLocApi->getEvtMask());
98    }
99    inline void locallog() {
100        LOC_LOGV("LocSsrMsg");
101    }
102    inline virtual void log() {
103        locallog();
104    }
105};
106
107struct LocOpenMsg : public LocMsg {
108    LocApiBase* mLocApi;
109    LOC_API_ADAPTER_EVENT_MASK_T mMask;
110    inline LocOpenMsg(LocApiBase* locApi,
111                      LOC_API_ADAPTER_EVENT_MASK_T mask) :
112        LocMsg(), mLocApi(locApi), mMask(mask)
113    {
114        locallog();
115    }
116    inline virtual void proc() const {
117        mLocApi->open(mMask);
118    }
119    inline void locallog() {
120        LOC_LOGV("%s:%d]: LocOpen Mask: %x\n",
121                 __func__, __LINE__, mMask);
122    }
123    inline virtual void log() {
124        locallog();
125    }
126};
127
128LocApiBase::LocApiBase(const MsgTask* msgTask,
129                       LOC_API_ADAPTER_EVENT_MASK_T excludedMask,
130                       ContextBase* context) :
131    mExcludedMask(excludedMask), mMsgTask(msgTask),
132    mMask(0), mSupportedMsg(0), mContext(context)
133{
134    memset(mLocAdapters, 0, sizeof(mLocAdapters));
135    memset(mFeaturesSupported, 0, sizeof(mFeaturesSupported));
136}
137
138LOC_API_ADAPTER_EVENT_MASK_T LocApiBase::getEvtMask()
139{
140    LOC_API_ADAPTER_EVENT_MASK_T mask = 0;
141
142    TO_ALL_LOCADAPTERS(mask |= mLocAdapters[i]->getEvtMask());
143
144    return mask & ~mExcludedMask;
145}
146
147bool LocApiBase::isInSession()
148{
149    bool inSession = false;
150
151    for (int i = 0;
152         !inSession && i < MAX_ADAPTERS && NULL != mLocAdapters[i];
153         i++) {
154        inSession = mLocAdapters[i]->isInSession();
155    }
156
157    return inSession;
158}
159
160void LocApiBase::addAdapter(LocAdapterBase* adapter)
161{
162    for (int i = 0; i < MAX_ADAPTERS && mLocAdapters[i] != adapter; i++) {
163        if (mLocAdapters[i] == NULL) {
164            mLocAdapters[i] = adapter;
165            mMsgTask->sendMsg(new LocOpenMsg(this,
166                                             (adapter->getEvtMask())));
167            break;
168        }
169    }
170}
171
172void LocApiBase::removeAdapter(LocAdapterBase* adapter)
173{
174    for (int i = 0;
175         i < MAX_ADAPTERS && NULL != mLocAdapters[i];
176         i++) {
177        if (mLocAdapters[i] == adapter) {
178            mLocAdapters[i] = NULL;
179
180            // shift the rest of the adapters up so that the pointers
181            // in the array do not have holes.  This should be more
182            // performant, because the array maintenance is much much
183            // less frequent than event handlings, which need to linear
184            // search all the adapters
185            int j = i;
186            while (++i < MAX_ADAPTERS && mLocAdapters[i] != NULL);
187
188            // i would be MAX_ADAPTERS or point to a NULL
189            i--;
190            // i now should point to a none NULL adapter within valid
191            // range although i could be equal to j, but it won't hurt.
192            // No need to check it, as it gains nothing.
193            mLocAdapters[j] = mLocAdapters[i];
194            // this makes sure that we exit the for loop
195            mLocAdapters[i] = NULL;
196
197            // if we have an empty list of adapters
198            if (0 == i) {
199                close();
200            } else {
201                // else we need to remove the bit
202                mMsgTask->sendMsg(new LocOpenMsg(this, getEvtMask()));
203            }
204        }
205    }
206}
207
208void LocApiBase::updateEvtMask()
209{
210    mMsgTask->sendMsg(new LocOpenMsg(this, getEvtMask()));
211}
212
213void LocApiBase::handleEngineUpEvent()
214{
215    // This will take care of renegotiating the loc handle
216    mMsgTask->sendMsg(new LocSsrMsg(this));
217
218    LocDualContext::injectFeatureConfig(mContext);
219
220    // loop through adapters, and deliver to all adapters.
221    TO_ALL_LOCADAPTERS(mLocAdapters[i]->handleEngineUpEvent());
222}
223
224void LocApiBase::handleEngineDownEvent()
225{
226    // loop through adapters, and deliver to all adapters.
227    TO_ALL_LOCADAPTERS(mLocAdapters[i]->handleEngineDownEvent());
228}
229
230void LocApiBase::reportPosition(UlpLocation &location,
231                                GpsLocationExtended &locationExtended,
232                                void* locationExt,
233                                enum loc_sess_status status,
234                                LocPosTechMask loc_technology_mask)
235{
236    // print the location info before delivering
237    LOC_LOGV("flags: %d\n  source: %d\n  latitude: %f\n  longitude: %f\n  "
238             "altitude: %f\n  speed: %f\n  bearing: %f\n  accuracy: %f\n  "
239             "timestamp: %lld\n  rawDataSize: %d\n  rawData: %p\n  "
240             "Session status: %d\n Technology mask: %u\n "
241             "SV used in fix (gps/glo/bds/gal) : (%x/%x/%x/%x)",
242             location.gpsLocation.flags, location.position_source,
243             location.gpsLocation.latitude, location.gpsLocation.longitude,
244             location.gpsLocation.altitude, location.gpsLocation.speed,
245             location.gpsLocation.bearing, location.gpsLocation.accuracy,
246             location.gpsLocation.timestamp, location.rawDataSize,
247             location.rawData, status, loc_technology_mask,
248             locationExtended.gnss_sv_used_ids.gps_sv_used_ids_mask,
249             locationExtended.gnss_sv_used_ids.glo_sv_used_ids_mask,
250             locationExtended.gnss_sv_used_ids.bds_sv_used_ids_mask,
251             locationExtended.gnss_sv_used_ids.gal_sv_used_ids_mask);
252    // loop through adapters, and deliver to all adapters.
253    TO_ALL_LOCADAPTERS(
254        mLocAdapters[i]->reportPosition(location,
255                                        locationExtended,
256                                        locationExt,
257                                        status,
258                                        loc_technology_mask)
259    );
260}
261
262void LocApiBase::reportWwanZppFix(GpsLocation &zppLoc)
263{
264    // loop through adapters, and deliver to the first handling adapter.
265    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportWwanZppFix(zppLoc));
266}
267
268void LocApiBase::reportSv(GnssSvStatus &svStatus,
269                  GpsLocationExtended &locationExtended,
270                  void* svExt)
271{
272    const char* constellationString[] = { "Unknown", "GPS", "SBAS", "GLONASS",
273        "QZSS", "BEIDOU", "GALILEO" };
274
275    // print the SV info before delivering
276    LOC_LOGV("num sv: %d\n"
277        "      sv: constellation svid         cN0"
278        "    elevation    azimuth    flags",
279        svStatus.num_svs);
280    for (int i = 0; i < svStatus.num_svs && i < GNSS_MAX_SVS; i++) {
281        if (svStatus.gnss_sv_list[i].constellation >
282            sizeof(constellationString) / sizeof(constellationString[0]) - 1) {
283            svStatus.gnss_sv_list[i].constellation = 0;
284        }
285        LOC_LOGV("   %03d: %*s  %02d    %f    %f    %f   0x%02X",
286            i,
287            13,
288            constellationString[svStatus.gnss_sv_list[i].constellation],
289            svStatus.gnss_sv_list[i].svid,
290            svStatus.gnss_sv_list[i].c_n0_dbhz,
291            svStatus.gnss_sv_list[i].elevation,
292            svStatus.gnss_sv_list[i].azimuth,
293            svStatus.gnss_sv_list[i].flags);
294    }
295    // loop through adapters, and deliver to all adapters.
296    TO_ALL_LOCADAPTERS(
297        mLocAdapters[i]->reportSv(svStatus,
298            locationExtended,
299            svExt)
300        );
301}
302
303void LocApiBase::reportSvMeasurement(GnssSvMeasurementSet &svMeasurementSet)
304{
305    // loop through adapters, and deliver to all adapters.
306    TO_ALL_LOCADAPTERS(
307        mLocAdapters[i]->reportSvMeasurement(svMeasurementSet)
308    );
309}
310
311void LocApiBase::reportSvPolynomial(GnssSvPolynomial &svPolynomial)
312{
313    // loop through adapters, and deliver to all adapters.
314    TO_ALL_LOCADAPTERS(
315        mLocAdapters[i]->reportSvPolynomial(svPolynomial)
316    );
317}
318
319void LocApiBase::reportStatus(GpsStatusValue status)
320{
321    // loop through adapters, and deliver to all adapters.
322    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportStatus(status));
323}
324
325void LocApiBase::reportNmea(const char* nmea, int length)
326{
327    // loop through adapters, and deliver to all adapters.
328    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportNmea(nmea, length));
329}
330
331void LocApiBase::reportXtraServer(const char* url1, const char* url2,
332                                  const char* url3, const int maxlength)
333{
334    // loop through adapters, and deliver to the first handling adapter.
335    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportXtraServer(url1, url2, url3, maxlength));
336
337}
338
339void LocApiBase::requestXtraData()
340{
341    // loop through adapters, and deliver to the first handling adapter.
342    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->requestXtraData());
343}
344
345void LocApiBase::requestTime()
346{
347    // loop through adapters, and deliver to the first handling adapter.
348    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->requestTime());
349}
350
351void LocApiBase::requestLocation()
352{
353    // loop through adapters, and deliver to the first handling adapter.
354    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->requestLocation());
355}
356
357void LocApiBase::requestATL(int connHandle, AGpsType agps_type)
358{
359    // loop through adapters, and deliver to the first handling adapter.
360    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->requestATL(connHandle, agps_type));
361}
362
363void LocApiBase::releaseATL(int connHandle)
364{
365    // loop through adapters, and deliver to the first handling adapter.
366    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->releaseATL(connHandle));
367}
368
369void LocApiBase::requestSuplES(int connHandle)
370{
371    // loop through adapters, and deliver to the first handling adapter.
372    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->requestSuplES(connHandle));
373}
374
375void LocApiBase::reportDataCallOpened()
376{
377    // loop through adapters, and deliver to the first handling adapter.
378    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportDataCallOpened());
379}
380
381void LocApiBase::reportDataCallClosed()
382{
383    // loop through adapters, and deliver to the first handling adapter.
384    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->reportDataCallClosed());
385}
386
387void LocApiBase::requestNiNotify(GpsNiNotification &notify, const void* data)
388{
389    // loop through adapters, and deliver to the first handling adapter.
390    TO_1ST_HANDLING_LOCADAPTERS(mLocAdapters[i]->requestNiNotify(notify, data));
391}
392
393void LocApiBase::saveSupportedMsgList(uint64_t supportedMsgList)
394{
395    mSupportedMsg = supportedMsgList;
396}
397
398void LocApiBase::saveSupportedFeatureList(uint8_t *featureList)
399{
400    memcpy((void *)mFeaturesSupported, (void *)featureList, sizeof(mFeaturesSupported));
401}
402
403void* LocApiBase :: getSibling()
404    DEFAULT_IMPL(NULL)
405
406LocApiProxyBase* LocApiBase :: getLocApiProxy()
407    DEFAULT_IMPL(NULL)
408
409void LocApiBase::reportGnssMeasurementData(GnssData &gnssMeasurementData)
410{
411    // loop through adapters, and deliver to all adapters.
412    TO_ALL_LOCADAPTERS(mLocAdapters[i]->reportGnssMeasurementData(gnssMeasurementData));
413}
414
415enum loc_api_adapter_err LocApiBase::
416   open(LOC_API_ADAPTER_EVENT_MASK_T mask)
417DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
418
419enum loc_api_adapter_err LocApiBase::
420    close()
421DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
422
423enum loc_api_adapter_err LocApiBase::
424    startFix(const LocPosMode& posMode)
425DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
426
427enum loc_api_adapter_err LocApiBase::
428    stopFix()
429DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
430
431enum loc_api_adapter_err LocApiBase::
432    deleteAidingData(GpsAidingData f)
433DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
434
435enum loc_api_adapter_err LocApiBase::
436    enableData(int enable)
437DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
438
439enum loc_api_adapter_err LocApiBase::
440    setAPN(char* apn, int len)
441DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
442
443enum loc_api_adapter_err LocApiBase::
444    injectPosition(double latitude, double longitude, float accuracy)
445DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
446
447enum loc_api_adapter_err LocApiBase::
448    setTime(GpsUtcTime time, int64_t timeReference, int uncertainty)
449DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
450
451enum loc_api_adapter_err LocApiBase::
452    setXtraData(char* data, int length)
453DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
454
455enum loc_api_adapter_err LocApiBase::
456    requestXtraServer()
457DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
458
459enum loc_api_adapter_err LocApiBase::
460   atlOpenStatus(int handle, int is_succ, char* apn,
461                 AGpsBearerType bear, AGpsType agpsType)
462DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
463
464enum loc_api_adapter_err LocApiBase::
465    atlCloseStatus(int handle, int is_succ)
466DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
467
468enum loc_api_adapter_err LocApiBase::
469    setPositionMode(const LocPosMode& posMode)
470DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
471
472enum loc_api_adapter_err LocApiBase::
473    setServer(const char* url, int len)
474DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
475
476enum loc_api_adapter_err LocApiBase::
477    setServer(unsigned int ip, int port,
478              LocServerType type)
479DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
480
481enum loc_api_adapter_err LocApiBase::
482    informNiResponse(GpsUserResponseType userResponse,
483                     const void* passThroughData)
484DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
485
486enum loc_api_adapter_err LocApiBase::
487    setSUPLVersion(uint32_t version)
488DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
489
490enum loc_api_adapter_err LocApiBase::
491    setNMEATypes (uint32_t typesMask)
492DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
493
494enum loc_api_adapter_err LocApiBase::
495    setLPPConfig(uint32_t profile)
496DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
497
498enum loc_api_adapter_err LocApiBase::
499    setSensorControlConfig(int sensorUsage,
500                           int sensorProvider)
501DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
502
503enum loc_api_adapter_err LocApiBase::
504    setSensorProperties(bool gyroBiasVarianceRandomWalk_valid,
505                        float gyroBiasVarianceRandomWalk,
506                        bool accelBiasVarianceRandomWalk_valid,
507                        float accelBiasVarianceRandomWalk,
508                        bool angleBiasVarianceRandomWalk_valid,
509                        float angleBiasVarianceRandomWalk,
510                        bool rateBiasVarianceRandomWalk_valid,
511                        float rateBiasVarianceRandomWalk,
512                        bool velocityBiasVarianceRandomWalk_valid,
513                        float velocityBiasVarianceRandomWalk)
514DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
515
516enum loc_api_adapter_err LocApiBase::
517    setSensorPerfControlConfig(int controlMode,
518                               int accelSamplesPerBatch,
519                               int accelBatchesPerSec,
520                               int gyroSamplesPerBatch,
521                               int gyroBatchesPerSec,
522                               int accelSamplesPerBatchHigh,
523                               int accelBatchesPerSecHigh,
524                               int gyroSamplesPerBatchHigh,
525                               int gyroBatchesPerSecHigh,
526                               int algorithmConfig)
527DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
528
529enum loc_api_adapter_err LocApiBase::
530    setAGLONASSProtocol(unsigned long aGlonassProtocol)
531DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
532
533enum loc_api_adapter_err LocApiBase::
534        setLPPeProtocol(unsigned long lppeCP, unsigned long lppeUP)
535    DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
536
537enum loc_api_adapter_err LocApiBase::
538   getWwanZppFix()
539DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
540
541enum loc_api_adapter_err LocApiBase::
542   getBestAvailableZppFix(GpsLocation& zppLoc)
543{
544   memset(&zppLoc, 0, sizeof(zppLoc));
545   DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
546}
547
548enum loc_api_adapter_err LocApiBase::
549   getBestAvailableZppFix(GpsLocation & zppLoc, LocPosTechMask & tech_mask)
550{
551   memset(&zppLoc, 0, sizeof(zppLoc));
552   memset(&tech_mask, 0, sizeof(tech_mask));
553   DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
554}
555
556int LocApiBase::
557    initDataServiceClient(bool isDueToSsr)
558DEFAULT_IMPL(-1)
559
560int LocApiBase::
561    openAndStartDataCall()
562DEFAULT_IMPL(-1)
563
564void LocApiBase::
565    stopDataCall()
566DEFAULT_IMPL()
567
568void LocApiBase::
569    closeDataCall()
570DEFAULT_IMPL()
571
572void LocApiBase::
573    releaseDataServiceClient()
574DEFAULT_IMPL()
575
576int LocApiBase::
577    setGpsLock(LOC_GPS_LOCK_MASK lock)
578DEFAULT_IMPL(-1)
579
580void LocApiBase::
581    installAGpsCert(const DerEncodedCertificate* pData,
582                    size_t length,
583                    uint32_t slotBitMask)
584DEFAULT_IMPL()
585
586int LocApiBase::
587    getGpsLock()
588DEFAULT_IMPL(-1)
589
590enum loc_api_adapter_err LocApiBase::
591    setXtraVersionCheck(enum xtra_version_check check)
592DEFAULT_IMPL(LOC_API_ADAPTER_ERR_SUCCESS)
593
594bool LocApiBase::
595    gnssConstellationConfig()
596DEFAULT_IMPL(false)
597
598bool LocApiBase::
599    isFeatureSupported(uint8_t featureVal)
600{
601    uint8_t arrayIndex = featureVal >> 3;
602    uint8_t bitPos = featureVal & 7;
603
604    if (arrayIndex >= MAX_FEATURE_LENGTH) return false;
605    return ((mFeaturesSupported[arrayIndex] >> bitPos ) & 0x1);
606}
607
608} // namespace loc_core
609