1 /*
2 * Copyright (c) 2017 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief IEEE 802.15.4 internal MAC and PHY Utils
10 *
11 * All references to the standard in this file cite IEEE 802.15.4-2020.
12 */
13
14 #ifndef __IEEE802154_UTILS_H__
15 #define __IEEE802154_UTILS_H__
16
17 #include <zephyr/net/ieee802154_radio.h>
18 #include <zephyr/sys/util_macro.h>
19
20 /**
21 * PHY utilities
22 */
23
ieee802154_radio_get_hw_capabilities(struct net_if * iface)24 static inline enum ieee802154_hw_caps ieee802154_radio_get_hw_capabilities(struct net_if *iface)
25 {
26 const struct ieee802154_radio_api *radio =
27 net_if_get_device(iface)->api;
28
29 if (!radio) {
30 return 0;
31 }
32
33 return radio->get_capabilities(net_if_get_device(iface));
34 }
35
ieee802154_radio_cca(struct net_if * iface)36 static inline int ieee802154_radio_cca(struct net_if *iface)
37 {
38 const struct ieee802154_radio_api *radio =
39 net_if_get_device(iface)->api;
40
41 if (!radio) {
42 return -ENOENT;
43 }
44
45 return radio->cca(net_if_get_device(iface));
46 }
47
ieee802154_radio_set_channel(struct net_if * iface,uint16_t channel)48 static inline int ieee802154_radio_set_channel(struct net_if *iface, uint16_t channel)
49 {
50 const struct ieee802154_radio_api *radio =
51 net_if_get_device(iface)->api;
52
53 if (!radio) {
54 return -ENOENT;
55 }
56
57 return radio->set_channel(net_if_get_device(iface), channel);
58 }
59
ieee802154_radio_set_tx_power(struct net_if * iface,int16_t dbm)60 static inline int ieee802154_radio_set_tx_power(struct net_if *iface, int16_t dbm)
61 {
62 const struct ieee802154_radio_api *radio =
63 net_if_get_device(iface)->api;
64
65 if (!radio) {
66 return -ENOENT;
67 }
68
69 return radio->set_txpower(net_if_get_device(iface), dbm);
70 }
71
ieee802154_radio_tx(struct net_if * iface,enum ieee802154_tx_mode mode,struct net_pkt * pkt,struct net_buf * buf)72 static inline int ieee802154_radio_tx(struct net_if *iface, enum ieee802154_tx_mode mode,
73 struct net_pkt *pkt, struct net_buf *buf)
74 {
75 const struct ieee802154_radio_api *radio =
76 net_if_get_device(iface)->api;
77
78 if (!radio) {
79 return -ENOENT;
80 }
81
82 return radio->tx(net_if_get_device(iface), mode, pkt, buf);
83 }
84
ieee802154_radio_start(struct net_if * iface)85 static inline int ieee802154_radio_start(struct net_if *iface)
86 {
87 const struct ieee802154_radio_api *radio =
88 net_if_get_device(iface)->api;
89
90 if (!radio) {
91 return -ENOENT;
92 }
93
94 return radio->start(net_if_get_device(iface));
95 }
96
ieee802154_radio_stop(struct net_if * iface)97 static inline int ieee802154_radio_stop(struct net_if *iface)
98 {
99 const struct ieee802154_radio_api *radio =
100 net_if_get_device(iface)->api;
101
102 if (!radio) {
103 return -ENOENT;
104 }
105
106 return radio->stop(net_if_get_device(iface));
107 }
108
ieee802154_radio_attr_get(struct net_if * iface,enum ieee802154_attr attr,struct ieee802154_attr_value * value)109 static inline int ieee802154_radio_attr_get(struct net_if *iface,
110 enum ieee802154_attr attr,
111 struct ieee802154_attr_value *value)
112 {
113 const struct ieee802154_radio_api *radio =
114 net_if_get_device(iface)->api;
115
116 if (!radio || !radio->attr_get) {
117 return -ENOENT;
118 }
119
120 return radio->attr_get(net_if_get_device(iface), attr, value);
121 }
122
123 /**
124 * Sets the radio drivers extended address filter.
125 *
126 * @param iface pointer to the IEEE 802.15.4 interface
127 * @param ieee_addr Pointer to an extended address in little endian byte order
128 */
ieee802154_radio_filter_ieee_addr(struct net_if * iface,uint8_t * ieee_addr)129 static inline void ieee802154_radio_filter_ieee_addr(struct net_if *iface, uint8_t *ieee_addr)
130 {
131 const struct ieee802154_radio_api *radio =
132 net_if_get_device(iface)->api;
133
134 if (radio && (radio->get_capabilities(net_if_get_device(iface)) &
135 IEEE802154_HW_FILTER)) {
136 struct ieee802154_filter filter;
137
138 filter.ieee_addr = ieee_addr;
139
140 if (radio->filter(net_if_get_device(iface), true,
141 IEEE802154_FILTER_TYPE_IEEE_ADDR,
142 &filter) != 0) {
143 NET_WARN("Could not apply IEEE address filter");
144 }
145 }
146 }
147
ieee802154_radio_filter_short_addr(struct net_if * iface,uint16_t short_addr)148 static inline void ieee802154_radio_filter_short_addr(struct net_if *iface, uint16_t short_addr)
149 {
150 const struct ieee802154_radio_api *radio =
151 net_if_get_device(iface)->api;
152
153 if (radio && (radio->get_capabilities(net_if_get_device(iface)) &
154 IEEE802154_HW_FILTER)) {
155 struct ieee802154_filter filter;
156
157 filter.short_addr = short_addr;
158
159 if (radio->filter(net_if_get_device(iface), true,
160 IEEE802154_FILTER_TYPE_SHORT_ADDR,
161 &filter) != 0) {
162 NET_WARN("Could not apply short address filter");
163 }
164 }
165 }
166
ieee802154_radio_filter_pan_id(struct net_if * iface,uint16_t pan_id)167 static inline void ieee802154_radio_filter_pan_id(struct net_if *iface, uint16_t pan_id)
168 {
169 const struct ieee802154_radio_api *radio =
170 net_if_get_device(iface)->api;
171
172 if (radio && (radio->get_capabilities(net_if_get_device(iface)) &
173 IEEE802154_HW_FILTER)) {
174 struct ieee802154_filter filter;
175
176 filter.pan_id = pan_id;
177
178 if (radio->filter(net_if_get_device(iface), true,
179 IEEE802154_FILTER_TYPE_PAN_ID,
180 &filter) != 0) {
181 NET_WARN("Could not apply PAN ID filter");
182 }
183 }
184 }
185
ieee802154_radio_filter_src_ieee_addr(struct net_if * iface,uint8_t * ieee_addr)186 static inline void ieee802154_radio_filter_src_ieee_addr(struct net_if *iface, uint8_t *ieee_addr)
187 {
188 const struct ieee802154_radio_api *radio =
189 net_if_get_device(iface)->api;
190
191 if (radio && (radio->get_capabilities(net_if_get_device(iface)) &
192 IEEE802154_HW_FILTER)) {
193 struct ieee802154_filter filter;
194
195 filter.ieee_addr = ieee_addr;
196
197 if (radio->filter(net_if_get_device(iface), true,
198 IEEE802154_FILTER_TYPE_SRC_IEEE_ADDR,
199 &filter) != 0) {
200 NET_WARN("Could not apply SRC IEEE address filter");
201 }
202 }
203 }
204
ieee802154_radio_filter_src_short_addr(struct net_if * iface,uint16_t short_addr)205 static inline void ieee802154_radio_filter_src_short_addr(struct net_if *iface, uint16_t short_addr)
206 {
207 const struct ieee802154_radio_api *radio =
208 net_if_get_device(iface)->api;
209
210 if (radio && (radio->get_capabilities(net_if_get_device(iface)) &
211 IEEE802154_HW_FILTER)) {
212 struct ieee802154_filter filter;
213
214 filter.short_addr = short_addr;
215
216 if (radio->filter(net_if_get_device(iface), true,
217 IEEE802154_FILTER_TYPE_SRC_SHORT_ADDR,
218 &filter) != 0) {
219 NET_WARN("Could not apply SRC short address filter");
220 }
221 }
222 }
223
ieee802154_radio_remove_src_ieee_addr(struct net_if * iface,uint8_t * ieee_addr)224 static inline void ieee802154_radio_remove_src_ieee_addr(struct net_if *iface, uint8_t *ieee_addr)
225 {
226 const struct ieee802154_radio_api *radio =
227 net_if_get_device(iface)->api;
228
229 if (radio && (radio->get_capabilities(net_if_get_device(iface)) &
230 IEEE802154_HW_FILTER)) {
231 struct ieee802154_filter filter;
232
233 filter.ieee_addr = ieee_addr;
234
235 if (radio->filter(net_if_get_device(iface), false,
236 IEEE802154_FILTER_TYPE_SRC_IEEE_ADDR,
237 &filter) != 0) {
238 NET_WARN("Could not remove SRC IEEE address filter");
239 }
240 }
241 }
242
ieee802154_radio_remove_src_short_addr(struct net_if * iface,uint16_t short_addr)243 static inline void ieee802154_radio_remove_src_short_addr(struct net_if *iface, uint16_t short_addr)
244 {
245 const struct ieee802154_radio_api *radio =
246 net_if_get_device(iface)->api;
247
248 if (radio && (radio->get_capabilities(net_if_get_device(iface)) &
249 IEEE802154_HW_FILTER)) {
250 struct ieee802154_filter filter;
251
252 filter.short_addr = short_addr;
253
254 if (radio->filter(net_if_get_device(iface), false,
255 IEEE802154_FILTER_TYPE_SRC_SHORT_ADDR,
256 &filter) != 0) {
257 NET_WARN("Could not remove SRC short address filter");
258 }
259 }
260 }
261
ieee802154_radio_remove_pan_id(struct net_if * iface,uint16_t pan_id)262 static inline void ieee802154_radio_remove_pan_id(struct net_if *iface, uint16_t pan_id)
263 {
264 const struct ieee802154_radio_api *radio =
265 net_if_get_device(iface)->api;
266
267 if (radio && (radio->get_capabilities(net_if_get_device(iface)) &
268 IEEE802154_HW_FILTER)) {
269 struct ieee802154_filter filter;
270
271 filter.pan_id = pan_id;
272
273 if (radio->filter(net_if_get_device(iface), false,
274 IEEE802154_FILTER_TYPE_PAN_ID,
275 &filter) != 0) {
276 NET_WARN("Could not remove PAN ID filter");
277 }
278 }
279 }
280
281
282 /**
283 * MAC utilities
284 *
285 * @note While MAC utilities may refer to PHY utilities, the inverse is not
286 * true.
287 */
288
289 /**
290 * @brief Retrieves the currently selected channel page from the driver (see
291 * phyCurrentPage, section 11.3, table 11-2). This is PHY-related information
292 * not configured by L2 but directly provided by the driver.
293 *
294 * @param iface pointer to the IEEE 802.15.4 interface
295 *
296 * @returns The currently active channel page.
297 * @retval 0 if an error occurred
298 */
299 static inline enum ieee802154_phy_channel_page
ieee802154_radio_current_channel_page(struct net_if * iface)300 ieee802154_radio_current_channel_page(struct net_if *iface)
301 {
302 struct ieee802154_attr_value value;
303
304 /* Currently we assume that drivers are statically configured to only
305 * support a single channel page. Once drivers need to switch channels at
306 * runtime this can be changed here w/o affecting clients.
307 */
308 if (ieee802154_radio_attr_get(iface, IEEE802154_ATTR_PHY_SUPPORTED_CHANNEL_PAGES, &value)) {
309 return 0;
310 }
311
312 return value.phy_supported_channel_pages;
313 }
314
315 /**
316 * @brief Calculates a multiple of the PHY's symbol period in nanoseconds.
317 *
318 * @details The PHY's symbol period depends on the interface's current PHY
319 * configuration which usually can be derived from the currently chosen channel
320 * page and channel (phyCurrentPage and phyCurrentChannel, section 11.3, table
321 * 11-2).
322 *
323 * To calculate the symbol period of HRP UWB PHYs, the nominal pulse repetition
324 * frequency (PRF) is required. HRP UWB drivers will be expected to expose the
325 * supported norminal PRF rates as a driver attribute. Existing drivers do not
326 * allow for runtime switching of the PRF, so currently the PRF is considered to
327 * be read-only and known.
328 *
329 * TODO: Add an UwbPrf argument once drivers need to support PRF switching at
330 * runtime.
331 *
332 * @note We do not expose an API for a single symbol period to avoid having to
333 * deal with floats for PHYs that don't require it while maintaining precision
334 * in calculations where PHYs operate at symbol periods involving fractions of
335 * nanoseconds.
336 *
337 * @param iface pointer to the IEEE 802.15.4 interface
338 * @param channel The channel for which the symbol period is to be calculated.
339 * @param multiplier The factor by which the symbol period is to be multiplied.
340 *
341 * @returns A multiple of the symbol period for the given interface with
342 * nanosecond precision.
343 * @retval 0 if an error occurred.
344 */
ieee802154_radio_get_multiple_of_symbol_period(struct net_if * iface,uint16_t channel,uint16_t multiplier)345 static inline net_time_t ieee802154_radio_get_multiple_of_symbol_period(struct net_if *iface,
346 uint16_t channel,
347 uint16_t multiplier)
348 {
349 /* To keep things simple we only calculate symbol periods for channel
350 * pages that are implemented by existing in-tree drivers. Add additional
351 * channel pages as required.
352 */
353 switch (ieee802154_radio_current_channel_page(iface)) {
354 case IEEE802154_ATTR_PHY_CHANNEL_PAGE_ZERO_OQPSK_2450_BPSK_868_915:
355 return (channel >= 11
356 ? IEEE802154_PHY_OQPSK_780_TO_2450MHZ_SYMBOL_PERIOD_NS
357 : (channel > 0 ? IEEE802154_PHY_BPSK_915MHZ_SYMBOL_PERIOD_NS
358 : IEEE802154_PHY_BPSK_868MHZ_SYMBOL_PERIOD_NS)) *
359 multiplier;
360
361 case IEEE802154_ATTR_PHY_CHANNEL_PAGE_TWO_OQPSK_868_915:
362 return (channel > 0 ? IEEE802154_PHY_OQPSK_780_TO_2450MHZ_SYMBOL_PERIOD_NS
363 : IEEE802154_PHY_OQPSK_868MHZ_SYMBOL_PERIOD_NS) *
364 multiplier;
365
366 case IEEE802154_ATTR_PHY_CHANNEL_PAGE_FOUR_HRP_UWB: {
367 struct ieee802154_attr_value value;
368
369 /* Currently we assume that drivers are statically configured to
370 * only support a single PRF. Once drivers support switching PRF
371 * at runtime an UWB PRF argument needs to be added to this
372 * function which then must be validated against the set of
373 * supported PRFs.
374 */
375 if (ieee802154_radio_attr_get(iface, IEEE802154_ATTR_PHY_HRP_UWB_SUPPORTED_PRFS,
376 &value)) {
377 return 0;
378 }
379
380 switch (value.phy_hrp_uwb_supported_nominal_prfs) {
381 case IEEE802154_PHY_HRP_UWB_NOMINAL_4_M:
382 return IEEE802154_PHY_HRP_UWB_PRF4_TPSYM_SYMBOL_PERIOD_NS * multiplier;
383
384 case IEEE802154_PHY_HRP_UWB_NOMINAL_16_M:
385 return IEEE802154_PHY_HRP_UWB_PRF16_TPSYM_SYMBOL_PERIOD_NS * multiplier;
386
387 case IEEE802154_PHY_HRP_UWB_NOMINAL_64_M:
388 return IEEE802154_PHY_HRP_UWB_PRF64_TPSYM_SYMBOL_PERIOD_NS * multiplier;
389
390 case IEEE802154_PHY_HRP_UWB_NOMINAL_64_M_BPRF:
391 case IEEE802154_PHY_HRP_UWB_NOMINAL_128_M_HPRF:
392 case IEEE802154_PHY_HRP_UWB_NOMINAL_256_M_HPRF:
393 return IEEE802154_PHY_HRP_UWB_ERDEV_TPSYM_SYMBOL_PERIOD_NS * multiplier;
394
395 default:
396 CODE_UNREACHABLE;
397 }
398 }
399
400 case IEEE802154_ATTR_PHY_CHANNEL_PAGE_FIVE_OQPSK_780:
401 return IEEE802154_PHY_OQPSK_780_TO_2450MHZ_SYMBOL_PERIOD_NS * multiplier;
402
403 case IEEE802154_ATTR_PHY_CHANNEL_PAGE_NINE_SUN_PREDEFINED:
404 /* Current SUN FSK drivers only implement legacy IEEE 802.15.4g
405 * 863 MHz (Europe) and 915 MHz (US ISM) bands, see IEEE
406 * 802.15.4g, section 5.1, table 0. Once more bands are required
407 * we need to request the currently active frequency band from
408 * the driver.
409 */
410 return IEEE802154_PHY_SUN_FSK_863MHZ_915MHZ_SYMBOL_PERIOD_NS * multiplier;
411
412 default:
413 CODE_UNREACHABLE;
414 }
415 }
416
417 /**
418 * @brief Calculates the PHY's turnaround time for the current channel page (see
419 * section 11.3, table 11-1, aTurnaroundTime) in PHY symbols.
420 *
421 * @details The PHY's turnaround time is used to calculate - among other
422 * parameters - the TX-to-RX turnaround time (see section 10.2.2) and the
423 * RX-to-TX turnaround time (see section 10.2.3).
424 *
425 * @param iface pointer to the IEEE 802.15.4 interface
426 *
427 * @returns The turnaround time for the given interface in symbols.
428 * @retval 0 if an error occurred.
429 */
ieee802154_radio_get_a_turnaround_time(struct net_if * iface)430 static inline uint32_t ieee802154_radio_get_a_turnaround_time(struct net_if *iface)
431 {
432 enum ieee802154_phy_channel_page channel_page =
433 ieee802154_radio_current_channel_page(iface);
434
435 if (!channel_page) {
436 return 0;
437 }
438
439 /* Section 11.3, table 11-1, aTurnaroundTime: "For the SUN [...] PHYs,
440 * the value is 1 ms expressed in symbol periods, rounded up to the next
441 * integer number of symbol periods using the ceiling() function. [...]
442 * The value is 12 [symbol periods] for all other PHYs.
443 */
444
445 if (channel_page == IEEE802154_ATTR_PHY_CHANNEL_PAGE_NINE_SUN_PREDEFINED) {
446 /* Current SUN FSK drivers only implement legacy IEEE 802.15.4g
447 * 863 MHz (Europe) and 915 MHz (US ISM) bands, see IEEE
448 * 802.15.4g, section 5.1, table 0. Once more bands are required
449 * we need to request the currently active frequency band from
450 * the driver.
451 */
452 return IEEE802154_PHY_A_TURNAROUND_TIME_1MS(
453 IEEE802154_PHY_SUN_FSK_863MHZ_915MHZ_SYMBOL_PERIOD_NS);
454 }
455
456 return IEEE802154_PHY_A_TURNAROUND_TIME_DEFAULT;
457 }
458
459 /**
460 * @brief Verify if the given channel lies within the allowed range of available
461 * channels of the driver's currently selected channel page.
462 *
463 * @param iface pointer to the IEEE 802.15.4 interface
464 * @param channel The channel to verify or IEEE802154_NO_CHANNEL
465 *
466 * @returns true if the channel is available, false otherwise
467 */
468 bool ieee802154_radio_verify_channel(struct net_if *iface, uint16_t channel);
469
470 /**
471 * @brief Counts all available channels of the driver's currently selected
472 * channel page.
473 *
474 * @param iface pointer to the IEEE 802.15.4 interface
475 *
476 * @returns The number of available channels.
477 */
478 uint16_t ieee802154_radio_number_of_channels(struct net_if *iface);
479
480 /**
481 * @brief Calculates the MAC's superframe duration (see section 8.4.2,
482 * table 8-93, aBaseSuperframeDuration) in microseconds.
483 *
484 * @details The number of symbols forming a superframe when the superframe order
485 * is equal to zero.
486 *
487 * @param iface pointer to the IEEE 802.15.4 interface
488 *
489 * @returns The base superframe duration for the given interface in microseconds.
490 */
ieee802154_get_a_base_superframe_duration(struct net_if * iface)491 static inline uint32_t ieee802154_get_a_base_superframe_duration(struct net_if *iface)
492 {
493 struct ieee802154_context *ctx = net_if_l2_data(iface);
494
495 return ieee802154_radio_get_multiple_of_symbol_period(
496 iface, ctx->channel, IEEE802154_MAC_A_BASE_SUPERFRAME_DURATION) /
497 NSEC_PER_USEC;
498 }
499
500 /**
501 * @brief Retrieves macResponseWaitTime, see section 8.4.3.1, table 8-94,
502 * converted to microseconds.
503 *
504 * @details The maximum time, in multiples of aBaseSuperframeDuration converted
505 * to microseconds, a device shall wait for a response command to be available
506 * following a request command.
507 *
508 * macResponseWaitTime is a network-topology-dependent parameter and may be set
509 * to match the specific requirements of the network that a device is operating
510 * on.
511 *
512 * @note Currently this parameter is read-only and uses the specified default of 32.
513 *
514 * @param iface pointer to the IEEE 802.15.4 interface
515 *
516 * @returns The response wait time for the given interface in microseconds.
517 */
ieee802154_get_response_wait_time_us(struct net_if * iface)518 static inline uint32_t ieee802154_get_response_wait_time_us(struct net_if *iface)
519 {
520 /* TODO: Make this parameter configurable. */
521 return IEEE802154_MAC_RESPONSE_WAIT_TIME_DEFAULT *
522 ieee802154_get_a_base_superframe_duration(iface);
523 }
524
525 #endif /* __IEEE802154_UTILS_H__ */
526