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 storage of PIB attributes in nRF 802.15.4 radio driver.
38  *
39  */
40 
41 #include "nrf_802154_pib.h"
42 
43 #include <assert.h>
44 #include <stdbool.h>
45 #include <stdint.h>
46 #include <string.h>
47 
48 #include "nrf_802154_config.h"
49 #include "nrf_802154_const.h"
50 #include "nrf_802154_utils.h"
51 
52 #define CSMACA_BE_MAXIMUM 8 ///< The maximum allowed CSMA-CA backoff exponent (BE) that results from the implementation
53 
54 typedef struct
55 {
56     nrf_802154_coex_rx_request_mode_t rx_request_mode; ///< Coex request mode in receive operation.
57     nrf_802154_coex_tx_request_mode_t tx_request_mode; ///< Coex request mode in transmit operation.
58 } nrf_802154_pib_coex_t;
59 
60 #if NRF_802154_CSMA_CA_ENABLED
61 typedef struct
62 {
63     uint8_t min_be;       // The minimum value of the backoff exponent (BE) in the CSMA-CA algorithm
64     uint8_t max_be;       // The maximum value of the backoff exponent (BE) in the CSMA-CA algorithm
65     uint8_t max_backoffs; // The maximum number of backoffs that the CSMA-CA algorithm will attempt before declaring a channel access failure.
66 } nrf_802154_pib_csmaca_t;
67 
68 #endif  // NRF_802154_CSMA_CA_ENABLED
69 
70 #if NRF_802154_IFS_ENABLED
71 typedef struct
72 {
73     nrf_802154_ifs_mode_t mode;               ///< Mode of Interframe Space insertion.
74     uint16_t              min_sifs_period_us; ///< Minimum Short Interframe Space period in us.
75     uint16_t              min_lifs_period_us; ///< Minimum Long Interframe Space period in us.
76 } nrf_802154_pib_ifs_t;
77 
78 #endif  // NRF_802154_IFS_ENABLED
79 
80 #if NRF_802154_TEST_MODES_ENABLED
81 typedef struct
82 {
83     nrf_802154_test_mode_csmaca_backoff_t csmaca_backoff; ///< CSMA/CA control mode
84 } nrf_802154_pib_test_modes_t;
85 
86 #endif  // NRF_802154_TEST_MODES_ENABLED
87 
88 typedef struct
89 {
90     int8_t                  tx_power;                             ///< Transmit power.
91     uint8_t                 pan_id[PAN_ID_SIZE];                  ///< Pan Id of this node.
92     uint8_t                 short_addr[SHORT_ADDRESS_SIZE];       ///< Short Address of this node.
93     uint8_t                 extended_addr[EXTENDED_ADDRESS_SIZE]; ///< Extended Address of this node.
94     nrf_802154_cca_cfg_t    cca;                                  ///< CCA mode and thresholds.
95     bool                    promiscuous : 1;                      ///< Indicating if radio is in promiscuous mode.
96     bool                    auto_ack    : 1;                      ///< Indicating if auto ACK procedure is enabled.
97     bool                    pan_coord   : 1;                      ///< Indicating if radio is configured as the PAN coordinator.
98     uint8_t                 channel     : 5;                      ///< Channel on which the node receives messages.
99     nrf_802154_pib_coex_t   coex;                                 ///< Coex-related fields.
100 
101 #if NRF_802154_CSMA_CA_ENABLED
102     nrf_802154_pib_csmaca_t csmaca;                               ///< CSMA-CA related fields.
103 
104 #endif
105 
106 #if NRF_802154_IFS_ENABLED
107     nrf_802154_pib_ifs_t ifs; ///< IFS-related fields.
108 
109 #endif
110 
111 #if NRF_802154_TEST_MODES_ENABLED
112     nrf_802154_pib_test_modes_t test_modes; ///< Test modes
113 
114 #endif
115 
116 } nrf_802154_pib_data_t;
117 
118 // Static variables.
119 static nrf_802154_pib_data_t m_data; ///< Buffer containing PIB data.
120 
121 /**
122  * @brief Checks if provided Coex transmit request mode is supported.
123  *
124  * @param[in] mode  Coex transmit request mode to check.
125  *
126  * @retval true     When value provided by @p mode param is supported.
127  * @retval false    Otherwise.
128  */
coex_tx_request_mode_is_supported(nrf_802154_coex_tx_request_mode_t mode)129 static bool coex_tx_request_mode_is_supported(nrf_802154_coex_tx_request_mode_t mode)
130 {
131     bool result = false;
132 
133     switch (mode)
134     {
135         case NRF_802154_COEX_TX_REQUEST_MODE_FRAME_READY:
136         case NRF_802154_COEX_TX_REQUEST_MODE_CCA_START:
137         case NRF_802154_COEX_TX_REQUEST_MODE_CCA_DONE:
138         case NRF_802154_COEX_TX_REQUEST_MODE_ON_CCA_TOGGLE:
139             result = true;
140             break;
141 
142         default:
143             break;
144     }
145 
146     return result;
147 }
148 
149 /**
150  * @brief Checks if provided Coex receive request mode is supported.
151  *
152  * @param[in] mode  Coex receive request mode to check.
153  *
154  * @retval true     When value provided by @p mode param is supported.
155  * @retval false    Otherwise.
156  */
coex_rx_request_mode_is_supported(nrf_802154_coex_rx_request_mode_t mode)157 static bool coex_rx_request_mode_is_supported(nrf_802154_coex_rx_request_mode_t mode)
158 {
159     bool result = false;
160 
161     switch (mode)
162     {
163 #if defined(RADIO_INTENSET_SYNC_Msk)
164         case NRF_802154_COEX_RX_REQUEST_MODE_ENERGY_DETECTION:
165 #endif
166         case NRF_802154_COEX_RX_REQUEST_MODE_PREAMBLE:
167         case NRF_802154_COEX_RX_REQUEST_MODE_DESTINED:
168             result = true;
169             break;
170 
171         default:
172             break;
173     }
174 
175     return result;
176 }
177 
nrf_802154_pib_init(void)178 void nrf_802154_pib_init(void)
179 {
180     m_data.promiscuous = false;
181     m_data.auto_ack    = true;
182     m_data.pan_coord   = false;
183     m_data.channel     = 11;
184 
185     memset(m_data.pan_id, 0xff, sizeof(m_data.pan_id));
186     m_data.short_addr[0] = 0xfe;
187     m_data.short_addr[1] = 0xff;
188     memset(m_data.extended_addr, 0, sizeof(m_data.extended_addr));
189 
190     m_data.cca.mode           = NRF_802154_CCA_MODE_DEFAULT;
191     m_data.cca.ed_threshold   = NRF_802154_CCA_ED_THRESHOLD_DEFAULT;
192     m_data.cca.corr_threshold = NRF_802154_CCA_CORR_THRESHOLD_DEFAULT;
193     m_data.cca.corr_limit     = NRF_802154_CCA_CORR_LIMIT_DEFAULT;
194 
195     m_data.coex.rx_request_mode = NRF_802154_COEX_RX_REQUEST_MODE_DESTINED;
196     m_data.coex.tx_request_mode = NRF_802154_COEX_TX_REQUEST_MODE_ON_CCA_TOGGLE;
197 
198 #if NRF_802154_CSMA_CA_ENABLED
199     m_data.csmaca.min_be       = NRF_802154_CSMA_CA_MIN_BE_DEFAULT;
200     m_data.csmaca.max_be       = NRF_802154_CSMA_CA_MAX_BE_DEFAULT;
201     m_data.csmaca.max_backoffs = NRF_802154_CSMA_CA_MAX_CSMA_BACKOFFS_DEFAULT;
202 #endif // NRF_802154_CSMA_CA_ENABLED
203 
204 #if NRF_802154_IFS_ENABLED
205     m_data.ifs.min_sifs_period_us = MIN_SIFS_PERIOD_US;
206     m_data.ifs.min_lifs_period_us = MIN_LIFS_PERIOD_US;
207     m_data.ifs.mode               = NRF_802154_IFS_MODE_DISABLED;
208 #endif // NRF_802154_IFS_ENABLED
209 
210 #if NRF_802154_TEST_MODES_ENABLED
211     m_data.test_modes.csmaca_backoff = NRF_802154_TEST_MODE_CSMACA_BACKOFF_RANDOM;
212 #endif
213 
214 }
215 
nrf_802154_pib_promiscuous_get(void)216 bool nrf_802154_pib_promiscuous_get(void)
217 {
218     return m_data.promiscuous;
219 }
220 
nrf_802154_pib_promiscuous_set(bool enabled)221 void nrf_802154_pib_promiscuous_set(bool enabled)
222 {
223     m_data.promiscuous = enabled;
224 }
225 
nrf_802154_pib_auto_ack_get(void)226 bool nrf_802154_pib_auto_ack_get(void)
227 {
228     return m_data.auto_ack;
229 }
230 
nrf_802154_pib_auto_ack_set(bool enabled)231 void nrf_802154_pib_auto_ack_set(bool enabled)
232 {
233     m_data.auto_ack = enabled;
234 }
235 
nrf_802154_pib_pan_coord_get(void)236 bool nrf_802154_pib_pan_coord_get(void)
237 {
238     return m_data.pan_coord;
239 }
240 
nrf_802154_pib_pan_coord_set(bool enabled)241 void nrf_802154_pib_pan_coord_set(bool enabled)
242 {
243     m_data.pan_coord = enabled;
244 }
245 
nrf_802154_pib_channel_get(void)246 uint8_t nrf_802154_pib_channel_get(void)
247 {
248     return m_data.channel;
249 }
250 
nrf_802154_pib_channel_set(uint8_t channel)251 void nrf_802154_pib_channel_set(uint8_t channel)
252 {
253     m_data.channel = channel;
254 }
255 
nrf_802154_pib_tx_power_get(void)256 int8_t nrf_802154_pib_tx_power_get(void)
257 {
258     return m_data.tx_power;
259 }
260 
nrf_802154_pib_tx_power_set(int8_t dbm)261 void nrf_802154_pib_tx_power_set(int8_t dbm)
262 {
263     m_data.tx_power = dbm;
264 }
265 
nrf_802154_pib_pan_id_get(void)266 const uint8_t * nrf_802154_pib_pan_id_get(void)
267 {
268     return m_data.pan_id;
269 }
270 
nrf_802154_pib_pan_id_set(const uint8_t * p_pan_id)271 void nrf_802154_pib_pan_id_set(const uint8_t * p_pan_id)
272 {
273     memcpy(m_data.pan_id, p_pan_id, PAN_ID_SIZE);
274 }
275 
nrf_802154_pib_extended_address_get(void)276 const uint8_t * nrf_802154_pib_extended_address_get(void)
277 {
278     return m_data.extended_addr;
279 }
280 
nrf_802154_pib_extended_address_set(const uint8_t * p_extended_address)281 void nrf_802154_pib_extended_address_set(const uint8_t * p_extended_address)
282 {
283     memcpy(m_data.extended_addr, p_extended_address, EXTENDED_ADDRESS_SIZE);
284 }
285 
nrf_802154_pib_short_address_get(void)286 const uint8_t * nrf_802154_pib_short_address_get(void)
287 {
288     return m_data.short_addr;
289 }
290 
nrf_802154_pib_short_address_set(const uint8_t * p_short_address)291 void nrf_802154_pib_short_address_set(const uint8_t * p_short_address)
292 {
293     memcpy(m_data.short_addr, p_short_address, SHORT_ADDRESS_SIZE);
294 }
295 
nrf_802154_pib_cca_cfg_set(const nrf_802154_cca_cfg_t * p_cca_cfg)296 void nrf_802154_pib_cca_cfg_set(const nrf_802154_cca_cfg_t * p_cca_cfg)
297 {
298     switch (p_cca_cfg->mode)
299     {
300         case NRF_RADIO_CCA_MODE_ED:
301             m_data.cca.mode         = p_cca_cfg->mode;
302             m_data.cca.ed_threshold = p_cca_cfg->ed_threshold;
303             break;
304 
305         case NRF_RADIO_CCA_MODE_CARRIER:
306             m_data.cca.mode           = p_cca_cfg->mode;
307             m_data.cca.corr_threshold = p_cca_cfg->corr_threshold;
308             m_data.cca.corr_limit     = p_cca_cfg->corr_limit;
309             break;
310 
311         case NRF_RADIO_CCA_MODE_CARRIER_AND_ED:
312         case NRF_RADIO_CCA_MODE_CARRIER_OR_ED:
313             memcpy(&m_data.cca, p_cca_cfg, sizeof(m_data.cca));
314             break;
315 
316         default:
317             assert(false);
318     }
319 }
320 
nrf_802154_pib_cca_cfg_get(nrf_802154_cca_cfg_t * p_cca_cfg)321 void nrf_802154_pib_cca_cfg_get(nrf_802154_cca_cfg_t * p_cca_cfg)
322 {
323     memcpy(p_cca_cfg, &m_data.cca, sizeof(m_data.cca));
324 }
325 
nrf_802154_pib_coex_rx_request_mode_set(nrf_802154_coex_rx_request_mode_t mode)326 bool nrf_802154_pib_coex_rx_request_mode_set(nrf_802154_coex_rx_request_mode_t mode)
327 {
328     bool result = coex_rx_request_mode_is_supported(mode);
329 
330     if (result)
331     {
332         m_data.coex.rx_request_mode = mode;
333     }
334 
335     return result;
336 }
337 
nrf_802154_pib_coex_rx_request_mode_get(void)338 nrf_802154_coex_rx_request_mode_t nrf_802154_pib_coex_rx_request_mode_get(void)
339 {
340     return m_data.coex.rx_request_mode;
341 }
342 
nrf_802154_pib_coex_tx_request_mode_set(nrf_802154_coex_tx_request_mode_t mode)343 bool nrf_802154_pib_coex_tx_request_mode_set(nrf_802154_coex_tx_request_mode_t mode)
344 {
345     bool result = coex_tx_request_mode_is_supported(mode);
346 
347     if (result)
348     {
349         m_data.coex.tx_request_mode = mode;
350     }
351 
352     return result;
353 }
354 
nrf_802154_pib_coex_tx_request_mode_get(void)355 nrf_802154_coex_tx_request_mode_t nrf_802154_pib_coex_tx_request_mode_get(void)
356 {
357     return m_data.coex.tx_request_mode;
358 }
359 
360 #if NRF_802154_CSMA_CA_ENABLED
nrf_802154_pib_csmaca_min_be_set(uint8_t min_be)361 bool nrf_802154_pib_csmaca_min_be_set(uint8_t min_be)
362 {
363     bool result = (min_be <= CSMACA_BE_MAXIMUM);
364 
365     if (result)
366     {
367         m_data.csmaca.min_be = min_be;
368     }
369 
370     return result;
371 }
372 
nrf_802154_pib_csmaca_min_be_get(void)373 uint8_t nrf_802154_pib_csmaca_min_be_get(void)
374 {
375     return m_data.csmaca.min_be;
376 }
377 
nrf_802154_pib_csmaca_max_be_set(uint8_t max_be)378 bool nrf_802154_pib_csmaca_max_be_set(uint8_t max_be)
379 {
380     bool result = (max_be <= CSMACA_BE_MAXIMUM);
381 
382     if (result)
383     {
384         m_data.csmaca.max_be = max_be;
385     }
386 
387     return result;
388 }
389 
nrf_802154_pib_csmaca_max_be_get(void)390 uint8_t nrf_802154_pib_csmaca_max_be_get(void)
391 {
392     return m_data.csmaca.max_be;
393 }
394 
nrf_802154_pib_csmaca_max_backoffs_set(uint8_t max_backoffs)395 void nrf_802154_pib_csmaca_max_backoffs_set(uint8_t max_backoffs)
396 {
397     m_data.csmaca.max_backoffs = max_backoffs;
398 }
399 
nrf_802154_pib_csmaca_max_backoffs_get(void)400 uint8_t nrf_802154_pib_csmaca_max_backoffs_get(void)
401 {
402     return m_data.csmaca.max_backoffs;
403 }
404 
405 #endif // NRF_802154_CSMA_CA_ENABLED
406 
407 #if NRF_802154_IFS_ENABLED
nrf_802154_pib_ifs_mode_get(void)408 nrf_802154_ifs_mode_t nrf_802154_pib_ifs_mode_get(void)
409 {
410     return m_data.ifs.mode;
411 }
412 
nrf_802154_pib_ifs_mode_set(nrf_802154_ifs_mode_t mode)413 bool nrf_802154_pib_ifs_mode_set(nrf_802154_ifs_mode_t mode)
414 {
415     switch (mode)
416     {
417         case NRF_802154_IFS_MODE_DISABLED:
418         case NRF_802154_IFS_MODE_MATCHING_ADDRESSES:
419         case NRF_802154_IFS_MODE_ALWAYS:
420             m_data.ifs.mode = mode;
421             return true;
422 
423         default:
424             return false;
425     }
426 }
427 
nrf_802154_pib_ifs_min_sifs_period_get(void)428 uint16_t nrf_802154_pib_ifs_min_sifs_period_get(void)
429 {
430     return m_data.ifs.min_sifs_period_us;
431 }
432 
nrf_802154_pib_ifs_min_sifs_period_set(uint16_t period)433 void nrf_802154_pib_ifs_min_sifs_period_set(uint16_t period)
434 {
435     assert(period >= TURNAROUND_TIME);
436 
437     m_data.ifs.min_sifs_period_us = period;
438 }
439 
nrf_802154_pib_ifs_min_lifs_period_get(void)440 uint16_t nrf_802154_pib_ifs_min_lifs_period_get(void)
441 {
442     return m_data.ifs.min_lifs_period_us;
443 }
444 
nrf_802154_pib_ifs_min_lifs_period_set(uint16_t period)445 void nrf_802154_pib_ifs_min_lifs_period_set(uint16_t period)
446 {
447     m_data.ifs.min_lifs_period_us = period;
448 }
449 
450 #endif // NRF_802154_IFS_ENABLED
451 
452 #if NRF_802154_TEST_MODES_ENABLED
nrf_802154_pib_test_mode_csmaca_backoff_get(void)453 nrf_802154_test_mode_csmaca_backoff_t nrf_802154_pib_test_mode_csmaca_backoff_get(void)
454 {
455     return m_data.test_modes.csmaca_backoff;
456 }
457 
nrf_802154_pib_test_mode_csmaca_backoff_set(nrf_802154_test_mode_csmaca_backoff_t value)458 void nrf_802154_pib_test_mode_csmaca_backoff_set(nrf_802154_test_mode_csmaca_backoff_t value)
459 {
460     m_data.test_modes.csmaca_backoff = value;
461 }
462 
463 #endif // NRF_802154_TEST_MODES_ENABLED
464