Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose more fields in beacon as pub #69

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
[package]
name = "ieee802154"
version = "0.6.1"
version = "0.7.0"
authors = [
"Erik Henriksson <[email protected]>",
"Hanno Braun <[email protected]>",
"Ryan Kurte <[email protected]>",
]
edition = "2018"
edition = "2021"

description = "Partial implementation of the IEEE 802.15.4 standard for low-rate wireless personal area networks"
documentation = "https://docs.rs/ieee802154"
Expand All @@ -17,11 +17,14 @@ categories = ["embedded", "network-programming", "no-std"]
keywords = ["WPAN"]

[features]
defmt = ["dep:defmt", "heapless/defmt-03"]
serde = ["dep:serde"]

[dependencies]
hash32 = "0.2.1"
hash32-derive = "0.1"
byte = "0.2.7"
heapless = "0.8.0"
defmt = { version = ">=0.2.0,<0.4", optional = true }

[dependencies.ccm]
Expand Down
158 changes: 72 additions & 86 deletions src/mac/beacon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use byte::{check_len, BytesExt, TryRead, TryWrite};
use core::convert::From;
use core::mem;

use crate::mac::{ExtendedAddress, ShortAddress};

Expand Down Expand Up @@ -40,11 +39,11 @@
}
}

/// Superframe order, amount of time during wich this superframe is active
/// Superframe order, amount of time during which this superframe is active
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum SuperframeOrder {
/// Ammount of time that the superframe is active
/// Amount of time that the superframe is active
///
/// superframe duration = base superframe duration × (2 ^ superframe order)
SuperframeOrder(u8),
Expand Down Expand Up @@ -83,15 +82,15 @@
///
/// Beacon interval = BaseSuperframeDuration × (2 ^ BeaconOrder)
pub beacon_order: BeaconOrder,
/// Superframe order, amount of time during wich this superframe is active
/// Superframe order, amount of time during which this superframe is active
pub superframe_order: SuperframeOrder,
/// final contention access period slot used
pub final_cap_slot: u8,
/// Limit receiving of beacons for a period. Not used if beacon_order is OnDemand.
pub battery_life_extension: bool,
/// Frame sent by a coordinator
pub pan_coordinator: bool,
/// The coordinator acceppts associations to the PAN
/// The coordinator accepts associations to the PAN
pub association_permit: bool,
}

Expand All @@ -102,7 +101,7 @@
impl TryRead<'_> for SuperframeSpecification {
fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
let offset = &mut 0;
check_len(&bytes, 2)?;

