1 /*
2  * Copyright (c) 2017, 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 "nrf_802154_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 
51 #define CSMACA_BE_MAXIMUM 8 ///< The maximum allowed CSMA-CA backoff exponent (BE) that results from the implementation
52 
53 typedef struct
54 {
55     nrf_802154_coex_rx_request_mode_t rx_request_mode; ///< Coex request mode in receive operation.
56     nrf_802154_coex_tx_request_mode_t tx_request_mode; ///< Coex request mode in transmit operation.
57 } nrf_802154_pib_coex_t;
58 
59 #if NRF_802154_CSMA_CA_ENABLED
60 typedef struct
61 {
62     uint8_t min_be;       // The minimum value of the backoff exponent (BE) in the CSMA-CA algorithm
63     uint8_t max_be;       // The maximum value of the backoff exponent (BE) in the CSMA-CA algorithm
64     uint8_t max_backoffs; // The maximum number of backoffs that the CSMA-CA algorithm will attempt before declaring a channel access failure.
65 } nrf_802154_pib_csmaca_t;
66 
67 #endif  // NRF_802154_CSMA_CA_ENABLED
68 
69 #if NRF_802154_IFS_ENABLED
70 typedef struct
71 {
72     nrf_802154_ifs_mode_t mode;               ///< Mode of Interframe Space insertion.
73     uint16_t              min_sifs_period_us; ///< Minimum Short Interframe Space period in us.
74     uint16_t              min_lifs_period_us; ///< Minimum Long Interframe Space period in us.
75 } nrf_802154_pib_ifs_t;
76 
77 #endif  // NRF_802154_IFS_ENABLED
78 
79 #if NRF_802154_TEST_MODES_ENABLED
80 typedef struct
81 {
82     nrf_802154_test_mode_csmaca_backoff_t csmaca_backoff; ///< CSMA/CA control mode
83 } nrf_802154_pib_test_modes_t;
84 
85 #endif  // NRF_802154_TEST_MODES_ENABLED
86 
87 typedef struct
88 {
89     int8_t                  tx_power;                             ///< Transmit power.
90     uint8_t                 pan_id[PAN_ID_SIZE];                  ///< Pan Id of this node.
91     uint8_t                 short_addr[SHORT_ADDRESS_SIZE];       ///< Short Address of this node.
92     uint8_t                 extended_addr[EXTENDED_ADDRESS_SIZE]; ///< Extended Address of this node.
93     nrf_802154_cca_cfg_t    cca;                                  ///< CCA mode and thresholds.
94     bool                    promiscuous : 1;                      ///< Indicating if radio is in promiscuous mode.
95     bool                    auto_ack    : 1;                      ///< Indicating if auto ACK procedure is enabled.
96     bool                    pan_coord   : 1;                      ///< Indicating if radio is configured as the PAN coordinator.
97     uint8_t                 channel     : 5;                      ///< Channel on which the node receives messages.
98     bool                    rx_on_when_idle;                      ///< Indicating if radio is in RxOnWhenIdle mode.
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.rx_on_when_idle = true;
182     m_data.auto_ack        = true;
183     m_data.pan_coord       = false;
184     m_data.channel         = 11;
185 
186     memset(m_data.pan_id, 0xff, sizeof(m_data.pan_id));
187     m_data.short_addr[0] = 0xfe;
188     m_data.short_addr[1] = 0xff;
189     memset(m_data.extended_addr, 0, sizeof(m_data.extended_addr));
190 
191     m_data.cca.mode           = NRF_802154_CCA_MODE_DEFAULT;
192     m_data.cca.ed_threshold   = NRF_802154_CCA_ED_THRESHOLD_DEFAULT;
193     m_data.cca.corr_threshold = NRF_802154_CCA_CORR_THRESHOLD_DEFAULT;
194     m_data.cca.corr_limit     = NRF_802154_CCA_CORR_LIMIT_DEFAULT;
195 
196     m_data.coex.rx_request_mode = NRF_802154_COEX_RX_REQUEST_MODE_DESTINED;
197     m_data.coex.tx_request_mode = NRF_802154_COEX_TX_REQUEST_MODE_ON_CCA_TOGGLE;
198 
199 #if NRF_802154_CSMA_CA_ENABLED
200     m_data.csmaca.min_be       = NRF_802154_CSMA_CA_MIN_BE_DEFAULT;
201     m_data.csmaca.max_be       = NRF_802154_CSMA_CA_MAX_BE_DEFAULT;
202     m_data.csmaca.max_backoffs = NRF_802154_CSMA_CA_MAX_CSMA_BACKOFFS_DEFAULT;
203 #endif // NRF_802154_CSMA_CA_ENABLED
204 
205 #if NRF_802154_IFS_ENABLED
206     m_data.ifs.min_sifs_period_us = MIN_SIFS_PERIOD_US;
207     m_data.ifs.min_lifs_period_us = MIN_LIFS_PERIOD_US;
208     m_data.ifs.mode               = NRF_802154_IFS_MODE_DISABLED;
209 #endif // NRF_802154_IFS_ENABLED
210 
211 #if NRF_802154_TEST_MODES_ENABLED
212     m_data.test_modes.csmaca_backoff = NRF_802154_TEST_MODE_CSMACA_BACKOFF_RANDOM;
213 #endif
214 
215 }
216 
nrf_802154_pib_promiscuous_get(void)217 bool nrf_802154_pib_promiscuous_get(void)
218 {
219     return m_data.promiscuous;
220 }
221 
nrf_802154_pib_promiscuous_set(bool enabled)222 void nrf_802154_pib_promiscuous_set(bool enabled)
223 {
224     m_data.promiscuous = enabled;
225 }
226 
nrf_802154_pib_rx_on_when_idle_get(void)227 bool nrf_802154_pib_rx_on_when_idle_get(void)
228 {
229     return m_data.rx_on_when_idle;
230 }
231 
nrf_802154_pib_rx_on_when_idle_set(bool enabled)232 void nrf_802154_pib_rx_on_when_idle_set(bool enabled)
233 {
234     m_data.rx_on_when_idle = enabled;
235 }
236 
nrf_802154_pib_auto_ack_get(void)237 bool nrf_802154_pib_auto_ack_get(void)
238 {
239     return m_data.auto_ack;
240 }
241 
nrf_802154_pib_auto_ack_set(bool enabled)242 void nrf_802154_pib_auto_ack_set(bool enabled)
243 {
244     m_data.auto_ack = enabled;
245 }
246 
nrf_802154_pib_pan_coord_get(void)247 bool nrf_802154_pib_pan_coord_get(void)
248 {
249     return m_data.pan_coord;
250 }
251 
nrf_802154_pib_pan_coord_set(bool enabled)252 void nrf_802154_pib_pan_coord_set(bool enabled)
253 {
254     m_data.pan_coord = enabled;
255 }
256 
nrf_802154_pib_channel_get(void)257 uint8_t nrf_802154_pib_channel_get(void)
258 {
259     return m_data.channel;
260 }
261 
nrf_802154_pib_channel_set(uint8_t channel)262 void nrf_802154_pib_channel_set(uint8_t channel)
263 {
264     m_data.channel = channel;
265 }
266 
nrf_802154_pib_tx_power_get(void)267 int8_t nrf_802154_pib_tx_power_get(void)
268 {
269     return m_data.tx_power;
270 }
271 
nrf_802154_pib_tx_power_set(int8_t dbm)272 void nrf_802154_pib_tx_power_set(int8_t dbm)
273 {
274     m_data.tx_power = dbm;
275 }
276 
nrf_802154_pib_pan_id_get(void)277 const uint8_t * nrf_802154_pib_pan_id_get(void)
278 {
279     return m_data.pan_id;
280 }
281 
nrf_802154_pib_pan_id_set(const uint8_t * p_pan_id)282 void nrf_802154_pib_pan_id_set(const uint8_t * p_pan_id)
283 {
284     memcpy(m_data.pan_id, p_pan_id, PAN_ID_SIZE);
285 }
286 
nrf_802154_pib_extended_address_get(void)287 const uint8_t * nrf_802154_pib_extended_address_get(void)
288 {
289     return m_data.extended_addr;
290 }
291 
nrf_802154_pib_extended_address_set(const uint8_t * p_extended_address)292 void nrf_802154_pib_extended_address_set(const uint8_t * p_extended_address)
293 {
294     memcpy(m_data.extended_addr, p_extended_address, EXTENDED_ADDRESS_SIZE);
295 }
296 
nrf_802154_pib_short_address_get(void)297 const uint8_t * nrf_802154_pib_short_address_get(void)
298 {
299     return m_data.short_addr;
300 }
301 
nrf_802154_pib_short_address_set(const uint8_t * p_short_address)302 void nrf_802154_pib_short_address_set(const uint8_t * p_short_address)
303 {
304     memcpy(m_data.short_addr, p_short_address, SHORT_ADDRESS_SIZE);
305 }
306 
nrf_802154_pib_cca_cfg_set(const nrf_802154_cca_cfg_t * p_cca_cfg)307 void nrf_802154_pib_cca_cfg_set(const nrf_802154_cca_cfg_t * p_cca_cfg)
308 {
309     switch (p_cca_cfg->mode)
310     {
311         case NRF_RADIO_CCA_MODE_ED:
312             m_data.cca.mode         = p_cca_cfg->mode;
313             m_data.cca.ed_threshold = p_cca_cfg->ed_threshold;
314             break;
315 
316         case NRF_RADIO_CCA_MODE_CARRIER:
317             m_data.cca.mode           = p_cca_cfg->mode;
318             m_data.cca.corr_threshold = p_cca_cfg->corr_threshold;
319             m_data.cca.corr_limit     = p_cca_cfg->corr_limit;
320             break;
321 
322         case NRF_RADIO_CCA_MODE_CARRIER_AND_ED:
323         case NRF_RADIO_CCA_MODE_CARRIER_OR_ED:
324             memcpy(&m_data.cca, p_cca_cfg, sizeof(m_data.cca));
325             break;
326 
327         default:
328             NRF_802154_ASSERT(false);
329     }
330 }
331 
nrf_802154_pib_cca_cfg_get(nrf_802154_cca_cfg_t * p_cca_cfg)332 void nrf_802154_pib_cca_cfg_get(nrf_802154_cca_cfg_t * p_cca_cfg)
333 {
334     memcpy(p_cca_cfg, &m_data.cca, sizeof(m_data.cca));
335 }
336 
nrf_802154_pib_coex_rx_request_mode_set(nrf_802154_coex_rx_request_mode_t mode)337 bool nrf_802154_pib_coex_rx_request_mode_set(nrf_802154_coex_rx_request_mode_t mode)
338 {
339     bool result = coex_rx_request_mode_is_supported(mode);
340 
341     if (result)
342     {
343         m_data.coex.rx_request_mode = mode;
344     }
345 
346     return result;
347 }
348 
nrf_802154_pib_coex_rx_request_mode_get(void)349 nrf_802154_coex_rx_request_mode_t nrf_802154_pib_coex_rx_request_mode_get(void)
350 {
351     return m_data.coex.rx_request_mode;
352 }
353 
nrf_802154_pib_coex_tx_request_mode_set(nrf_802154_coex_tx_request_mode_t mode)354 bool nrf_802154_pib_coex_tx_request_mode_set(nrf_802154_coex_tx_request_mode_t mode)
355 {
356     bool result = coex_tx_request_mode_is_supported(mode);
357 
358     if (result)
359     {
360         m_data.coex.tx_request_mode = mode;
361     }
362 
363     return result;
364 }
365 
nrf_802154_pib_coex_tx_request_mode_get(void)366 nrf_802154_coex_tx_request_mode_t nrf_802154_pib_coex_tx_request_mode_get(void)
367 {
368     return m_data.coex.tx_request_mode;
369 }
370 
371 #if NRF_802154_CSMA_CA_ENABLED
nrf_802154_pib_csmaca_min_be_set(uint8_t min_be)372 bool nrf_802154_pib_csmaca_min_be_set(uint8_t min_be)
373 {
374     bool result = (min_be <= CSMACA_BE_MAXIMUM);
375 
376     if (result)
377     {
378         m_data.csmaca.min_be = min_be;
379     }
380 
381     return result;
382 }
383 
nrf_802154_pib_csmaca_min_be_get(void)384 uint8_t nrf_802154_pib_csmaca_min_be_get(void)
385 {
386     return m_data.csmaca.min_be;
387 }
388 
nrf_802154_pib_csmaca_max_be_set(uint8_t max_be)389 bool nrf_802154_pib_csmaca_max_be_set(uint8_t max_be)
390 {
391     bool result = (max_be <= CSMACA_BE_MAXIMUM);
392 
393     if (result)
394     {
395         m_data.csmaca.max_be = max_be;
396     }
397 
398     return result;
399 }
400 
nrf_802154_pib_csmaca_max_be_get(void)401 uint8_t nrf_802154_pib_csmaca_max_be_get(void)
402 {
403     return m_data.csmaca.max_be;
404 }
405 
nrf_802154_pib_csmaca_max_backoffs_set(uint8_t max_backoffs)406 void nrf_802154_pib_csmaca_max_backoffs_set(uint8_t max_backoffs)
407 {
408     m_data.csmaca.max_backoffs = max_backoffs;
409 }
410 
nrf_802154_pib_csmaca_max_backoffs_get(void)411 uint8_t nrf_802154_pib_csmaca_max_backoffs_get(void)
412 {
413     return m_data.csmaca.max_backoffs;
414 }
415 
416 #endif // NRF_802154_CSMA_CA_ENABLED
417 
418 #if NRF_802154_IFS_ENABLED
nrf_802154_pib_ifs_mode_get(void)419 nrf_802154_ifs_mode_t nrf_802154_pib_ifs_mode_get(void)
420 {
421     return m_data.ifs.mode;
422 }
423 
nrf_802154_pib_ifs_mode_set(nrf_802154_ifs_mode_t mode)424 bool nrf_802154_pib_ifs_mode_set(nrf_802154_ifs_mode_t mode)
425 {
426     switch (mode)
427     {
428         case NRF_802154_IFS_MODE_DISABLED:
429         case NRF_802154_IFS_MODE_MATCHING_ADDRESSES:
430         case NRF_802154_IFS_MODE_ALWAYS:
431             m_data.ifs.mode = mode;
432             return true;
433 
434         default:
435             return false;
436     }
437 }
438 
nrf_802154_pib_ifs_min_sifs_period_get(void)439 uint16_t nrf_802154_pib_ifs_min_sifs_period_get(void)
440 {
441     return m_data.ifs.min_sifs_period_us;
442 }
443 
nrf_802154_pib_ifs_min_sifs_period_set(uint16_t period)444 void nrf_802154_pib_ifs_min_sifs_period_set(uint16_t period)
445 {
446     NRF_802154_ASSERT(period >= TURNAROUND_TIME);
447 
448     m_data.ifs.min_sifs_period_us = period;
449 }
450 
nrf_802154_pib_ifs_min_lifs_period_get(void)451 uint16_t nrf_802154_pib_ifs_min_lifs_period_get(void)
452 {
453     return m_data.ifs.min_lifs_period_us;
454 }
455 
nrf_802154_pib_ifs_min_lifs_period_set(uint16_t period)456 void nrf_802154_pib_ifs_min_lifs_period_set(uint16_t period)
457 {
458     m_data.ifs.min_lifs_period_us = period;
459 }
460 
461 #endif // NRF_802154_IFS_ENABLED
462 
463 #if NRF_802154_TEST_MODES_ENABLED
nrf_802154_pib_test_mode_csmaca_backoff_get(void)464 nrf_802154_test_mode_csmaca_backoff_t nrf_802154_pib_test_mode_csmaca_backoff_get(void)
465 {
466     return m_data.test_modes.csmaca_backoff;
467 }
468 
nrf_802154_pib_test_mode_csmaca_backoff_set(nrf_802154_test_mode_csmaca_backoff_t value)469 void nrf_802154_pib_test_mode_csmaca_backoff_set(nrf_802154_test_mode_csmaca_backoff_t value)
470 {
471     m_data.test_modes.csmaca_backoff = value;
472 }
473 
474 #endif // NRF_802154_TEST_MODES_ENABLED
475