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