1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
/*
 * Copyright (c) 2019-2025 Beijing Hanwei Innovation Technology Ltd. Co. and
 * its subsidiaries and affiliates (collectly called MKSEMI).
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into an MKSEMI
 *    integrated circuit in a product or a software update for such product,
 *    must reproduce the above copyright notice, this list of conditions and
 *    the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of MKSEMI nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    MKSEMI integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be
 *    reverse engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL MKSEMI OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
#ifndef RANGING_LIB_H
#define RANGING_LIB_H
#include "mk_uwb.h"
 
/**
 * @addtogroup MK8000_ALGO_Ranging
 * @{
 */
 
#ifndef CHEST_DUMP_EN
#define CHEST_DUMP_EN (1)
#endif
 
#ifndef CHEST_DUMP_STS_EN
#define CHEST_DUMP_STS_EN (1)
#endif
 
// total channel tap number
#define MLAGS_LENGTH 160
// output channel tap number
#define CE_LEN (128)
 
// Maximum STS segment number
#define MAX_STS_SEG_NUM (1)
// Maximum STS segment length
#define MAX_STS_SEG_LEN (64)
 
// STS buffer number
#define STS_BUF_NUM (1)
 
/* for 4 symbol based switching, max size is 2*11*256, buffer size = (11*2*Nsegs*seg_len/4)*4 Byte */
/* for segment based switching, max size is 4*11*256 = 11KB (never switch mode use the same formula to calculate buffer size) */
/* if set 11k, it has memory issue when run time */
/* we may not use segment based switching */
#define STS_BUF_SIZE (11 * MAX_STS_SEG_NUM * MAX_STS_SEG_LEN + 2)
 
struct STS_INF_T
{
    float sts_short_ce[11];
    float sts_IQ[22];
    float sts_lsp_result[STS_BUF_SIZE];
};
 
struct RANGING_INF_T
{
    uint32_t CE_CIR[64];
    struct MAC_HW_REPORT_T RPT;
};
 
/** Ranging channel status information */
struct RANGING_CSI_T
{
    uint32_t session_id;
    uint32_t sts_index;
    uint16_t ranging_status;
    uint16_t block_index;
    uint16_t round_index;
    uint16_t distance_cm;
    int16_t azimuth;
    uint8_t ranging_fom;
    uint8_t azimuth_fom;
    uint8_t antenna;
    uint8_t frame_idx;
    uint8_t reserved[2];
 
    // pre-poll | poll | final | final-data
    // poll | final
    // RCM | RIM | RFM | MRM
    struct FRAME_INF_T
    {
        int8_t rssi;
        int8_t snr;
        uint8_t rf_gain;
        uint8_t bb_gain;
        uint16_t bd_cnt;
        uint16_t sfd_cnt;
        int32_t freq_offset;
        uint32_t channel_power;
        uint32_t noise_power;
        int16_t main_tap_power;
        int16_t first_tap_power;
        int16_t fap_delta;
        uint8_t main_tap;
        uint8_t first_tap;
        int16_t sts_fap_delta;
        uint8_t sts_main_tap;
        uint8_t sts_first_tap;
        uint16_t error_code;
        uint8_t nlos;
        uint8_t fom;
        int8_t cir[128][2];
        float sts_taps[11][2];
    } frame[4];
};
 
typedef struct
{
    uint8_t en_rfg_adj;      ///> Enable RF gain adjust logic. Default value: 1
    uint8_t en_hpm;          ///> Enable high performance mode. Default value: 0
    int16_t sfd_offset_db;   ///> Offset to be used when SFD metric is used. Default value: 132.0
    int16_t agc_offset_db;   ///> Offset to be used when AGC gains are used. Default value: 32.0
    int16_t snr_offset_init; ///> Initial offset for SNR calculation. Default value: 10.0
} comp_rssi_t;
 
