1*84e33947SAndroid Build Coastguard Worker /*
2*84e33947SAndroid Build Coastguard Worker * Copyright (C) 2021 The Android Open Source Project
3*84e33947SAndroid Build Coastguard Worker *
4*84e33947SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*84e33947SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*84e33947SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*84e33947SAndroid Build Coastguard Worker *
8*84e33947SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*84e33947SAndroid Build Coastguard Worker *
10*84e33947SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*84e33947SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*84e33947SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*84e33947SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*84e33947SAndroid Build Coastguard Worker * limitations under the License.
15*84e33947SAndroid Build Coastguard Worker */
16*84e33947SAndroid Build Coastguard Worker
17*84e33947SAndroid Build Coastguard Worker #include "chre/pal/util/wifi_pal_convert.h"
18*84e33947SAndroid Build Coastguard Worker
19*84e33947SAndroid Build Coastguard Worker // Constants defining the number of bits per LCI IE field.
20*84e33947SAndroid Build Coastguard Worker #define LCI_IE_UNCERTAINTY_BITS 6
21*84e33947SAndroid Build Coastguard Worker #define LCI_IE_LAT_LONG_BITS 34
22*84e33947SAndroid Build Coastguard Worker #define LCI_IE_ALT_TYPE_BITS 4
23*84e33947SAndroid Build Coastguard Worker #define LCI_IE_ALT_BITS 30
24*84e33947SAndroid Build Coastguard Worker
25*84e33947SAndroid Build Coastguard Worker // The LCI subelement ID.
26*84e33947SAndroid Build Coastguard Worker #define LCI_SUBELEMENT_ID 0
27*84e33947SAndroid Build Coastguard Worker
28*84e33947SAndroid Build Coastguard Worker /************************************************
29*84e33947SAndroid Build Coastguard Worker * Private functions
30*84e33947SAndroid Build Coastguard Worker ***********************************************/
31*84e33947SAndroid Build Coastguard Worker
32*84e33947SAndroid Build Coastguard Worker /**
33*84e33947SAndroid Build Coastguard Worker * Reverses the bit positions in a byte.
34*84e33947SAndroid Build Coastguard Worker *
35*84e33947SAndroid Build Coastguard Worker * @param input The input byte.
36*84e33947SAndroid Build Coastguard Worker *
37*84e33947SAndroid Build Coastguard Worker * @return The output byte with reversed bits.
38*84e33947SAndroid Build Coastguard Worker */
reverseBits(uint8_t input)39*84e33947SAndroid Build Coastguard Worker static uint8_t reverseBits(uint8_t input) {
40*84e33947SAndroid Build Coastguard Worker uint8_t output = 0;
41*84e33947SAndroid Build Coastguard Worker for (size_t i = 0; i < 8; i++) {
42*84e33947SAndroid Build Coastguard Worker output <<= 1;
43*84e33947SAndroid Build Coastguard Worker uint8_t tmp = (uint8_t)(input & 1);
44*84e33947SAndroid Build Coastguard Worker output |= tmp;
45*84e33947SAndroid Build Coastguard Worker input >>= 1;
46*84e33947SAndroid Build Coastguard Worker }
47*84e33947SAndroid Build Coastguard Worker
48*84e33947SAndroid Build Coastguard Worker return output;
49*84e33947SAndroid Build Coastguard Worker }
50*84e33947SAndroid Build Coastguard Worker
51*84e33947SAndroid Build Coastguard Worker /**
52*84e33947SAndroid Build Coastguard Worker * @param buf A non-null pointer to a buffer.
53*84e33947SAndroid Build Coastguard Worker * @param bufferBitOffset The bit offset with respect to the buffer pointer.
54*84e33947SAndroid Build Coastguard Worker *
55*84e33947SAndroid Build Coastguard Worker * @return The bit value of the desired bit offset.
56*84e33947SAndroid Build Coastguard Worker */
getBitAtBitOffsetInByteArray(const uint8_t * buf,size_t bufferBitOffset)57*84e33947SAndroid Build Coastguard Worker static uint64_t getBitAtBitOffsetInByteArray(const uint8_t *buf,
58*84e33947SAndroid Build Coastguard Worker size_t bufferBitOffset) {
59*84e33947SAndroid Build Coastguard Worker size_t index = bufferBitOffset / 8;
60*84e33947SAndroid Build Coastguard Worker size_t offsetInByte = bufferBitOffset % 8;
61*84e33947SAndroid Build Coastguard Worker return ((buf[index] & 0x80 >> offsetInByte) != 0);
62*84e33947SAndroid Build Coastguard Worker }
63*84e33947SAndroid Build Coastguard Worker
64*84e33947SAndroid Build Coastguard Worker /**
65*84e33947SAndroid Build Coastguard Worker * Returns the field value of the LCI IE buffer.
66*84e33947SAndroid Build Coastguard Worker *
67*84e33947SAndroid Build Coastguard Worker * The user must invoke this method in order of the IE data fields, providing
68*84e33947SAndroid Build Coastguard Worker * the number of bits the field is encoded as in numBits, and updating
69*84e33947SAndroid Build Coastguard Worker * bufferBitPos sequentially.
70*84e33947SAndroid Build Coastguard Worker *
71*84e33947SAndroid Build Coastguard Worker * @param buf A non-null pointer to a buffer.
72*84e33947SAndroid Build Coastguard Worker * @param numBits The number of bits the value is encoded as.
73*84e33947SAndroid Build Coastguard Worker * @param bufferBitPos The current bit position. This value will be updated as a
74*84e33947SAndroid Build Coastguard Worker * result of this function invocation, and will be incremented by numBits.
75*84e33947SAndroid Build Coastguard Worker *
76*84e33947SAndroid Build Coastguard Worker * @return The field value.
77*84e33947SAndroid Build Coastguard Worker */
getField(const uint8_t * buf,size_t numBits,size_t * bufferBitPos)78*84e33947SAndroid Build Coastguard Worker static uint64_t getField(const uint8_t *buf, size_t numBits,
79*84e33947SAndroid Build Coastguard Worker size_t *bufferBitPos) {
80*84e33947SAndroid Build Coastguard Worker uint64_t field = 0;
81*84e33947SAndroid Build Coastguard Worker for (size_t i = 0; i < numBits; i++) {
82*84e33947SAndroid Build Coastguard Worker // Per specs, we need to store the bits in MSB first per field,
83*84e33947SAndroid Build Coastguard Worker // so we store the bits in reverse order (since we have reverse the bits
84*84e33947SAndroid Build Coastguard Worker // per byte earlier).
85*84e33947SAndroid Build Coastguard Worker field |= getBitAtBitOffsetInByteArray(buf, *bufferBitPos + i) << i;
86*84e33947SAndroid Build Coastguard Worker }
87*84e33947SAndroid Build Coastguard Worker
88*84e33947SAndroid Build Coastguard Worker *bufferBitPos += numBits;
89*84e33947SAndroid Build Coastguard Worker return field;
90*84e33947SAndroid Build Coastguard Worker }
91*84e33947SAndroid Build Coastguard Worker
convert34BitTwosComplementToInt64(uint64_t input)92*84e33947SAndroid Build Coastguard Worker static int64_t convert34BitTwosComplementToInt64(uint64_t input) {
93*84e33947SAndroid Build Coastguard Worker // This is 34 bits, so we need to sign extend
94*84e33947SAndroid Build Coastguard Worker if ((input & 0x200000000) != 0) {
95*84e33947SAndroid Build Coastguard Worker input |= 0xFFFFFFFC00000000;
96*84e33947SAndroid Build Coastguard Worker }
97*84e33947SAndroid Build Coastguard Worker
98*84e33947SAndroid Build Coastguard Worker return (int64_t)input;
99*84e33947SAndroid Build Coastguard Worker }
100*84e33947SAndroid Build Coastguard Worker
convert30BitTwosComplementToInt32(uint32_t input)101*84e33947SAndroid Build Coastguard Worker static int32_t convert30BitTwosComplementToInt32(uint32_t input) {
102*84e33947SAndroid Build Coastguard Worker // This is 30 bits, so we need to sign extend
103*84e33947SAndroid Build Coastguard Worker if ((input & 0x20000000) != 0) {
104*84e33947SAndroid Build Coastguard Worker input |= 0xC0000000;
105*84e33947SAndroid Build Coastguard Worker }
106*84e33947SAndroid Build Coastguard Worker
107*84e33947SAndroid Build Coastguard Worker return (int32_t)input;
108*84e33947SAndroid Build Coastguard Worker }
109*84e33947SAndroid Build Coastguard Worker
decodeLciSubelement(const uint8_t * lciSubelement,struct chreWifiLci * out)110*84e33947SAndroid Build Coastguard Worker static void decodeLciSubelement(const uint8_t *lciSubelement,
111*84e33947SAndroid Build Coastguard Worker struct chreWifiLci *out) {
112*84e33947SAndroid Build Coastguard Worker uint8_t lciDataTmp[CHRE_LCI_SUBELEMENT_DATA_LEN_BYTES];
113*84e33947SAndroid Build Coastguard Worker size_t bufferBitPos = 0;
114*84e33947SAndroid Build Coastguard Worker uint64_t x;
115*84e33947SAndroid Build Coastguard Worker
116*84e33947SAndroid Build Coastguard Worker // First, reverse the bits to get the LSB first per specs.
117*84e33947SAndroid Build Coastguard Worker for (size_t i = 0; i < CHRE_LCI_SUBELEMENT_DATA_LEN_BYTES; i++) {
118*84e33947SAndroid Build Coastguard Worker lciDataTmp[i] = reverseBits(lciSubelement[i]);
119*84e33947SAndroid Build Coastguard Worker }
120*84e33947SAndroid Build Coastguard Worker
121*84e33947SAndroid Build Coastguard Worker out->latitudeUncertainty =
122*84e33947SAndroid Build Coastguard Worker (uint8_t)getField(lciDataTmp, LCI_IE_UNCERTAINTY_BITS, &bufferBitPos);
123*84e33947SAndroid Build Coastguard Worker
124*84e33947SAndroid Build Coastguard Worker x = getField(lciDataTmp, LCI_IE_LAT_LONG_BITS, &bufferBitPos);
125*84e33947SAndroid Build Coastguard Worker out->latitude = convert34BitTwosComplementToInt64(x);
126*84e33947SAndroid Build Coastguard Worker
127*84e33947SAndroid Build Coastguard Worker out->longitudeUncertainty =
128*84e33947SAndroid Build Coastguard Worker (uint8_t)getField(lciDataTmp, LCI_IE_UNCERTAINTY_BITS, &bufferBitPos);
129*84e33947SAndroid Build Coastguard Worker
130*84e33947SAndroid Build Coastguard Worker x = getField(lciDataTmp, LCI_IE_LAT_LONG_BITS, &bufferBitPos);
131*84e33947SAndroid Build Coastguard Worker out->longitude = convert34BitTwosComplementToInt64(x);
132*84e33947SAndroid Build Coastguard Worker
133*84e33947SAndroid Build Coastguard Worker out->altitudeType =
134*84e33947SAndroid Build Coastguard Worker (uint8_t)getField(lciDataTmp, LCI_IE_ALT_TYPE_BITS, &bufferBitPos);
135*84e33947SAndroid Build Coastguard Worker out->altitudeUncertainty =
136*84e33947SAndroid Build Coastguard Worker (uint8_t)getField(lciDataTmp, LCI_IE_UNCERTAINTY_BITS, &bufferBitPos);
137*84e33947SAndroid Build Coastguard Worker
138*84e33947SAndroid Build Coastguard Worker x = getField(lciDataTmp, LCI_IE_ALT_BITS, &bufferBitPos);
139*84e33947SAndroid Build Coastguard Worker out->altitude = convert30BitTwosComplementToInt32((uint32_t)x);
140*84e33947SAndroid Build Coastguard Worker }
141*84e33947SAndroid Build Coastguard Worker
142*84e33947SAndroid Build Coastguard Worker /************************************************
143*84e33947SAndroid Build Coastguard Worker * Public functions
144*84e33947SAndroid Build Coastguard Worker ***********************************************/
chreWifiLciFromIe(const uint8_t * ieData,size_t len,struct chreWifiRangingResult * outResult)145*84e33947SAndroid Build Coastguard Worker bool chreWifiLciFromIe(const uint8_t *ieData, size_t len,
146*84e33947SAndroid Build Coastguard Worker struct chreWifiRangingResult *outResult) {
147*84e33947SAndroid Build Coastguard Worker bool success = false;
148*84e33947SAndroid Build Coastguard Worker const size_t kHeaderLen =
149*84e33947SAndroid Build Coastguard Worker CHRE_LCI_IE_HEADER_LEN_BYTES + CHRE_LCI_SUBELEMENT_HEADER_LEN_BYTES;
150*84e33947SAndroid Build Coastguard Worker if (len >= kHeaderLen) {
151*84e33947SAndroid Build Coastguard Worker size_t pos = CHRE_LCI_IE_HEADER_LEN_BYTES;
152*84e33947SAndroid Build Coastguard Worker
153*84e33947SAndroid Build Coastguard Worker uint8_t subelementId = ieData[pos++];
154*84e33947SAndroid Build Coastguard Worker uint8_t subelementLength = ieData[pos++];
155*84e33947SAndroid Build Coastguard Worker if ((subelementId == LCI_SUBELEMENT_ID) &&
156*84e33947SAndroid Build Coastguard Worker (len >= kHeaderLen + subelementLength)) {
157*84e33947SAndroid Build Coastguard Worker success = true;
158*84e33947SAndroid Build Coastguard Worker if (subelementLength < CHRE_LCI_SUBELEMENT_DATA_LEN_BYTES) {
159*84e33947SAndroid Build Coastguard Worker outResult->flags = 0;
160*84e33947SAndroid Build Coastguard Worker } else {
161*84e33947SAndroid Build Coastguard Worker outResult->flags = CHRE_WIFI_RTT_RESULT_HAS_LCI;
162*84e33947SAndroid Build Coastguard Worker decodeLciSubelement(&ieData[pos], &outResult->lci);
163*84e33947SAndroid Build Coastguard Worker }
164*84e33947SAndroid Build Coastguard Worker }
165*84e33947SAndroid Build Coastguard Worker }
166*84e33947SAndroid Build Coastguard Worker
167*84e33947SAndroid Build Coastguard Worker return success;
168*84e33947SAndroid Build Coastguard Worker }
169