xref: /aosp_15_r20/system/chre/pal/util/wifi_pal_convert.c (revision 84e339476a462649f82315436d70fd732297a399)
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