typedef struct
{
    int32_t ce_delta;
    uint16_t ce_map_loc;
    uint16_t ce_fap_loc;
    int32_t sts_delta;
    uint16_t sts_map_loc;
    uint16_t sts_fap_loc;
    uint8_t ce_fom;
    uint8_t ce_nlos;
    uint8_t sts_fom;
    uint8_t sts_nlos;
 
    uint32_t ce_map_pwr;
    uint32_t ce_fap_pwr;
    uint32_t ce_ch_pwr;
    uint32_t ce_mean_npwr;
    uint32_t ce_max_npwr;
 
    uint32_t sts_map_pwr;
    uint32_t sts_fap_pwr;
    uint32_t sts_ch_pwr;
    uint32_t sts_mean_npwr;
    uint32_t sts_max_npwr;
 
    uint8_t use_ce_sts;
    uint8_t sts_valid;
    uint8_t fap_fom;
    uint8_t angle_valid;
 
    int8_t rssi;
    int8_t snr;
 
    float all_ant_sts_taps[4 * 11];
    float per_ant_sts_pwr[4];
 
    float sts_rssi[4];
    float sts_fap_iq[8];
 
    float theta_est;
    float phi_est;
    float Kfactor;
 
} ranging_result_t;
 
typedef struct
{
    uint8_t local_search_win;      ///> Local search window (configured register value). Default: 2
    uint8_t en_sts_fap_det;        ///> Flag to enable first path detection: 1: Enabled, 0: Disabled
    uint8_t init_detect_opt;       ///> FAP detect option. 0: Original, 1: Enhanced. Default: 1
    uint8_t THR_SF1;               ///> !!! scale factor 1 for threshold. Default: 8 (Internal test purpose only, not accessible to user)
    uint8_t THR_SF2;               ///> !!! scale factor 2 for threshold. Default: 16 (Internal test purpose only, not accessible to user)
    uint8_t ant_switching_enabled; ///> 1: Antenna switching is enabled, 0: Antenna switching is not enabled (single antenna mode)
    uint8_t num_of_antennas;       ///> Number of antenna: tied to the mk_phy parameter. Range 1 to 4
    uint8_t ant_offset;            ///> Antenna offset indicating the main antenna. Tied to the mk_phy parameter. Range 0 to 3
    uint8_t en_skip_ant_ports;     ///> 0: Disabled (Default), 1: Enabled. When 1, IQ samples from skip_port_idx are not used in computation
    uint8_t skip_port_idx; ///> 0 to 3. Only used when en_skp_ant_ports = 1. The port index (relative to main port) whose data is not used. Main port is always
                           /// at index 0
    uint8_t en_dynamic_port_sel; ///> 0: Disabled (Default), 1: Enabled. When 1, SNR metric for all ports are generated and ports will small SNR (based on
                                 /// thres_skip_port) are skipped
    uint8_t opt_sts_ce;          ///> Option for STS CE. 0 (default) - Use sts_short_ce from STS valid module, 1 - Regenerate CE internally using sts store data
                                 ///(original method)
    float total_energy_thres;    ///> total energy threshold. Default: 5.0e-5
    float par_th;                ///> peak to average threshold. default: 6.0
    float preecho_thres_lin;     ///> Pre-echo threshold linear (take configured register value and generate linear value). Range 0.1 to 0.001. Default 0.01
    float ENER_THR1;             ///> !!! Energy threshold 1, Usually around 0.05 or 0.06. Default: 0.05 (Internal test purpose only, not accessible to user)
    float ENER_THR2;             ///> !!! Energy threshold 2, Usually around 0.01 or 0.02. Default: 0.01 (Internal test purpose only, not accessible to user)
    float thres_skip_port;       ///> Default: 0.1. When dynamic port selection is enabled then this threshold is used to select good ports
 
} sts_fap_detect_t;
 