Check warning on line 104 in src/mac/beacon.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler
let byte: u8 = bytes.read(offset)?;
let beacon_order = BeaconOrder::from(byte & 0x0f);
let superframe_order = SuperframeOrder::from((byte >> 4) & 0x0f);
Expand Down Expand Up @@ -130,8 +129,8 @@
impl TryWrite for SuperframeSpecification {
fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
let offset = &mut 0;
let bo = u8::from(self.beacon_order.clone());

Check warning on line 132 in src/mac/beacon.rs

View workflow job for this annotation

GitHub Actions / clippy

using `clone` on type `BeaconOrder` which implements the `Copy` trait
let so = u8::from(self.superframe_order.clone());

Check warning on line 133 in src/mac/beacon.rs

View workflow job for this annotation

GitHub Actions / clippy

using `clone` on type `SuperframeOrder` which implements the `Copy` trait
bytes.write(offset, (bo & 0x0f) | (so << 4))?;
let ble = if self.battery_life_extension {
BATTERY_LIFE_EXTENSION
Expand All @@ -156,7 +155,7 @@
/// Direction of data
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum Direction {
pub enum Direction {
/// Receive data
Receive,
/// Transmit data
Expand All @@ -168,18 +167,18 @@
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GuaranteedTimeSlotDescriptor {
/// Device short address used by this slot
short_address: ShortAddress,
pub short_address: ShortAddress,
/// Slot start
starting_slot: u8,
pub starting_slot: u8,
/// Slot length
length: u8,
pub length: u8,
/// Direction of the slot, either transmit or receive
direction: Direction,
pub direction: Direction,
}

impl GuaranteedTimeSlotDescriptor {
/// Create a new empty slot
pub fn new() -> Self {

Check warning on line 181 in src/mac/beacon.rs

View workflow job for this annotation

GitHub Actions / clippy

you should consider adding a `Default` implementation for `GuaranteedTimeSlotDescriptor`
GuaranteedTimeSlotDescriptor {
short_address: ShortAddress::broadcast(),
starting_slot: 0,
Expand All @@ -192,7 +191,7 @@
impl TryRead<'_> for GuaranteedTimeSlotDescriptor {
fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
let offset = &mut 0;
check_len(&bytes, 3)?;

Check warning on line 194 in src/mac/beacon.rs

View workflow job for this annotation

GitHub Actions / clippy

this expression creates a reference which is immediately dereferenced by the compiler
let short_address = bytes.read(offset)?;
let byte: u8 = bytes.read(offset)?;
let starting_slot = byte & 0x0f;
Expand Down Expand Up @@ -234,58 +233,56 @@
const PERMIT: u8 = 0b1000_0000;

/// Information of the guaranteed time slots (GTSs)
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct GuaranteedTimeSlotInformation {
/// Permit GTS
pub permit: bool,
slot_count: usize,
slots: [GuaranteedTimeSlotDescriptor; 7],
/// Time slot information
pub slots: heapless::Vec<GuaranteedTimeSlotDescriptor, 7>,
}

impl GuaranteedTimeSlotInformation {
/// Create a new empty GTS information
pub fn new() -> Self {

Check warning on line 247 in src/mac/beacon.rs

View workflow job for this annotation

GitHub Actions / clippy

you should consider adding a `Default` implementation for `GuaranteedTimeSlotInformation`
GuaranteedTimeSlotInformation {
permit: false,
slot_count: 0,
slots: [GuaranteedTimeSlotDescriptor::new(); 7],
slots: heapless::Vec::new(),
}
}

/// Get the slots as a slice
pub fn slots(&self) -> &[GuaranteedTimeSlotDescriptor] {
&self.slots[..self.slot_count]
self.slots.as_slice()
}
}

impl TryWrite for GuaranteedTimeSlotInformation {
fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
let offset = &mut 0;
assert!(self.slot_count <= 7);
assert!(self.slots.capacity() <= 7);
let permit = if self.permit { PERMIT } else { 0 };

let header = ((self.slot_count as u8) & COUNT_MASK) | permit;
let header = ((self.slots.len() as u8) & COUNT_MASK) | permit;
bytes.write(offset, header)?;

if self.slot_count > 0 {
if !self.slots.is_empty() {
let direction_mask = {
let mut dir = 0x01;
let mut direction_mask = 0u8;
for n in 0..self.slot_count {
let slot = self.slots[n];
for slot in &self.slots {
if slot.direction_transmit() {
direction_mask = direction_mask | dir;

Check warning on line 275 in src/mac/beacon.rs

View workflow job for this annotation

GitHub Actions / clippy

manual implementation of an assign operation
}
dir = dir << 1;

Check warning on line 277 in src/mac/beacon.rs

View workflow job for this annotation

GitHub Actions / clippy

manual implementation of an assign operation
}
direction_mask
};

bytes.write(offset, direction_mask)?;

for n in 0..self.slot_count {
bytes.write(offset, self.slots[n])?;
for slot in self.slots {
bytes.write(offset, slot)?;
}
}
Ok(*offset)
Expand All @@ -298,16 +295,12 @@
let byte: u8 = bytes.read(offset)?;
let slot_count = (byte & COUNT_MASK) as usize;
let permit = (byte & PERMIT) == PERMIT;
let mut slots = [GuaranteedTimeSlotDescriptor {
short_address: ShortAddress::broadcast(),
starting_slot: 0,
length: 0,
direction: Direction::Receive,
}; 7];
let mut slots = heapless::Vec::new();
assert!(slot_count <= slots.capacity());
if slot_count > 0 {
check_len(&bytes[*offset..], 2 + (3 * slot_count))?;
let mut direction_mask: u8 = bytes.read(offset)?;
for n in 0..slot_count {
for _ in 0..slot_count {
let mut slot: GuaranteedTimeSlotDescriptor =
bytes.read(offset)?;
let direction = if direction_mask & 0b1 == 0b1 {
Expand All @@ -316,18 +309,13 @@
Direction::Receive
};
slot.set_direction(direction);
direction_mask = direction_mask >> 1;

Check warning on line 312 in src/mac/beacon.rs

View workflow job for this annotation

GitHub Actions / clippy

manual implementation of an assign operation
slots[n] = slot;
slots.push(slot).expect(
"slot_count can never be larger than Vec::capacity",
);
}
}
Ok((
Self {
permit,
slot_count,
slots,
},
*offset,
))
Ok((Self { permit, slots }, *offset))
}
}

Expand All @@ -338,7 +326,7 @@
///
/// Addresses to devices that has pending messages with the coordinator
///
/// ```notrust
/// ```txt
/// +--------+-----------------+--------------------+
/// | Header | Short Addresses | Extended Addresses |
/// +--------+-----------------+--------------------+
Expand All @@ -347,64 +335,66 @@
///
/// ## Header
///
/// ```notrust
/// ```txt
/// +-------------+----------+----------------+----------+
/// | Short Count | Reserved | Extended Count | Reserved |
/// +-------------+----------+----------------+----------+
/// 0 - 2 3 4 - 6 7 bit
/// ```
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Default, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PendingAddress {
short_address_count: usize,
short_addresses: [ShortAddress; 7],
extended_address_count: usize,
extended_addresses: [ExtendedAddress; 7],
/// List of pending [`ShortAddress`]es
pub short_addresses: heapless::Vec<ShortAddress, 7>,
/// List of pending [`ExtendedAddress`]es
pub extended_addresses: heapless::Vec<ExtendedAddress, 7>,
}

impl PendingAddress {
/// Create a new empty PendingAddress struct
pub fn new() -> Self {
PendingAddress {
short_address_count: 0,
short_addresses: [ShortAddress::broadcast(); 7],
extended_address_count: 0,
extended_addresses: [ExtendedAddress::broadcast(); 7],
pub const fn new() -> Self {
Self {
short_addresses: heapless::Vec::new(),
extended_addresses: heapless::Vec::new(),
}
}

/// Get the short addresses
pub fn short_addresses(&self) -> &[ShortAddress] {
&self.short_addresses[..self.short_address_count]
self.short_addresses.as_slice()
}
/// Get the extended address
pub fn extended_addresses(&self) -> &[ExtendedAddress] {
&self.extended_addresses[..self.extended_address_count]
self.extended_addresses.as_slice()
}
}

impl TryRead<'_> for PendingAddress {
fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
let offset = &mut 0;
let ss = mem::size_of::<ShortAddress>();
let es = mem::size_of::<ExtendedAddress>();
let ss = size_of::<ShortAddress>();
let es = size_of::<ExtendedAddress>();
let byte: u8 = bytes.read(offset)?;
let sl = (byte & SHORT_MASK) as usize;
let el = ((byte & EXTENDED_MASK) >> 4) as usize;
check_len(&bytes[*offset..], (sl * ss) + (el * es))?;
let mut short_addresses = [ShortAddress::broadcast(); 7];
for n in 0..sl {
short_addresses[n] = bytes.read(offset)?;
let mut short_addresses = heapless::Vec::new();
assert!(sl <= short_addresses.capacity());
for _ in 0..sl {
short_addresses
.push(bytes.read(offset)?)
.expect("sl can never be larger than 7");
}
let mut extended_addresses = [ExtendedAddress::broadcast(); 7];
for n in 0..el {
extended_addresses[n] = bytes.read(offset)?;
let mut extended_addresses = heapless::Vec::new();
assert!(el <= extended_addresses.capacity());
for _ in 0..el {
extended_addresses
.push(bytes.read(offset)?)
.expect("el can never be larger than 7");
}
Ok((
Self {
short_address_count: sl,
short_addresses,
extended_address_count: el,
extended_addresses,
},
*offset,
Expand All @@ -415,31 +405,30 @@
impl TryWrite for PendingAddress {
fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
let offset = &mut 0;
assert!(self.short_address_count <= 7);
assert!(self.extended_address_count <= 7);
assert!(self.short_addresses.capacity() <= 7);
assert!(self.extended_addresses.capacity() <= 7);

let sl = self.short_address_count;
let el = self.extended_address_count;
let sl = self.short_addresses.len();
let el = self.extended_addresses.len();

let it_s_magic =
(((el as u8) << 4) & EXTENDED_MASK) | ((sl as u8) & SHORT_MASK); //FIXME give variable meaningful name
bytes.write(offset, it_s_magic)?;
// Combine list lengths into one field, see Table 45 of IEEE 802.15.4-2011
let combined_lengths =
(((el as u8) << 4) & EXTENDED_MASK) | ((sl as u8) & SHORT_MASK);
bytes.write(offset, combined_lengths)?;

for n in 0..self.short_address_count {
let addr = self.short_addresses[n];
for addr in self.short_addresses {
bytes.write(offset, addr)?;
}

for n in 0..self.extended_address_count {
let addr = self.extended_addresses[n];
for addr in self.extended_addresses {
bytes.write(offset, addr)?;
}
Ok(*offset)
}
}

/// Beacon frame
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Beacon {
/// Superframe specification
Expand Down Expand Up @@ -477,6 +466,7 @@
#[cfg(test)]
mod tests {
use super::*;
use heapless::Vec;

#[test]
fn decode_superframe_specification() {
Expand Down Expand Up @@ -632,29 +622,25 @@
association_permit: true,
};

let mut slots = [GuaranteedTimeSlotDescriptor::new(); 7];
slots[0] = GuaranteedTimeSlotDescriptor {
let slots = Vec::from_slice(&[GuaranteedTimeSlotDescriptor {
short_address: ShortAddress(0x1234),
starting_slot: 1,
length: 1,
direction: Direction::Transmit,
};
}])
.unwrap();

let guaranteed_time_slot_info = GuaranteedTimeSlotInformation {
permit: true,
slot_count: 1,
slots,
};

let mut short_addresses = [ShortAddress::broadcast(); 7];
short_addresses[0] = ShortAddress(0x7856);
let mut extended_addresses = [ExtendedAddress::broadcast(); 7];
extended_addresses[0] = ExtendedAddress(0xaec24a1c2116e260);
let short_addresses = Vec::from_slice(&[ShortAddress(0x7856)]).unwrap();
let extended_addresses =
Vec::from_slice(&[ExtendedAddress(0xaec24a1c2116e260)]).unwrap();

let pending_address = PendingAddress {
short_address_count: 1,
short_addresses,
extended_address_count: 1,
extended_addresses,
};

Expand Down
Loading
Loading