1 /** @file wls_api.c
2 *
3 * @brief This file contains source code for CSI processing API.
4 *
5 * Copyright 2023-2024 NXP
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
9 */
10
11 /************************************************************************
12 * DFW source code for CSI processing API.
13 ************************************************************************/
14
15 #include <osa.h>
16 #if CONFIG_WLS_CSI_PROC
17
18 // Standard includes.
19 // #include <stdio.h>
20 // #include <stdlib.h>
21 #include <string.h>
22
23 // Specific includes.
24 #include "wls_param_defines.h"
25 #include "wls_structure_defs.h"
26
27 #include "wls_radix4Fft.h"
28 #ifdef ENABLE_AOA
29 #include "wls_aoa_processing.h"
30 #endif
31 #ifdef ARM_DS5
32 #include "wls_processing_Neon_Intrinsic.h"
33 #endif
34
35 #include "wls_processing.h"
36 #ifdef FFT_PARALLEL
37 #include "wls_processing_parallel.h"
38 #endif
39 #ifdef ENABLE_SUBSPACE_FTIMING
40 #include "wls_subspace_processing.h"
41 #endif
42
43 #ifdef DEBUG_OUT_FD
saveDebug(unsigned int * writePointer,unsigned int * readPointer,int size)44 void saveDebug(unsigned int *writePointer, unsigned int *readPointer, int size)
45 {
46 int ii;
47
48 for (ii = 0; ii < size; ii++)
49 {
50 writePointer[ii] = readPointer[ii];
51 }
52 }
53 #endif
54
wls_process_csi(unsigned int * bufferMemory,unsigned int * fftBuffer,hal_wls_packet_params_t * packetparams,hal_wls_processing_input_params_t * inputVals,unsigned int * resArray)55 int wls_process_csi(
56 unsigned int *bufferMemory, // CSI buffer
57 unsigned int *fftBuffer, // 2k times (MAX_RX*MAX_TX+1) scratch memory
58 hal_wls_packet_params_t *packetparams, // values from Rx/Tx-Info, used mostly to find correct CSI buffer
59 hal_wls_processing_input_params_t *inputVals, // WLS / AoA CSI Processing Parameters Structure
60 unsigned int *resArray) // outputs � phase roll, first path, pktinfo, difference of rxInfo CSI TSF counters
61 { // weight1, weight2, angle, delay (16 bits each) for AoA processing per Peak
62
63 int csiDataSize;
64 int fftSize, ifftSizeOsf, firstPathDelay, maxIdx;
65 unsigned int maxVal;
66 unsigned int *fftInBuffer, *pdpOut;
67 unsigned int powerPerSubband[4 * MAX_RX * MAX_TX]; // max num. of 40 MHz subbands
68 unsigned int totalpower[MAX_RX * MAX_TX + 1];
69 int phaseRollNg[MAX_RX * MAX_TX];
70 unsigned int headerBuffer[HEADER_LEN];
71
72 int header_length, start_csi = 0;
73 unsigned int tempVec[2] = {0, 0};
74 #ifdef ENABLE_AOA
75 hal_cal_struc_t calData;
76 #endif
77 hal_csirxinfo_t *csirxinfo;
78 hal_pktinfo_t *pktinfo;
79
80 memcpy(&headerBuffer, bufferMemory, HEADER_LEN * sizeof(unsigned int));
81
82 if (!(inputVals->enableCsi))
83 {
84 return -1;
85 }
86
87 #if defined(DEBUG_CYCLE_TIME)
88 DEBUG_DELTA_TIME_US1 = ((UINT64)HAL_REGS32(0x8000a604) << 32) + HAL_REGS32(0x8000a600);
89 #endif
90
91 csirxinfo = (hal_csirxinfo_t *)headerBuffer;
92
93 tempVec[0] = (unsigned int)csirxinfo->pktinfo;
94 pktinfo = (hal_pktinfo_t *)tempVec;
95
96 if (pktinfo->packetType < 3)
97 { // HT, legacy
98 if (pktinfo->packetType == 0)
99 { // legacy
100 pktinfo->sigBw = pktinfo->rxDevBw;
101 }
102
103 if (pktinfo->sigBw)
104 { // bw > 20 MHz
105 pktinfo->NgDsfShift = pktinfo->Ng + 1;
106 }
107 else
108 { // 20 MHz
109 pktinfo->NgDsfShift = 0;
110 }
111 }
112 else
113 { // VHT, HE
114 pktinfo->NgDsfShift = 0;
115 // pktinfo->Ng = 0; // not used
116 }
117
118 #ifdef SMAC_BFINFO
119 header_length = csirxinfo->header_length;
120 csiDataSize = bufferMemory[header_length] - 1;
121 start_csi = header_length + 1;
122 #else
123 header_length = HEADER_LEN;
124 start_csi = header_length;
125 if (csirxinfo->ltf)
126 {
127 start_csi += bufferMemory[header_length];
128 }
129 csiDataSize = bufferMemory[start_csi] - 1;
130 start_csi++;
131 #endif
132
133 fftSize = pktinfo->sigBw + IFFT_OSF_SHIFT - pktinfo->NgDsfShift;
134 pktinfo->fftSize = (fftSize < MAX_IFFT_SIZE_SHIFT) ? fftSize : MAX_IFFT_SIZE_SHIFT;
135 pktinfo->scOffset = 0;
136 ifftSizeOsf = 1 << (pktinfo->fftSize + 6);
137 #if defined(FFT_INPLACE)
138 fftInBuffer = fftBuffer;
139 #else
140 fftInBuffer = fftBuffer + NUM_PARALLEL * ifftSizeOsf;
141 #endif
142 // expand data from 8->16 bit, demodulate pilots for L-LTF, measure power and linear phase
143 if (pktinfo->packetType > 2)
144 { // VHT+HE (Ng=1)
145 #ifdef FFT_PARALLEL
146 readHexDataDemodulateProcessVhtHeNg1Parallel(pktinfo, inputVals, bufferMemory + start_csi, csiDataSize,
147 fftInBuffer, powerPerSubband, phaseRollNg, packetparams->chNum);
148 #else
149 readHexDataDemodulateProcessVhtHeNg1(pktinfo, inputVals, bufferMemory + start_csi, csiDataSize, fftInBuffer,
150 powerPerSubband, phaseRollNg, packetparams->chNum);
151 #endif
152 if (pktinfo->sigBw == 3) // 160 MHz only
153 detectPhaseJump(pktinfo, inputVals, fftInBuffer, phaseRollNg);
154 }
155 else
156 { // Legacy, HT, Ng=2/4
157 #ifdef FFT_PARALLEL
158 readHexDataDemodulateProcessParallel(pktinfo, inputVals, bufferMemory + start_csi, csiDataSize, fftInBuffer,
159 powerPerSubband, phaseRollNg, packetparams->chNum);
160 #else
161 readHexDataDemodulateProcess(pktinfo, inputVals, bufferMemory + start_csi, csiDataSize, fftInBuffer,
162 powerPerSubband, phaseRollNg, packetparams->chNum);
163 #endif
164 }
165 if (pktinfo->packetType == 0)
166 { // in case of legacy packets, check active subbands && (packetparams->ftmSignalBW<pktinfo->sigBw)
167 findActiveSubbands(pktinfo, powerPerSubband, totalpower, packetparams->chNum, packetparams->ftmSignalBW);
168 zeroOutTones(pktinfo, fftInBuffer, ifftSizeOsf);
169 }
170 else
171 {
172 calculateTotalPower(pktinfo, powerPerSubband, totalpower);
173 }
174 #ifndef STA_20_ONLY
175 if (((pktinfo->packetType < 4) && (pktinfo->sigBw > 0)) || (pktinfo->rxDevBw == 3))
176 { // not for HE and BW > 20 MHz
177 #if defined(FFT_PARALLEL) && defined(ARM_DS5)
178 removeToneRotationIntrinsic(pktinfo, fftInBuffer, ifftSizeOsf);
179 #elif defined(FFT_PARALLEL) && !defined(ARM_DS5)
180 removeToneRotationParallel(pktinfo, fftInBuffer, ifftSizeOsf);
181 #else
182 removeToneRotation(pktinfo, fftInBuffer, ifftSizeOsf);
183 #endif
184 }
185 if ((pktinfo->packetType == 0) && (pktinfo->rxDevBw > 0))
186 { // all legacy except full interpolation for 20in20
187 processLegacyPackets(pktinfo, fftInBuffer, ifftSizeOsf, phaseRollNg);
188 }
189 #endif
190 if ((pktinfo->packetType > 2) || ((pktinfo->packetType == 1) && (pktinfo->Ng == 0)) // add HT20, HT40 case, Ng=2
191 || ((pktinfo->packetType == 0) && (pktinfo->sigBw == 0) && (pktinfo->rxDevBw == 0))) // add Leg20 case, DevBw=0
192 {
193 #if defined(FFT_PARALLEL) && defined(ARM_DS5)
194 interpolatePilotsIntrinsic(pktinfo, fftInBuffer, ifftSizeOsf, phaseRollNg, totalpower);
195 #elif defined(FFT_PARALLEL) && !defined(ARM_DS5)
196 interpolatePilotsParallel(pktinfo, fftInBuffer, ifftSizeOsf, phaseRollNg, totalpower);
197 #else
198 interpolatePilots(pktinfo, fftInBuffer, ifftSizeOsf, phaseRollNg, totalpower);
199 #endif
200 }
201 #if defined(DEBUG_OUT_FD) && !defined(ARM_DS5)
202 saveDebug(bufferMemory, fftInBuffer + 0 * ifftSizeOsf, ifftSizeOsf);
203 #endif
204 // ifft processing
205 ifftProcessing(pktinfo, fftInBuffer, fftBuffer, ifftSizeOsf); // ifftSizeOsf might not match pktinfo->sigBw
206
207 // update
208 fftSize = (1 << (pktinfo->sigBw + 6));
209 ifftSizeOsf = 1 << (pktinfo->fftSize + 6);
210 pktinfo->rsvd1 = 0;
211
212 resArray[2] = (unsigned int)tempVec[0]; // = pktinfo
213 resArray[3] = (unsigned int)tempVec[1]; // = pktinfo
214
215 #if defined(DEBUG_OUT_TD) && !defined(ARM_DS5)
216 saveDebug(bufferMemory + data_length, fftBuffer + 0 * ifftSizeOsf, NUM_PARALLEL * ifftSizeOsf);
217 #endif
218 // determine first path
219 pdpOut = fftBuffer + (MAX_RX * MAX_TX) * ifftSizeOsf; // last buffer
220
221 if (inputVals->useToaMin == 1)
222 {
223 calcPdpAndFirstPathMin(pktinfo, fftBuffer, pdpOut, totalpower, &maxIdx, &maxVal, &firstPathDelay);
224 }
225 else
226 {
227 #if defined(FFT_PARALLEL) && defined(ARM_DS5)
228 calcPdpAndMaxIntrinsic(pktinfo, fftBuffer, pdpOut, totalpower, &maxIdx, &maxVal);
229 #else
230 calcPdpAndMaxParallel(pktinfo, fftBuffer, pdpOut, totalpower, &maxIdx, &maxVal);
231 #endif
232 firstPathDelay = findFirstPath(pktinfo, pdpOut, maxIdx, maxVal, 1);
233 }
234 if (pktinfo->packetType > 2)
235 { // Ng=1 case
236 resArray[0] = ((phaseRollNg[0] * fftSize << 2) / 5) >> (pktinfo->sigBw);
237 }
238 else
239 { // Ng=2/4 case
240 resArray[0] = ((phaseRollNg[0] * fftSize << 1) / 5) >> (pktinfo->sigBw + pktinfo->Ng);
241 }
242 #ifdef ENABLE_SUBSPACE_FTIMING
243 {
244 int fineTimingRes, retVal = 1;
245 if (inputVals->useSubspace == 1)
246 {
247 retVal = calcSubspaceFineTiming(pktinfo, fftBuffer, totalpower, firstPathDelay, &fineTimingRes, pdpOut,
248 packetparams);
249 }
250 if (retVal)
251 { // error or not uses, use first path
252 fineTimingRes = firstPathDelay;
253 }
254 resArray[1] = ((fineTimingRes << (14 - TOA_FPATH_BIPT)) / 5) >> (pktinfo->fftSize + pktinfo->NgDsfShift);
255 }
256 #else
257 // final format is 32.TOA_FPATH_BIPT in micro seconds
258 resArray[1] = ((firstPathDelay << (14 - TOA_FPATH_BIPT)) / 5) >> (pktinfo->fftSize + pktinfo->NgDsfShift);
259 #endif
260 #ifdef ENABLE_AOA
261 if (inputVals->enableAoA && pktinfo->nRx)
262 { // at least 2 Rx paths
263 readCalDataNew(&calData, packetparams, pktinfo, inputVals);
264 resArray[4] = maxVal >> 15;
265 if (inputVals->useFindAngleDelayPeaks && (pktinfo->nRx > 1))
266 { // at least 3 Rx paths
267 findAngleDelayPeaks(pktinfo, packetparams, inputVals, &calData, fftBuffer, pdpOut, totalpower, maxIdx,
268 resArray + 4);
269 }
270 else
271 {
272 findAngleLinPhase(pktinfo, packetparams, &calData, fftBuffer, totalpower, firstPathDelay, resArray + 5);
273 }
274 }
275 if (inputVals->dumpRawAngle)
276 {
277 dumpRawComplex(pktinfo, fftBuffer, firstPathDelay, resArray + 8);
278 }
279 #endif
280 #if defined(DEBUG_CYCLE_TIME)
281 DEBUG_DELTA_TIME_US2 = ((UINT64)HAL_REGS32(0x8000a604) << 32) + HAL_REGS32(0x8000a600);
282 DEBUG_DELTA_TIME_US = DEBUG_DELTA_TIME_US2 - DEBUG_DELTA_TIME_US1;
283 #endif
284
285 return 0;
286 }
287
288 #endif /* CONFIG_WLS_CSI_PROC */
289