typedef struct
{
    uint8_t ch_number;             // RF channel number
    uint8_t tx_sts_config;         // STS packet configurator ( Valid values 0 to 3) - only applicable in BPRF and HPRF modes.
                                   // Refer to Table 41 of 15.4z standard - specifies where STS is placed
    uint8_t tx_sts_seg_num;        // STS segment number (Valid values 0 to 3). BPRF: 1 segment (parameter value = 0). HPRF:
                                   // 1, 2, 3, or 4 segments
    uint8_t tx_sts_seg_len;        // STS segment length (in units of 512 chips). Valid values 0 to 3. BPRF: 64 (parameter
                                   // value = 1). HPRF: 0 (32), 1 (64), 2 (128), or 3 (256)
    uint8_t tx_en_AoD_mode;        // 1: Enable AoD mode (assumes that the TX has multiple antennas)
    uint8_t antenna_array_size;    // Number of antenna elements
    uint8_t xdim_Nrx_ant;          // Number of antennas along x-axis
    uint8_t ant_sw_period;         // switching period in symbols
    uint8_t rx_syms_avail;         // Number of symbols (512 chips) available on each dwell
    uint8_t alg_option;            // 1 - classical beamforming, 2 - Capon, 3 - Music
    uint8_t gen_steering_vec_file; // Generate steering vector file; 0 - Use pre-generated steering vector file, 1 -
                                   // Re-generate steering vector file
    uint8_t en_calib;              // Enable calibration option - Only used during steering vector generation
    uint8_t module_opt;            // Module Option - 0: ISA based, 1: Matrix based
    int8_t tau1;                   // FE_tp - Default: -12
    int8_t tau2;                   // FE_ti - Default: -10
    int8_t tau3;                   // FE_Fp - Default: -11 (when FE opt = 0)
                                   //         Default: -8 (When FE opt = 1)
    int8_t tau4;                   // FE_Fi - Default: -3 (when FE opt = 0)
                                   //         Default: -11 (when FE opt = 1)
    uint8_t fe_opt_Fp;             // FE_opt_Fp - 0 or 1
    uint8_t cal_mode;              // cal_mode
    uint8_t ant_offset;            // antenna offset to indicate the first antenna in STS field
    uint8_t ant_board_pos;         // antenna board position
    uint8_t sym_cnt_mode;          // 0: auto (based on STS parameters), 1: Custom
    uint8_t aoa_sym_cnt;           // Used only when symbol count mode = 1 (i.e. custom). The number of AoA symbols should be less than the total STS symbols
 
    uint16_t sts_inlen;
    sts_fap_detect_t fap_params;
 
} sts_params_t;
 
// Structure holding the angle information for steering vector generation
typedef struct
{
    uint8_t Ndim;    ///> Number of dimensions. 1 - Azimuth only, 2 - Azimuth and Elevation
    int16_t az_low;  ///> Lower end of azimuth scan range (in degrees)
    int16_t az_high; ///> Higher end of azimuth scan range (in degrees)
    uint8_t az_step; ///> Azimuth step size in degrees. Normally 3
    int16_t el_low;  ///> Lower end of elevation scan range (in degrees)
    int16_t el_high; ///> Higher end of elevation scan range (in degrees)
    uint8_t el_step; ///> Elevation step size in degrees. Normally 3
} angle_span_t;
 
// (aux_mode << 4) | (alg_option)
enum STS_AUX_OPT_T
{
    // 135us
    STS_AUX_ANT_IQ_RSSI = ((1 << 4) | 3),
    // 239us
    STS_AUX_ANT_IQ_RSSI_PDOA = ((1 << 4) | 0),
    // 312us
    STS_AUX_ANT_IQ_RSSI_PDOA_AOA = ((1 << 4) | 2),
    // 930us
    STS_AUX_ANT_IQ_RSSI_PDOA_AOA_FOM = ((2 << 4) | 2),
};
 
// Ranging auxiliary information option
enum RANGING_AUX_OPT_T
{
    // 10us
    CE_AUX_CH_PWR_NLOS = 1,
    // 140us
    CE_AUX_FOM = 2,
    // 150us
    CE_AUX_CH_PWR_NLOS_FOM = 3,
};
 
