1 /*
2  * Copyright (c) 2017 - 2023, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
18  *    contributors may be used to endorse or promote products derived from this
19  *    software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 
35 /**
36  * @file
37  *   This file implements RSSI calculations for 802.15.4 driver.
38  *
39  */
40 #include "nrf_802154_rssi.h"
41 #include "nrf_802154_nrfx_addons.h"
42 #include "nrf_802154_const.h"
43 
44 #include "nrfx.h"
45 #include <stdint.h>
46 
47 #include "platform/nrf_802154_temperature.h"
48 
49 #if defined(NRF52_SERIES)
50 
51 /* Implementation for nRF52 family. */
nrf_802154_rssi_sample_temp_corr_value_get(uint8_t rssi_sample)52 int8_t nrf_802154_rssi_sample_temp_corr_value_get(uint8_t rssi_sample)
53 {
54     (void)rssi_sample;
55 
56     int8_t temp = nrf_802154_temperature_get();
57     int8_t result;
58 
59 #if defined(NRF52840_XXAA) || defined(NRF52833_XXAA)
60     /* Implementation based on Errata 153 for nRF52840 SoC and Errata 225 for nRF52833 SoCs.. */
61     if (temp <= -30)
62     {
63         result = 3;
64     }
65     else if (temp <= -10)
66     {
67         result = 2;
68     }
69     else if (temp <= 10)
70     {
71         result = 1;
72     }
73     else if (temp <= 30)
74     {
75         result = 0;
76     }
77     else if (temp <= 50)
78     {
79         result = -1;
80     }
81     else if (temp <= 70)
82     {
83         result = -2;
84     }
85     else if (temp <= 85)
86     {
87         result = -3;
88     }
89     else
90     {
91         // nRF52840 cannot work for a temperature above 85 degrees Celsius, so this part won't affect its operation,
92         // even if it isn't present in its errata.
93         result = -4;
94     }
95 #else
96     /* Implementation for other SoCs from nRF52 family */
97     result = 0;
98 #endif
99     return result;
100 }
101 
102 #else
103 
104 /** Macro for calculating x raised to the power of 2. */
105 #define POW_2(x)        ((x) * (x))
106 /** Macro for calculating x raised to the power of 3. */
107 #define POW_3(x)        ((x) * POW_2(x))
108 
109 /**
110  * @brief Polynomial coefficients of the correction equation.
111  *
112  *  Coefficients were calculated as round(x * RSSI_COEFF_BASE) based on Errata 87.
113  */
114 #define RSSI_COEFF_A0   30198989L /* Initial value: 7.2           */
115 #define RSSI_COEFF_A1   6543114L  /* Initial value: 1.56          */
116 #define RSSI_COEFF_A2   41524L    /* Initial value: 9.9e-3        */
117 #define RSSI_COEFF_A3   205L      /* Initial value: 4.9e-5        */
118 #define RSSI_COEFF_TEMP 209715L   /* Initial value: 0.05   */
119 /** @brief Value used to increase precision of calculations. */
120 #define RSSI_COEFF_BASE (1UL << 22U)
121 
122 /**
123  * @brief Normalizes intermediate RSSI value by dividing and rounding.
124  *
125  * @param[in]   rssi_value  Intermediate RSSI value to be normalized.
126  *
127  * @returns normalized rssi_value.
128  */
normalize_rssi(int32_t rssi_value)129 static int8_t normalize_rssi(int32_t rssi_value)
130 {
131     uint32_t abs_rssi_value;
132 
133     abs_rssi_value = (rssi_value < 0) ? (-rssi_value) : rssi_value;
134     abs_rssi_value = (abs_rssi_value + (RSSI_COEFF_BASE / 2)) / RSSI_COEFF_BASE;
135 
136     return (rssi_value < 0) ? (-(int8_t)abs_rssi_value) : ((int8_t)abs_rssi_value);
137 }
138 
139 /* Implementation based on Errata 87 for nRF53 family. */
nrf_802154_rssi_sample_temp_corr_value_get(uint8_t rssi_sample)140 int8_t nrf_802154_rssi_sample_temp_corr_value_get(uint8_t rssi_sample)
141 {
142     int32_t temp;
143     int32_t rssi_sample_i32;
144     int8_t  compensated_rssi;
145 
146     temp            = (int32_t)nrf_802154_temperature_get();
147     rssi_sample_i32 = (int32_t)rssi_sample;
148 
149     compensated_rssi = normalize_rssi((RSSI_COEFF_A1 * rssi_sample_i32)
150                                       + (RSSI_COEFF_A3 * POW_3(rssi_sample_i32))
151                                       - (RSSI_COEFF_A2 * POW_2(rssi_sample_i32))
152                                       - (RSSI_COEFF_TEMP * temp) - RSSI_COEFF_A0);
153 
154     return compensated_rssi - (int8_t)rssi_sample;
155 }
156 
157 #endif
158 
nrf_802154_rssi_sample_corrected_get(uint8_t rssi_sample)159 uint8_t nrf_802154_rssi_sample_corrected_get(uint8_t rssi_sample)
160 {
161     return rssi_sample + nrf_802154_rssi_sample_temp_corr_value_get(rssi_sample);
162 }
163 
nrf_802154_rssi_lqi_corrected_get(uint8_t lqi)164 uint8_t nrf_802154_rssi_lqi_corrected_get(uint8_t lqi)
165 {
166     return lqi - nrf_802154_rssi_sample_temp_corr_value_get(lqi);
167 }
168 
nrf_802154_rssi_ed_corrected_get(int16_t ed)169 int16_t nrf_802154_rssi_ed_corrected_get(int16_t ed)
170 {
171     return ed - nrf_802154_rssi_sample_temp_corr_value_get(ed);
172 }
173 
nrf_802154_rssi_cca_ed_threshold_corrected_get(uint8_t cca_ed)174 uint8_t nrf_802154_rssi_cca_ed_threshold_corrected_get(uint8_t cca_ed)
175 {
176     return cca_ed - nrf_802154_rssi_sample_temp_corr_value_get(cca_ed);
177 }
178 
nrf_802154_rssi_ed_sample_convert(uint8_t ed_sample)179 uint8_t nrf_802154_rssi_ed_sample_convert(uint8_t ed_sample)
180 {
181     int16_t result;
182 
183     result = nrf_802154_rssi_ed_corrected_get(ed_sample);
184     result = ED_RESULT_MAX * (result - EDSAMPLE_MIN_REPORTED_VALUE) /
185              (EDSAMPLE_MAX_REPORTED_VALUE - EDSAMPLE_MIN_REPORTED_VALUE);
186 
187     if (result < 0)
188     {
189         result = 0;
190     }
191 
192     if (result > ED_RESULT_MAX)
193     {
194         result = ED_RESULT_MAX;
195     }
196 
197     return (uint8_t)result;
198 }
199 
nrf_802154_rssi_dbm_from_energy_level_calculate(uint8_t energy_level)200 int8_t nrf_802154_rssi_dbm_from_energy_level_calculate(uint8_t energy_level)
201 {
202     return ((int16_t)(EDSAMPLE_MAX_REPORTED_VALUE - EDSAMPLE_MIN_REPORTED_VALUE) *
203             ((int16_t)energy_level)) /
204            ED_RESULT_MAX + EDSAMPLE_MIN_REPORTED_VALUE + ED_RSSIOFFS;
205 }
206