#ifdef __cplusplus
extern "C" {
#endif
 
#if CHEST_DUMP_EN
#define CIR_LEN 128
#define CE_WIN 16
 
#define PWR_TH 100
#define TAP_MARGIN 4
 
extern struct RANGING_CSI_T debug_csi;
uint8_t ranging_fom_calculate(struct RANGING_CSI_T *csi, uint8_t frame_start, uint8_t response_fom, uint8_t *response_tap_gaps, uint8_t response_tap_gaps_num);
void dump_preamble_cir(uint8_t idx, uint8_t taps_num);
void print_preamble_cir(uint32_t seq_num, uint8_t frame_start, uint8_t frame_num);
int8_t correct_rssi(int8_t rssi);
int8_t correct_snr(int8_t snr);
void calculate_first_tap_power(uint8_t frame_start, uint8_t frame_num);
int8_t calculate_noise_floor(uint8_t rf_gain, uint8_t bb_gain);
uint32_t auto_adjust_filter_coeff(uint8_t idx);
 
#if CHEST_DUMP_STS_EN
void dump_sts_cir(uint8_t idx);
void print_sts_cir(uint8_t frame_start, uint8_t frame_num);
#endif
#endif
 
extern int16_t fap_ones_zeros[256] __attribute__((aligned(4)));
 
extern ranging_result_t g_ranging_result;
 
extern sts_params_t g_sts_params;
 
extern struct STS_INF_T *g_sts_cir_buff;
 
extern struct STS_INF_T g_sts_inf[STS_BUF_NUM];
 
/**
 * @brief Initialize all the global variables that will be used in the ranging lib.
 *
 * @param[in] rframe    Ranging frame type, SP0 ~ SP3
 * @param [in] opt      Options for auxiliary information
 *    0 (000)    -    No auxiliary data is generated
 *    1 (001)    -    (ch pwr, fap/map pwr, Kfactor, LoS/NLoS)
 *    2 (002)    -    (FoM)
 */
void ranging_lib_init(uint8_t rframe, enum RANGING_AUX_OPT_T opt);
 
/**
 * @brief Enable or disable ranging debug CSI output
 * @param[in] en        Enable or disable
 */
void ranging_debug_csi_en_set(uint8_t en);
 
/**
 * @brief Get ranging debug CSI output status
 * @return ranging debug CSI output status
 */
uint8_t ranging_debug_csi_en_get(void);
 
/**
 * @brief Detect the fisrt path of ranging frame.
 * @param[in] rssi      Rx packet RSSI
 * @param[in] snr       Rx packet SNR
 * @return delta of the first path
 */
int32_t ranging_first_path_detect(int8_t rssi, int8_t snr);
 
/**
 * @brief Calculate timestamp difference.
 * @param[in] end           End timestamp
 * @param[in] begin         Begin timestamp
 * @return end - begin
 */
int64_t ranging_timestamp_diff(int64_t end, int64_t begin);
 
/**
 * @brief Calculate TX timestamp of the ranging frame.
 *
 * @param[in] timestamp    PHY timer count of TX
 * @return TX timestamp (unit: 15.65ps)
 */
int64_t ranging_tx_time(uint32_t timestamp);
 
/**
 * @brief Calculate RX timestamp of the ranging frame.
 *
 * @param[in] ind    MAC RX report
 * @return RX timestamp (unit: 15.65ps)
 */
int64_t ranging_rx_time(const struct MAC_HW_REPORT_T *ind);
 
/**
 * @brief Calculate TX timestamp of the ranging frame.
 *
 * @param[in] timestamp    PHY timer count of TX
 * @return TX timestamp (unit: 2ns)
 */
int64_t ranging_tx_time_in_2ns(uint32_t timestamp);
 
/**
 * @brief Calculate RX timestamp of the ranging frame.
 *
 * @param[in] ind    MAC RX report
 * @return RX timestamp (unit: 2ns)
 */
int64_t ranging_rx_time_in_2ns(const struct MAC_HW_REPORT_T *ind);
 
/**
 * @brief Get ranging FAP FoM.
 *
 * @param[out] NLoS     Non-Line of sight flag, 0/1: LoS, 2: Multipath, 3: NLoS
 * @param[out] FoM      FAP confidence measure, 0 ~ 100
 */
void ranging_fom_get(uint8_t *NLoS, uint8_t *FoM);
 
/**
 * @brief Set antenna delay for ranging.
 *
 * @param[in] ant_idx       antenna port index, from 0 to 3
 * @param[in] delay_rstu    antenna delay, unit 15.65ps
 */
void ranging_ant_delays_set(uint8_t ant_idx, int16_t delay_rstu);
 
/**
 * @brief Get antenna delay for ranging.
 *
 * @param[in] ant_idx       antenna port index, from 0 to 3
 * @return antenna delay of the specified port, unit 15.6ps
 */
int16_t ranging_ant_delays_get(uint8_t ant_idx);
 
/**
 * @brief Get UWB RX RSSI.
 *
 * @param[out] rssi    RSSI (-110 ~ -10) dBm
 * @param[out] snr     SNR (-21 ~ 20) dB
 */
void ranging_rssi_get(int8_t *rssi, int8_t *snr);
 
/**
 * @brief Configure STS parameters.
 * @param[in] rframe            Ranging frame type, SP0 ~ SP3
 * @param [in] opt              STS auxiliary option @ref enum STS_AUX_OPT_T
 * @param [in] sts_buff_num     STS buffer number @ref STS_BUF_NUM
 * @param [in] sts_buff_len     STS buffer length @ref STS_BUF_SIZE
 * @return Size of samples that need LSP to process
 */
uint16_t sts_param_config(uint8_t rframe, enum STS_AUX_OPT_T opt, uint8_t sts_buff_num, uint16_t sts_buff_len);
 
/**
 * @brief Update STS parameters.
 * @param [in] main_ant         RX main antenna
 */
void sts_param_update(uint8_t main_ant);
 
/**
 * @brief Enable or disable dynamic port selection
 * @param [in] enable           0: disable, 1: enable
 */
void sts_dynamic_port_sel(uint8_t enable);
 
/**
 * @brief Store LSP result of RX ranging frame.
 */
void sts_lsp_store(void);
 
/**
 * @brief Stop storing LSP result of RX ranging frame.
 */
void sts_lsp_store_stop(void);
 
/**
 * @brief Validate STS.
 * @return 1 represents STS is valid
 */
uint8_t sts_valid_check(void);
 
/**
 * @brief Detect the fisrt path of ranging frame based on STS.
 * @param [in] rssi                 RSSI
 * @param [in] snr                  SNR
 * @return delta of the first path
 */
int32_t sts_first_path_detect(int8_t rssi, int8_t snr);
 
/**
 * @brief Calculate RX main antenna based on STS RSSI.
 * @param [in][out]                 Input current main antenna ID, ouput updated main antenna ID
 */
void sts_rx_main_ant_get(uint8_t *id);
 
/**
 * @brief Get 4 antenna port RSSI.
 * @return array of 4 antenna port RSSI
 */
float *sts_4ant_rssi_get(void);
 
/**
 * @brief Get RSSI result.
 *
 * @return RSSI
 */
float *sts_rssi_output_get(void);
 
/**
 * @brief Get STS first path IQ of each antenna port, needs to call AoA calculation or PDoA calculation in advanced.
 *
 * @return STS first path IQ
 */
float *sts_first_path_iq_get(void);
 
/**
 * @brief Function to compute 10*log10 of a number
 * This function takes in 32-bit integer and outputs 10*log10 in floating point
 *
 * @param[in] num              Input number
 * @return the result of 10*log10(num)
 */
float fast_10log10(uint32_t num);
 
/**
 * @brief Get ranging library version.
 *
 * @return String of ranging library version
 */
const char *MK8000_get_rangelib_version(void);
 
#ifdef __cplusplus
}
#endif
 
/**
 * @}
 */
 
#endif // RANGING_LIB_H