Add the esp-ieee802154 package to the repository (#1554)
* Add the `esp-ieee802154` package to the repo * Add examples for `esp-ieee802154` package
This commit is contained in:
parent
3c05759556
commit
8a1df42309
@ -7,6 +7,7 @@ exclude = [
|
|||||||
"esp-hal",
|
"esp-hal",
|
||||||
"esp-hal-procmacros",
|
"esp-hal-procmacros",
|
||||||
"esp-hal-smartled",
|
"esp-hal-smartled",
|
||||||
|
"esp-ieee802154",
|
||||||
"esp-lp-hal",
|
"esp-lp-hal",
|
||||||
"esp-metadata",
|
"esp-metadata",
|
||||||
"esp-riscv-rt",
|
"esp-riscv-rt",
|
||||||
|
|||||||
31
esp-ieee802154/Cargo.toml
Normal file
31
esp-ieee802154/Cargo.toml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
[package]
|
||||||
|
name = "esp-ieee802154"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
rust-version = "1.76.0"
|
||||||
|
description = "Low-level IEEE 802.15.4 driver for the ESP32-C6 and ESP32-H2"
|
||||||
|
repository = "https://github.com/esp-rs/esp-hal"
|
||||||
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
default-target = "riscv32imac-unknown-none-elf"
|
||||||
|
features = ["esp32c6"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
bench = false
|
||||||
|
test = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
byte = "0.2.7"
|
||||||
|
critical-section = "1.1.2"
|
||||||
|
esp-hal = { version = "0.17.0", path = "../esp-hal" }
|
||||||
|
esp-wifi-sys = { git = "https://github.com/esp-rs/esp-wifi", rev = "2ceb4b3" }
|
||||||
|
heapless = "0.8.0"
|
||||||
|
ieee802154 = "0.6.1"
|
||||||
|
log = "0.4.21"
|
||||||
|
vcell = "0.1.3"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
esp32c6 = ["esp-hal/esp32c6", "esp-wifi-sys/esp32c6"]
|
||||||
|
esp32h2 = ["esp-hal/esp32h2", "esp-wifi-sys/esp32h2"]
|
||||||
35
esp-ieee802154/README.md
Normal file
35
esp-ieee802154/README.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# esp-ieee802154
|
||||||
|
|
||||||
|
[](https://crates.io/crates/esp-ieee802154)
|
||||||
|
[](https://docs.rs/esp-ieee802154)
|
||||||
|

|
||||||
|

|
||||||
|
[](https://matrix.to/#/#esp-rs:matrix.org)
|
||||||
|
|
||||||
|
Low-level [IEEE 802.15.4] driver for the ESP32-C6 and ESP32-H2.
|
||||||
|
|
||||||
|
Implements the PHY/MAC layers of the IEEE802.15.4 protocol stack, and supports sending and receiving of raw frames.
|
||||||
|
|
||||||
|
[IEEE 802.15.4]: https://en.wikipedia.org/wiki/IEEE_802.15.4
|
||||||
|
|
||||||
|
## [Documentation](https://docs.rs/crate/esp-ieee802154)
|
||||||
|
|
||||||
|
## Minimum Supported Rust Version (MSRV)
|
||||||
|
|
||||||
|
This crate is guaranteed to compile on stable Rust 1.76 and up. It _might_
|
||||||
|
compile with older versions but that may change in any new patch release.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Licensed under either of:
|
||||||
|
|
||||||
|
- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
||||||
|
- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
at your option.
|
||||||
|
|
||||||
|
### Contribution
|
||||||
|
|
||||||
|
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in
|
||||||
|
the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without
|
||||||
|
any additional terms or conditions.
|
||||||
6
esp-ieee802154/build.rs
Normal file
6
esp-ieee802154/build.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
use std::{env, path::PathBuf};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||||
|
println!("cargo:rustc-link-search={}", out.display());
|
||||||
|
}
|
||||||
130
esp-ieee802154/src/compat/mod.rs
Normal file
130
esp-ieee802154/src/compat/mod.rs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
use core::{ffi::VaListImpl, fmt::Write};
|
||||||
|
|
||||||
|
use log::info;
|
||||||
|
|
||||||
|
use self::str_buf::StrBuf;
|
||||||
|
|
||||||
|
mod str_buf;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn phy_printf(format: *const u8, args: ...) {
|
||||||
|
syslog(format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn rtc_printf(format: *const u8, args: ...) {
|
||||||
|
syslog(format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn coexist_printf(format: *const u8, args: ...) {
|
||||||
|
syslog(format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe extern "C" fn syslog(format: *const u8, args: VaListImpl) {
|
||||||
|
let mut buf = [0u8; 512];
|
||||||
|
vsnprintf(&mut buf as *mut u8, 511, format, args);
|
||||||
|
let res_str = StrBuf::from(&buf as *const u8);
|
||||||
|
info!("{}", res_str.as_str_ref());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn vsnprintf(
|
||||||
|
dst: *mut u8,
|
||||||
|
_n: u32,
|
||||||
|
format: *const u8,
|
||||||
|
mut args: VaListImpl,
|
||||||
|
) -> i32 {
|
||||||
|
let fmt_str_ptr = format;
|
||||||
|
|
||||||
|
let mut res_str = StrBuf::new();
|
||||||
|
|
||||||
|
let strbuf = StrBuf::from(fmt_str_ptr);
|
||||||
|
let s = strbuf.as_str_ref();
|
||||||
|
|
||||||
|
let mut format_char = ' ';
|
||||||
|
let mut is_long = false;
|
||||||
|
let mut found = false;
|
||||||
|
for c in s.chars() {
|
||||||
|
if !found {
|
||||||
|
if c == '%' {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
res_str.append_char(c);
|
||||||
|
}
|
||||||
|
} else if c.is_numeric() || c == '-' || c == 'l' {
|
||||||
|
if c == 'l' {
|
||||||
|
is_long = true;
|
||||||
|
}
|
||||||
|
// ignore
|
||||||
|
} else {
|
||||||
|
// a format char
|
||||||
|
format_char = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
if found && format_char != ' ' {
|
||||||
|
// have to format an arg
|
||||||
|
match format_char {
|
||||||
|
'd' => {
|
||||||
|
if is_long {
|
||||||
|
let v = args.arg::<i64>();
|
||||||
|
write!(res_str, "{}", v).ok();
|
||||||
|
} else {
|
||||||
|
let v = args.arg::<i32>();
|
||||||
|
write!(res_str, "{}", v).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
'u' => {
|
||||||
|
let v = args.arg::<u32>();
|
||||||
|
write!(res_str, "{}", v).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
'p' => {
|
||||||
|
let v = args.arg::<u32>();
|
||||||
|
write!(res_str, "0x{:x}", v).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
'X' => {
|
||||||
|
let v = args.arg::<u32>();
|
||||||
|
write!(res_str, "{:02x}", (v & 0xff000000) >> 24).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
'x' => {
|
||||||
|
let v = args.arg::<u32>();
|
||||||
|
write!(res_str, "{:02x}", v).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
's' => {
|
||||||
|
let v = args.arg::<u32>() as *const u8;
|
||||||
|
let vbuf = StrBuf::from(v);
|
||||||
|
write!(res_str, "{}", vbuf.as_str_ref()).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
'c' => {
|
||||||
|
let v = args.arg::<u8>();
|
||||||
|
if v != 0 {
|
||||||
|
write!(res_str, "{}", v as char).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
write!(res_str, "<UNKNOWN{}>", format_char).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
format_char = ' ';
|
||||||
|
found = false;
|
||||||
|
is_long = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut idx = 0;
|
||||||
|
res_str.as_str_ref().chars().for_each(|c| {
|
||||||
|
*(dst.offset(idx)) = c as u8;
|
||||||
|
idx += 1;
|
||||||
|
});
|
||||||
|
*(dst.offset(idx)) = 0;
|
||||||
|
|
||||||
|
idx as i32
|
||||||
|
}
|
||||||
58
esp-ieee802154/src/compat/str_buf.rs
Normal file
58
esp-ieee802154/src/compat/str_buf.rs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
pub struct StrBuf {
|
||||||
|
buffer: [u8; 512],
|
||||||
|
len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StrBuf {
|
||||||
|
pub fn new() -> StrBuf {
|
||||||
|
StrBuf {
|
||||||
|
buffer: [0u8; 512],
|
||||||
|
len: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn from(c_str: *const u8) -> StrBuf {
|
||||||
|
let mut res = StrBuf {
|
||||||
|
buffer: [0u8; 512],
|
||||||
|
len: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut idx: usize = 0;
|
||||||
|
while *(c_str.add(idx)) != 0 {
|
||||||
|
res.buffer[idx] = *(c_str.add(idx));
|
||||||
|
idx += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.len = idx;
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append(&mut self, s: &str) {
|
||||||
|
let mut idx: usize = self.len;
|
||||||
|
s.chars().for_each(|c| {
|
||||||
|
self.buffer[idx] = c as u8;
|
||||||
|
idx += 1;
|
||||||
|
});
|
||||||
|
self.len = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append_char(&mut self, c: char) {
|
||||||
|
let mut idx: usize = self.len;
|
||||||
|
self.buffer[idx] = c as u8;
|
||||||
|
idx += 1;
|
||||||
|
self.len = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn as_str_ref(&self) -> &str {
|
||||||
|
core::str::from_utf8_unchecked(&self.buffer[..self.len])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Write for StrBuf {
|
||||||
|
fn write_str(&mut self, s: &str) -> Result<(), core::fmt::Error> {
|
||||||
|
self.append(s);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
45
esp-ieee802154/src/frame.rs
Normal file
45
esp-ieee802154/src/frame.rs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
use heapless::Vec;
|
||||||
|
use ieee802154::mac::{FrameContent, Header};
|
||||||
|
|
||||||
|
pub(crate) const FRAME_SIZE: usize = 129;
|
||||||
|
pub(crate) const FRAME_VERSION_1: u8 = 0x10; // IEEE 802.15.4 - 2006 & 2011
|
||||||
|
pub(crate) const FRAME_VERSION_2: u8 = 0x20; // IEEE 802.15.4 - 2015
|
||||||
|
|
||||||
|
const FRAME_AR_OFFSET: usize = 1;
|
||||||
|
const FRAME_AR_BIT: u8 = 0x20;
|
||||||
|
const FRAME_VERSION_OFFSET: usize = 2;
|
||||||
|
const FRAME_VERSION_MASK: u8 = 0x30;
|
||||||
|
|
||||||
|
/// IEEE 802.15.4 MAC frame
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Frame {
|
||||||
|
/// Header
|
||||||
|
pub header: Header,
|
||||||
|
/// Content
|
||||||
|
pub content: FrameContent,
|
||||||
|
/// Payload
|
||||||
|
pub payload: Vec<u8, FRAME_SIZE>,
|
||||||
|
/// This is a 2-byte CRC checksum
|
||||||
|
pub footer: [u8; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IEEE 802.15.4 MAC frame which has been received
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ReceivedFrame {
|
||||||
|
/// Frame
|
||||||
|
pub frame: Frame,
|
||||||
|
/// Receiver channel
|
||||||
|
pub channel: u8,
|
||||||
|
/// Received Signal Strength Indicator (RSSI)
|
||||||
|
pub rssi: i8,
|
||||||
|
/// Link Quality Indication (LQI)
|
||||||
|
pub lqi: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn frame_is_ack_required(frame: &[u8]) -> bool {
|
||||||
|
(frame[FRAME_AR_OFFSET] & FRAME_AR_BIT) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn frame_get_version(frame: &[u8]) -> u8 {
|
||||||
|
frame[FRAME_VERSION_OFFSET] & FRAME_VERSION_MASK
|
||||||
|
}
|
||||||
437
esp-ieee802154/src/hal.rs
Normal file
437
esp-ieee802154/src/hal.rs
Normal file
@ -0,0 +1,437 @@
|
|||||||
|
use core::ops::{BitAnd, BitOr};
|
||||||
|
|
||||||
|
use esp_hal::peripherals::IEEE802154;
|
||||||
|
|
||||||
|
use crate::pib::CcaMode;
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub(crate) enum Event {
|
||||||
|
TxDone = 1 << 0,
|
||||||
|
RxDone = 1 << 1,
|
||||||
|
AckTxDone = 1 << 2,
|
||||||
|
AckRxDone = 1 << 3,
|
||||||
|
RxAbort = 1 << 4,
|
||||||
|
TxAbort = 1 << 5,
|
||||||
|
EdDone = 1 << 6,
|
||||||
|
Timer0Overflow = 1 << 8,
|
||||||
|
Timer1Overflow = 1 << 9,
|
||||||
|
ClockCountMatch = 1 << 10,
|
||||||
|
TxSfdDone = 1 << 11,
|
||||||
|
RxSfdDone = 1 << 12,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Event {
|
||||||
|
pub(crate) fn mask() -> u16 {
|
||||||
|
0x0000_1FFF
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitAnd<Event> for u16 {
|
||||||
|
type Output = u16;
|
||||||
|
|
||||||
|
fn bitand(self, rhs: Event) -> Self::Output {
|
||||||
|
self & rhs as u16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr for Event {
|
||||||
|
type Output = u16;
|
||||||
|
|
||||||
|
fn bitor(self, rhs: Self) -> Self::Output {
|
||||||
|
self as u16 | rhs as u16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr<Event> for u16 {
|
||||||
|
type Output = u16;
|
||||||
|
|
||||||
|
fn bitor(self, rhs: Event) -> Self::Output {
|
||||||
|
self | rhs as u16
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub(crate) enum TxAbortReason {
|
||||||
|
RxAckStop = 1,
|
||||||
|
RxAckSfdTimeout = 2,
|
||||||
|
RxAckCrcError = 3,
|
||||||
|
RxAckInvalidLen = 4,
|
||||||
|
RxAckFilterFail = 5,
|
||||||
|
RxAckNoRss = 6,
|
||||||
|
RxAckCoexBreak = 7,
|
||||||
|
RxAckTypeNotAck = 8,
|
||||||
|
RxAckRestart = 9,
|
||||||
|
RxAckTimeout = 16,
|
||||||
|
TxStop = 17,
|
||||||
|
TxCoexBreak = 18,
|
||||||
|
TxSecurityError = 19,
|
||||||
|
CcaFailed = 24,
|
||||||
|
CcaBusy = 25,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxAbortReason {
|
||||||
|
pub fn bit(&self) -> u32 {
|
||||||
|
1 << (*self as u32 - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr for TxAbortReason {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
fn bitor(self, rhs: Self) -> Self::Output {
|
||||||
|
self.bit() | rhs.bit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr<TxAbortReason> for u32 {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
fn bitor(self, rhs: TxAbortReason) -> Self::Output {
|
||||||
|
self | rhs.bit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub(crate) enum RxAbortReason {
|
||||||
|
RxStop = 1,
|
||||||
|
SfdTimeout = 2,
|
||||||
|
CrcError = 3,
|
||||||
|
InvalidLen = 4,
|
||||||
|
FilterFail = 5,
|
||||||
|
NoRss = 6,
|
||||||
|
CoexBreak = 7,
|
||||||
|
UnexpectedAck = 8,
|
||||||
|
RxRestart = 9,
|
||||||
|
TxAckTimeout = 16,
|
||||||
|
TxAckStop = 17,
|
||||||
|
TxAckCoexBreak = 18,
|
||||||
|
EnhackSecurityError = 19,
|
||||||
|
EdAbort = 24,
|
||||||
|
EdStop = 25,
|
||||||
|
EdCoexReject = 26,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RxAbortReason {
|
||||||
|
pub fn bit(&self) -> u32 {
|
||||||
|
1 << (*self as u32 - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr for RxAbortReason {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
fn bitor(self, rhs: Self) -> Self::Output {
|
||||||
|
self.bit() | rhs.bit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BitOr<RxAbortReason> for u32 {
|
||||||
|
type Output = u32;
|
||||||
|
|
||||||
|
fn bitor(self, rhs: RxAbortReason) -> Self::Output {
|
||||||
|
self | rhs.bit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub(crate) enum EdSampleMode {
|
||||||
|
Max = 0,
|
||||||
|
Avg = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub(crate) enum Command {
|
||||||
|
TxStart = 0x41,
|
||||||
|
RxStart = 0x42,
|
||||||
|
CcaTxStart = 0x43,
|
||||||
|
EdStart = 0x44,
|
||||||
|
Stop = 0x45,
|
||||||
|
DtmTxStart = 0x46,
|
||||||
|
DtmRxStart = 0x47,
|
||||||
|
DtmStop = 0x48,
|
||||||
|
Timer0Start = 0x4C,
|
||||||
|
Timer0Stop = 0x4D,
|
||||||
|
Timer1Start = 0x4E,
|
||||||
|
Timer1Stop = 0x4F,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub(crate) enum MultipanIndex {
|
||||||
|
Multipan0 = 0,
|
||||||
|
Multipan1 = 1,
|
||||||
|
Multipan2 = 2,
|
||||||
|
Multipan3 = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<usize> for MultipanIndex {
|
||||||
|
fn from(value: usize) -> Self {
|
||||||
|
match value {
|
||||||
|
0 => MultipanIndex::Multipan0,
|
||||||
|
1 => MultipanIndex::Multipan1,
|
||||||
|
2 => MultipanIndex::Multipan2,
|
||||||
|
3 => MultipanIndex::Multipan3,
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn mac_date() -> u32 {
|
||||||
|
unsafe { &*IEEE802154::PTR }.mac_date().read().bits()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_rx_on_delay(delay: u16) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.rxon_delay()
|
||||||
|
.modify(|_, w| unsafe { w.rxon_delay().bits(delay) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn enable_events(events: u16) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.event_en()
|
||||||
|
.modify(|r, w| unsafe { w.event_en().bits(r.event_en().bits() | events) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn disable_events(events: u16) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.event_en()
|
||||||
|
.modify(|r, w| unsafe { w.event_en().bits(r.event_en().bits() & !events) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn enable_tx_abort_events(events: u32) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.tx_abort_interrupt_control()
|
||||||
|
.modify(|r, w| unsafe {
|
||||||
|
w.tx_abort_interrupt_control()
|
||||||
|
.bits(r.tx_abort_interrupt_control().bits() | events)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn enable_rx_abort_events(events: u32) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.rx_abort_intr_ctrl()
|
||||||
|
.modify(|r, w| unsafe {
|
||||||
|
w.rx_abort_intr_ctrl()
|
||||||
|
.bits(r.rx_abort_intr_ctrl().bits() | events)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_ed_sample_mode(ed_sample_mode: EdSampleMode) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.ed_scan_cfg()
|
||||||
|
.modify(|_, w| unsafe { w.ed_sample_mode().bits(ed_sample_mode as u8) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_tx_addr(addr: *const u8) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.txdma_addr()
|
||||||
|
.modify(|_, w| unsafe { w.txdma_addr().bits(addr as u32) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_cmd(cmd: Command) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.command()
|
||||||
|
.modify(|_, w| unsafe { w.opcode().bits(cmd as u8) })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_freq(freq: u8) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.channel()
|
||||||
|
.modify(|_, w| unsafe { w.hop().bits(freq) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn get_freq() -> u8 {
|
||||||
|
unsafe { &*IEEE802154::PTR }.channel().read().hop().bits()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_power(power: u8) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.tx_power()
|
||||||
|
.modify(|_, w| unsafe { w.tx_power().bits(power) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_multipan_enable_mask(mask: u8) {
|
||||||
|
// apparently the REGS are garbage and the struct is right?
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.ctrl_cfg()
|
||||||
|
.modify(|r, w| unsafe { w.bits(r.bits() & !(0b1111 << 29) | (mask as u32) << 29) })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_multipan_panid(index: MultipanIndex, panid: u16) {
|
||||||
|
unsafe {
|
||||||
|
let pan_id = (&*IEEE802154::PTR)
|
||||||
|
.inf0_pan_id()
|
||||||
|
.as_ptr()
|
||||||
|
.offset(4 * index as isize);
|
||||||
|
pan_id.write_volatile(panid as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_multipan_short_addr(index: MultipanIndex, value: u16) {
|
||||||
|
unsafe {
|
||||||
|
let short_addr = (&*IEEE802154::PTR)
|
||||||
|
.inf0_short_addr()
|
||||||
|
.as_ptr()
|
||||||
|
.offset(4 * index as isize);
|
||||||
|
short_addr.write_volatile(value as u32);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_multipan_ext_addr(index: MultipanIndex, ext_addr: *const u8) {
|
||||||
|
unsafe {
|
||||||
|
let mut ext_addr_ptr = (&*IEEE802154::PTR)
|
||||||
|
.inf0_extend_addr0()
|
||||||
|
.as_ptr()
|
||||||
|
.offset(4 * index as isize);
|
||||||
|
|
||||||
|
ext_addr_ptr.write_volatile(
|
||||||
|
(ext_addr.offset(0).read_volatile() as u32)
|
||||||
|
| ((ext_addr.offset(1).read_volatile() as u32) << 8)
|
||||||
|
| ((ext_addr.offset(2).read_volatile() as u32) << 16)
|
||||||
|
| ((ext_addr.offset(3).read_volatile() as u32) << 24),
|
||||||
|
);
|
||||||
|
|
||||||
|
ext_addr_ptr = ext_addr_ptr.offset(1);
|
||||||
|
|
||||||
|
ext_addr_ptr.write_volatile(
|
||||||
|
(ext_addr.offset(4).read_volatile() as u32)
|
||||||
|
| ((ext_addr.offset(5).read_volatile() as u32) << 8)
|
||||||
|
| ((ext_addr.offset(6).read_volatile() as u32) << 16)
|
||||||
|
| ((ext_addr.offset(7).read_volatile() as u32) << 24),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_cca_mode(cca_mode: CcaMode) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.ed_scan_cfg()
|
||||||
|
.modify(|_, w| unsafe { w.cca_mode().bits(cca_mode as u8) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_cca_threshold(cca_threshold: i8) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.ed_scan_cfg()
|
||||||
|
.modify(|_, w| unsafe { w.cca_ed_threshold().bits(cca_threshold as u8) })
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_tx_auto_ack(enable: bool) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.ctrl_cfg()
|
||||||
|
.modify(|_, w| w.hw_auto_ack_tx_en().bit(enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn get_tx_auto_ack() -> bool {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.ctrl_cfg()
|
||||||
|
.read()
|
||||||
|
.hw_auto_ack_tx_en()
|
||||||
|
.bit_is_set()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_rx_auto_ack(enable: bool) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.ctrl_cfg()
|
||||||
|
.modify(|_, w| w.hw_auto_ack_rx_en().bit(enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_tx_enhance_ack(enable: bool) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.ctrl_cfg()
|
||||||
|
.modify(|_, w| w.hw_enhance_ack_tx_en().bit(enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn get_tx_enhance_ack() -> bool {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.ctrl_cfg()
|
||||||
|
.read()
|
||||||
|
.hw_enhance_ack_tx_en()
|
||||||
|
.bit_is_set()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_coordinator(enable: bool) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.ctrl_cfg()
|
||||||
|
.modify(|_, w| w.pan_coordinator().bit(enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_promiscuous(enable: bool) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.ctrl_cfg()
|
||||||
|
.modify(|_, w| w.promiscuous_mode().bit(enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_pending_mode(enable: bool) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.ctrl_cfg()
|
||||||
|
.modify(|_, w| w.autopend_enhance().bit(enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn get_events() -> u16 {
|
||||||
|
unsafe { &*IEEE802154::PTR }.event_status().read().bits() as u16
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn clear_events(events: u16) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.event_status()
|
||||||
|
.modify(|r, w| unsafe { w.event_status().bits(r.event_status().bits() & events) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_transmit_security(enable: bool) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.sec_ctrl()
|
||||||
|
.modify(|_, w| w.sec_en().bit(enable));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn set_rx_addr(addr: *mut u8) {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.rxdma_addr()
|
||||||
|
.modify(|_, w| unsafe { w.rxdma_addr().bits(addr as u32) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn abort_tx() {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.tx_status()
|
||||||
|
.modify(|_, w| unsafe { w.tx_abort_status().bits(0) });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub(crate) fn abort_rx() {
|
||||||
|
unsafe { &*IEEE802154::PTR }
|
||||||
|
.rx_status()
|
||||||
|
.modify(|_, w| unsafe { w.rx_abort_status().bits(0) });
|
||||||
|
}
|
||||||
349
esp-ieee802154/src/lib.rs
Normal file
349
esp-ieee802154/src/lib.rs
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
//! Low-level [IEEE 802.15.4] driver for the ESP32-C6 and ESP32-H2
|
||||||
|
//!
|
||||||
|
//! Implements the PHY/MAC layers of the IEEE 802.15.4 protocol stack, and
|
||||||
|
//! supports sending and receiving of raw frames.
|
||||||
|
//!
|
||||||
|
//! [IEEE 802.15.4]: https://en.wikipedia.org/wiki/IEEE_802.15.4
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![feature(c_variadic)]
|
||||||
|
|
||||||
|
use core::{cell::RefCell, marker::PhantomData};
|
||||||
|
|
||||||
|
use byte::{BytesExt, TryRead};
|
||||||
|
use critical_section::Mutex;
|
||||||
|
use esp_hal::peripherals::{IEEE802154, RADIO_CLK};
|
||||||
|
use heapless::Vec;
|
||||||
|
use ieee802154::mac::{self, FooterMode, FrameSerDesContext};
|
||||||
|
|
||||||
|
use self::{
|
||||||
|
frame::FRAME_SIZE,
|
||||||
|
pib::{CONFIG_IEEE802154_CCA_THRESHOLD, IEEE802154_FRAME_EXT_ADDR_SIZE},
|
||||||
|
raw::*,
|
||||||
|
};
|
||||||
|
pub use self::{
|
||||||
|
frame::{Frame, ReceivedFrame},
|
||||||
|
pib::{CcaMode, PendingMode},
|
||||||
|
raw::RawReceived,
|
||||||
|
};
|
||||||
|
|
||||||
|
mod compat;
|
||||||
|
mod frame;
|
||||||
|
mod hal;
|
||||||
|
mod pib;
|
||||||
|
mod raw;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn rtc_clk_xtal_freq_get() -> i32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IEEE 802.15.4 errors
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum Error {
|
||||||
|
/// The requested data is bigger than available range, and/or the offset is
|
||||||
|
/// invalid
|
||||||
|
Incomplete,
|
||||||
|
/// The requested data content is invalid
|
||||||
|
BadInput,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<byte::Error> for Error {
|
||||||
|
fn from(err: byte::Error) -> Self {
|
||||||
|
match err {
|
||||||
|
byte::Error::Incomplete | byte::Error::BadOffset(_) => Error::Incomplete,
|
||||||
|
byte::Error::BadInput { .. } => Error::BadInput,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IEEE 802.15.4 driver configuration
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Config {
|
||||||
|
pub auto_ack_tx: bool,
|
||||||
|
pub auto_ack_rx: bool,
|
||||||
|
pub enhance_ack_tx: bool,
|
||||||
|
pub promiscuous: bool,
|
||||||
|
pub coordinator: bool,
|
||||||
|
pub rx_when_idle: bool,
|
||||||
|
pub txpower: i8,
|
||||||
|
pub channel: u8,
|
||||||
|
pub cca_threshold: i8,
|
||||||
|
pub cca_mode: CcaMode,
|
||||||
|
pub pan_id: Option<u16>,
|
||||||
|
pub short_addr: Option<u16>,
|
||||||
|
pub ext_addr: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Config {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
auto_ack_tx: Default::default(),
|
||||||
|
auto_ack_rx: Default::default(),
|
||||||
|
enhance_ack_tx: Default::default(),
|
||||||
|
promiscuous: Default::default(),
|
||||||
|
coordinator: Default::default(),
|
||||||
|
rx_when_idle: Default::default(),
|
||||||
|
txpower: 10,
|
||||||
|
channel: 15,
|
||||||
|
cca_threshold: CONFIG_IEEE802154_CCA_THRESHOLD,
|
||||||
|
cca_mode: CcaMode::Ed,
|
||||||
|
pan_id: None,
|
||||||
|
short_addr: None,
|
||||||
|
ext_addr: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// IEEE 802.15.4 driver
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Ieee802154<'a> {
|
||||||
|
_align: u32,
|
||||||
|
transmit_buffer: [u8; FRAME_SIZE],
|
||||||
|
_phantom1: PhantomData<&'a ()>,
|
||||||
|
//_phantom2:PhantomData< &'b ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Ieee802154<'a> {
|
||||||
|
/// Construct a new driver, enabling the IEEE 802.15.4 radio in the process
|
||||||
|
pub fn new(_radio: IEEE802154, radio_clocks: &mut RADIO_CLK) -> Self {
|
||||||
|
esp_ieee802154_enable(radio_clocks);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
_align: 0,
|
||||||
|
transmit_buffer: [0u8; FRAME_SIZE],
|
||||||
|
_phantom1: PhantomData::default(),
|
||||||
|
//_phantom2: PhantomData::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the configuration for the driver
|
||||||
|
pub fn set_config(&mut self, cfg: Config) {
|
||||||
|
set_auto_ack_tx(cfg.auto_ack_tx);
|
||||||
|
set_auto_ack_rx(cfg.auto_ack_rx);
|
||||||
|
set_enhance_ack_tx(cfg.enhance_ack_tx);
|
||||||
|
set_promiscuous(cfg.promiscuous);
|
||||||
|
set_coordinator(cfg.coordinator);
|
||||||
|
set_rx_when_idle(cfg.rx_when_idle);
|
||||||
|
set_tx_power(cfg.txpower);
|
||||||
|
set_channel(cfg.channel);
|
||||||
|
set_cca_theshold(cfg.cca_threshold);
|
||||||
|
set_cca_mode(cfg.cca_mode);
|
||||||
|
|
||||||
|
if let Some(pan_id) = cfg.pan_id {
|
||||||
|
set_panid(0, pan_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(short_addr) = cfg.short_addr {
|
||||||
|
set_short_address(0, short_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ext_addr) = cfg.ext_addr {
|
||||||
|
let mut address = [0u8; IEEE802154_FRAME_EXT_ADDR_SIZE];
|
||||||
|
address.copy_from_slice(&ext_addr.to_be_bytes()); // LE or BE?
|
||||||
|
|
||||||
|
set_extended_address(0, address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Start receiving frames
|
||||||
|
pub fn start_receive(&mut self) {
|
||||||
|
ieee802154_receive();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the raw data of a received frame
|
||||||
|
pub fn get_raw_received(&mut self) -> Option<RawReceived> {
|
||||||
|
ieee802154_poll()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a received frame, if available
|
||||||
|
pub fn get_received(&mut self) -> Option<Result<ReceivedFrame, Error>> {
|
||||||
|
if let Some(raw) = ieee802154_poll() {
|
||||||
|
let maybe_decoded =
|
||||||
|
mac::Frame::try_read(&raw.data[1..][..raw.data[0] as usize], FooterMode::Explicit);
|
||||||
|
|
||||||
|
let result = match maybe_decoded {
|
||||||
|
Ok((decoded, _)) => {
|
||||||
|
let rssi = raw.data[raw.data[0] as usize - 1] as i8; // crc is not written to rx buffer
|
||||||
|
|
||||||
|
Ok(ReceivedFrame {
|
||||||
|
frame: Frame {
|
||||||
|
header: decoded.header,
|
||||||
|
content: decoded.content,
|
||||||
|
payload: Vec::from_slice(decoded.payload).unwrap(),
|
||||||
|
footer: decoded.footer,
|
||||||
|
},
|
||||||
|
channel: raw.channel,
|
||||||
|
rssi,
|
||||||
|
lqi: rssi_to_lqi(rssi),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Err(err) => Err(err.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(result)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transmit a frame
|
||||||
|
pub fn transmit(&mut self, frame: &Frame) -> Result<(), Error> {
|
||||||
|
let frm = mac::Frame {
|
||||||
|
header: frame.header,
|
||||||
|
content: frame.content,
|
||||||
|
payload: &frame.payload,
|
||||||
|
footer: frame.footer,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut offset = 1usize;
|
||||||
|
self.transmit_buffer
|
||||||
|
.write_with(
|
||||||
|
&mut offset,
|
||||||
|
frm,
|
||||||
|
&mut FrameSerDesContext::no_security(FooterMode::Explicit),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
self.transmit_buffer[0] = (offset - 1) as u8;
|
||||||
|
|
||||||
|
ieee802154_transmit(self.transmit_buffer.as_ptr() as *const u8, false); // what about CCA?
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transmit a raw frame
|
||||||
|
pub fn transmit_raw(&mut self, frame: &[u8]) -> Result<(), Error> {
|
||||||
|
self.transmit_buffer[1..][..frame.len()].copy_from_slice(frame);
|
||||||
|
self.transmit_buffer[0] = frame.len() as u8;
|
||||||
|
|
||||||
|
ieee802154_transmit(self.transmit_buffer.as_ptr() as *const u8, false); // what about CCA?
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_tx_done_callback(&mut self, callback: &'a mut (dyn FnMut() + Send)) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut tx_done_callback = TX_DONE_CALLBACK.borrow_ref_mut(cs);
|
||||||
|
tx_done_callback.replace(unsafe { core::mem::transmute(callback) });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_tx_done_callback(&mut self) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut tx_done_callback = TX_DONE_CALLBACK.borrow_ref_mut(cs);
|
||||||
|
tx_done_callback.take();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_rx_available_callback(&mut self, callback: &'a mut (dyn FnMut() + Send)) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut rx_available_callback = RX_AVAILABLE_CALLBACK.borrow_ref_mut(cs);
|
||||||
|
rx_available_callback.replace(unsafe { core::mem::transmute(callback) });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_rx_available_callback(&mut self) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut rx_available_callback = RX_AVAILABLE_CALLBACK.borrow_ref_mut(cs);
|
||||||
|
rx_available_callback.take();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_tx_done_callback_fn(&mut self, callback: fn()) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut tx_done_callback_fn = TX_DONE_CALLBACK_FN.borrow_ref_mut(cs);
|
||||||
|
tx_done_callback_fn.replace(callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_tx_done_callback_fn(&mut self) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut tx_done_callback_fn = TX_DONE_CALLBACK_FN.borrow_ref_mut(cs);
|
||||||
|
tx_done_callback_fn.take();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_rx_available_callback_fn(&mut self, callback: fn()) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut rx_available_callback_fn = RX_AVAILABLE_CALLBACK_FN.borrow_ref_mut(cs);
|
||||||
|
rx_available_callback_fn.replace(unsafe { core::mem::transmute(callback) });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_rx_available_callback_fn(&mut self) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut rx_available_callback_fn = RX_AVAILABLE_CALLBACK_FN.borrow_ref_mut(cs);
|
||||||
|
rx_available_callback_fn.take();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Drop for Ieee802154<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.clear_tx_done_callback();
|
||||||
|
self.clear_tx_done_callback_fn();
|
||||||
|
self.clear_rx_available_callback();
|
||||||
|
self.clear_rx_available_callback_fn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rssi_to_lqi(rssi: i8) -> u8 {
|
||||||
|
if rssi < -80 {
|
||||||
|
0
|
||||||
|
} else if rssi > -30 {
|
||||||
|
0xff
|
||||||
|
} else {
|
||||||
|
let lqi_convert = ((rssi as u32).wrapping_add(80)) * 255;
|
||||||
|
(lqi_convert / 50) as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static TX_DONE_CALLBACK: Mutex<RefCell<Option<&'static mut (dyn FnMut() + Send)>>> =
|
||||||
|
Mutex::new(RefCell::new(None));
|
||||||
|
|
||||||
|
static RX_AVAILABLE_CALLBACK: Mutex<RefCell<Option<&'static mut (dyn FnMut() + Send)>>> =
|
||||||
|
Mutex::new(RefCell::new(None));
|
||||||
|
|
||||||
|
static TX_DONE_CALLBACK_FN: Mutex<RefCell<Option<fn()>>> = Mutex::new(RefCell::new(None));
|
||||||
|
|
||||||
|
static RX_AVAILABLE_CALLBACK_FN: Mutex<RefCell<Option<fn()>>> = Mutex::new(RefCell::new(None));
|
||||||
|
|
||||||
|
fn tx_done() {
|
||||||
|
log::trace!("tx_done callback");
|
||||||
|
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut tx_done_callback = TX_DONE_CALLBACK.borrow_ref_mut(cs);
|
||||||
|
let tx_done_callback = tx_done_callback.as_mut();
|
||||||
|
|
||||||
|
if let Some(tx_done_callback) = tx_done_callback {
|
||||||
|
tx_done_callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut tx_done_callback_fn = TX_DONE_CALLBACK_FN.borrow_ref_mut(cs);
|
||||||
|
let tx_done_callback_fn = tx_done_callback_fn.as_mut();
|
||||||
|
|
||||||
|
if let Some(tx_done_callback_fn) = tx_done_callback_fn {
|
||||||
|
tx_done_callback_fn();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rx_available() {
|
||||||
|
log::trace!("rx available callback");
|
||||||
|
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut rx_available_callback = RX_AVAILABLE_CALLBACK.borrow_ref_mut(cs);
|
||||||
|
let rx_available_callback = rx_available_callback.as_mut();
|
||||||
|
|
||||||
|
if let Some(rx_available_callback) = rx_available_callback {
|
||||||
|
rx_available_callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rx_available_callback_fn = RX_AVAILABLE_CALLBACK_FN.borrow_ref_mut(cs);
|
||||||
|
let rx_available_callback_fn = rx_available_callback_fn.as_mut();
|
||||||
|
|
||||||
|
if let Some(rx_available_callback_fn) = rx_available_callback_fn {
|
||||||
|
rx_available_callback_fn();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
241
esp-ieee802154/src/pib.rs
Normal file
241
esp-ieee802154/src/pib.rs
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
use core::cell::RefCell;
|
||||||
|
|
||||||
|
use critical_section::Mutex;
|
||||||
|
|
||||||
|
use crate::hal::{
|
||||||
|
set_cca_mode,
|
||||||
|
set_cca_threshold,
|
||||||
|
set_coordinator,
|
||||||
|
set_freq,
|
||||||
|
set_multipan_enable_mask,
|
||||||
|
set_multipan_ext_addr,
|
||||||
|
set_multipan_panid,
|
||||||
|
set_multipan_short_addr,
|
||||||
|
set_pending_mode,
|
||||||
|
set_power,
|
||||||
|
set_promiscuous,
|
||||||
|
set_rx_auto_ack,
|
||||||
|
set_tx_auto_ack,
|
||||||
|
set_tx_enhance_ack,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) const CONFIG_IEEE802154_CCA_THRESHOLD: i8 = 1;
|
||||||
|
pub(crate) const IEEE802154_FRAME_EXT_ADDR_SIZE: usize = 8;
|
||||||
|
|
||||||
|
const IEEE802154_MULTIPAN_0: u8 = 0;
|
||||||
|
const IEEE802154_MULTIPAN_MAX: usize = 4;
|
||||||
|
|
||||||
|
static PIB: Mutex<RefCell<Option<Pib>>> = Mutex::new(RefCell::new(None));
|
||||||
|
|
||||||
|
/// Frame pending mode
|
||||||
|
#[derive(Debug, Default, Clone, Copy, PartialEq)]
|
||||||
|
pub enum PendingMode {
|
||||||
|
/// Frame pending bit always set to 1 in the ack to Data Request
|
||||||
|
#[default]
|
||||||
|
Disable = 0,
|
||||||
|
/// Frame pending bit set to 1 if src address matches, in the ack to Data
|
||||||
|
/// Request
|
||||||
|
Enable = 1,
|
||||||
|
/// Frame pending bit set to 1 if src address matches, in all ack frames
|
||||||
|
Enhanced = 2,
|
||||||
|
/// Frame pending bit set to 0 only if src address is short address and
|
||||||
|
/// matches in table, in the ack to Data Request
|
||||||
|
Zigbee = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CCA mode
|
||||||
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
|
pub enum CcaMode {
|
||||||
|
/// Carrier only
|
||||||
|
#[default]
|
||||||
|
Carrier = 0x00,
|
||||||
|
/// Energy Detect only
|
||||||
|
Ed = 0x01,
|
||||||
|
/// Carrier or Energy Detect
|
||||||
|
CarrierOrEd = 0x02,
|
||||||
|
/// Carrier and Energy Detect
|
||||||
|
CarrierAndEd = 0x03,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
|
struct Pib {
|
||||||
|
auto_ack_tx: bool,
|
||||||
|
auto_ack_rx: bool,
|
||||||
|
enhance_ack_tx: bool,
|
||||||
|
promiscuous: bool,
|
||||||
|
coordinator: bool,
|
||||||
|
rx_when_idle: bool,
|
||||||
|
txpower: i8,
|
||||||
|
channel: u8,
|
||||||
|
pending_mode: PendingMode,
|
||||||
|
multipan_mask: u8,
|
||||||
|
panid: [u16; IEEE802154_MULTIPAN_MAX],
|
||||||
|
short_addr: [u16; IEEE802154_MULTIPAN_MAX],
|
||||||
|
ext_addr: [[u8; IEEE802154_FRAME_EXT_ADDR_SIZE]; IEEE802154_MULTIPAN_MAX],
|
||||||
|
cca_threshold: i8,
|
||||||
|
cca_mode: CcaMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_init() {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).replace(Pib {
|
||||||
|
auto_ack_tx: true,
|
||||||
|
auto_ack_rx: true,
|
||||||
|
enhance_ack_tx: true,
|
||||||
|
coordinator: false,
|
||||||
|
promiscuous: true,
|
||||||
|
rx_when_idle: false,
|
||||||
|
txpower: 10,
|
||||||
|
channel: 11,
|
||||||
|
pending_mode: PendingMode::Disable,
|
||||||
|
multipan_mask: 1 << IEEE802154_MULTIPAN_0,
|
||||||
|
panid: [0u16; 4],
|
||||||
|
short_addr: [0u16; IEEE802154_MULTIPAN_MAX],
|
||||||
|
ext_addr: [[0xffu8; IEEE802154_FRAME_EXT_ADDR_SIZE]; IEEE802154_MULTIPAN_MAX],
|
||||||
|
cca_threshold: CONFIG_IEEE802154_CCA_THRESHOLD,
|
||||||
|
cca_mode: CcaMode::Ed,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_set_panid(index: u8, panid: u16) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).as_mut().unwrap().panid[index as usize] = panid;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_set_promiscuous(enable: bool) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).as_mut().unwrap().promiscuous = enable;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_set_auto_ack_tx(enable: bool) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).as_mut().unwrap().auto_ack_tx = enable;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_set_auto_ack_rx(enable: bool) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).as_mut().unwrap().auto_ack_rx = enable;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_set_enhance_ack_tx(enable: bool) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).as_mut().unwrap().enhance_ack_tx = enable;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_set_coordinator(enable: bool) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).as_mut().unwrap().coordinator = enable;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_set_rx_when_idle(enable: bool) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).as_mut().unwrap().rx_when_idle = enable;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_get_rx_when_idle() -> bool {
|
||||||
|
critical_section::with(|cs| PIB.borrow_ref_mut(cs).as_mut().unwrap().rx_when_idle)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_set_tx_power(power: i8) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).as_mut().unwrap().txpower = power;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_set_channel(channel: u8) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).as_mut().unwrap().channel = channel;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_set_pending_mode(mode: PendingMode) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).as_mut().unwrap().pending_mode = mode;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_set_short_address(index: u8, address: u16) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).as_mut().unwrap().short_addr[index as usize] = address;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_set_extended_address(
|
||||||
|
index: u8,
|
||||||
|
address: [u8; IEEE802154_FRAME_EXT_ADDR_SIZE],
|
||||||
|
) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).as_mut().unwrap().ext_addr[index as usize] = address;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_set_cca_theshold(cca_threshold: i8) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).as_mut().unwrap().cca_threshold = cca_threshold;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_set_cca_mode(mode: CcaMode) {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
PIB.borrow_ref_mut(cs).as_mut().unwrap().cca_mode = mode;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn ieee802154_pib_update() {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut pib = PIB.borrow_ref_mut(cs);
|
||||||
|
let pib = pib.as_mut().unwrap();
|
||||||
|
|
||||||
|
set_freq(channel_to_freq(pib.channel));
|
||||||
|
set_power(ieee802154_txpower_convert(pib.txpower));
|
||||||
|
|
||||||
|
set_multipan_enable_mask(pib.multipan_mask);
|
||||||
|
ieee802154_set_multipan_hal(pib);
|
||||||
|
|
||||||
|
set_cca_mode(pib.cca_mode);
|
||||||
|
set_cca_threshold(pib.cca_threshold);
|
||||||
|
|
||||||
|
set_tx_auto_ack(pib.auto_ack_tx);
|
||||||
|
set_rx_auto_ack(pib.auto_ack_rx);
|
||||||
|
set_tx_enhance_ack(pib.enhance_ack_tx);
|
||||||
|
|
||||||
|
set_coordinator(pib.coordinator);
|
||||||
|
set_promiscuous(pib.promiscuous);
|
||||||
|
set_pending_mode(pib.pending_mode == PendingMode::Enhanced);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn channel_to_freq(channel: u8) -> u8 {
|
||||||
|
(channel - 11) * 5 + 3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ieee802154_set_multipan_hal(pib: &Pib) {
|
||||||
|
for index in 0..IEEE802154_MULTIPAN_MAX {
|
||||||
|
if (pib.multipan_mask & (1 << index)) != 0 {
|
||||||
|
set_multipan_panid(index.into(), pib.panid[index]);
|
||||||
|
set_multipan_short_addr(index.into(), pib.short_addr[index]);
|
||||||
|
set_multipan_ext_addr(index.into(), pib.ext_addr[index].as_ptr() as *const u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ieee802154_txpower_convert(txpower: i8) -> u8 {
|
||||||
|
const IEEE802154_TXPOWER_VALUE_MAX: i8 = 13;
|
||||||
|
const IEEE802154_TXPOWER_VALUE_MIN: i8 = -32;
|
||||||
|
|
||||||
|
if txpower > IEEE802154_TXPOWER_VALUE_MAX {
|
||||||
|
15
|
||||||
|
} else if txpower < IEEE802154_TXPOWER_VALUE_MIN {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
((txpower - IEEE802154_TXPOWER_VALUE_MIN) / 3) as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
439
esp-ieee802154/src/raw.rs
Normal file
439
esp-ieee802154/src/raw.rs
Normal file
@ -0,0 +1,439 @@
|
|||||||
|
use core::cell::RefCell;
|
||||||
|
|
||||||
|
use critical_section::Mutex;
|
||||||
|
use esp_hal::{
|
||||||
|
interrupt::Priority,
|
||||||
|
peripherals::RADIO_CLK,
|
||||||
|
prelude::handler,
|
||||||
|
system::{RadioClockController, RadioPeripherals},
|
||||||
|
};
|
||||||
|
use esp_wifi_sys::include::{
|
||||||
|
esp_phy_calibration_data_t,
|
||||||
|
esp_phy_calibration_mode_t_PHY_RF_CAL_FULL,
|
||||||
|
ieee802154_coex_event_t,
|
||||||
|
ieee802154_coex_event_t_IEEE802154_IDLE,
|
||||||
|
ieee802154_coex_event_t_IEEE802154_LOW,
|
||||||
|
ieee802154_coex_event_t_IEEE802154_MIDDLE,
|
||||||
|
register_chipv7_phy,
|
||||||
|
};
|
||||||
|
use heapless::spsc::Queue;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
frame::{frame_get_version, frame_is_ack_required, FRAME_VERSION_1, FRAME_VERSION_2},
|
||||||
|
hal::*,
|
||||||
|
pib::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) const FRAME_SIZE: usize = 129;
|
||||||
|
|
||||||
|
const PHY_ENABLE_VERSION_PRINT: u32 = 1;
|
||||||
|
|
||||||
|
static mut RX_BUFFER: [u8; FRAME_SIZE] = [0u8; FRAME_SIZE];
|
||||||
|
static RX_QUEUE: Mutex<RefCell<Queue<RawReceived, 20>>> = Mutex::new(RefCell::new(Queue::new()));
|
||||||
|
static STATE: Mutex<RefCell<Ieee802154State>> = Mutex::new(RefCell::new(Ieee802154State::Idle));
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
fn bt_bb_v2_init_cmplx(print_version: u32); // from libbtbb.a
|
||||||
|
|
||||||
|
fn bt_bb_set_zb_tx_on_delay(time: u16); // from libbtbb.a
|
||||||
|
|
||||||
|
fn esp_coex_ieee802154_ack_pti_set(event: ieee802154_coex_event_t); // from ???
|
||||||
|
|
||||||
|
fn esp_coex_ieee802154_txrx_pti_set(event: ieee802154_coex_event_t); // from ???
|
||||||
|
|
||||||
|
fn phy_version_print(); // from libphy.a
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
enum Ieee802154State {
|
||||||
|
Idle,
|
||||||
|
Receive,
|
||||||
|
Transmit,
|
||||||
|
TxAck,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
enum Ieee802154TxRxScene {
|
||||||
|
Idle,
|
||||||
|
Tx,
|
||||||
|
Rx,
|
||||||
|
TxAt,
|
||||||
|
RxAt,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A raw payload received on some channel
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct RawReceived {
|
||||||
|
/// Payload
|
||||||
|
pub data: [u8; FRAME_SIZE],
|
||||||
|
/// Receiver channel
|
||||||
|
pub channel: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn esp_ieee802154_enable(radio_clock_control: &mut RADIO_CLK) {
|
||||||
|
radio_clock_control.init_clocks();
|
||||||
|
radio_clock_control.enable(RadioPeripherals::Phy);
|
||||||
|
radio_clock_control.enable(RadioPeripherals::Ieee802154);
|
||||||
|
|
||||||
|
esp_phy_enable();
|
||||||
|
esp_btbb_enable();
|
||||||
|
ieee802154_mac_init();
|
||||||
|
|
||||||
|
unsafe { phy_version_print() }; // libphy.a
|
||||||
|
log::info!("date={:x}", mac_date());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn esp_phy_enable() {
|
||||||
|
unsafe {
|
||||||
|
let mut calibration_data = esp_phy_calibration_data_t {
|
||||||
|
version: [0u8; 4],
|
||||||
|
mac: [0u8; 6],
|
||||||
|
opaque: [0u8; 1894],
|
||||||
|
};
|
||||||
|
|
||||||
|
register_chipv7_phy(
|
||||||
|
core::ptr::null(),
|
||||||
|
&mut calibration_data as *mut esp_phy_calibration_data_t,
|
||||||
|
esp_phy_calibration_mode_t_PHY_RF_CAL_FULL,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn esp_btbb_enable() {
|
||||||
|
unsafe { bt_bb_v2_init_cmplx(PHY_ENABLE_VERSION_PRINT) };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ieee802154_mac_init() {
|
||||||
|
#[cfg(feature = "esp32c6")]
|
||||||
|
unsafe {
|
||||||
|
extern "C" {
|
||||||
|
static mut coex_pti_tab_ptr: u32;
|
||||||
|
static coex_pti_tab: u8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manually set `coex_pti_tab_ptr` pointing to `coex_pti_tab`
|
||||||
|
core::ptr::addr_of_mut!(coex_pti_tab_ptr).write_volatile(&coex_pti_tab as *const _ as u32);
|
||||||
|
}
|
||||||
|
|
||||||
|
ieee802154_pib_init();
|
||||||
|
|
||||||
|
enable_events(Event::mask());
|
||||||
|
disable_events(Event::Timer0Overflow | Event::Timer1Overflow);
|
||||||
|
|
||||||
|
enable_tx_abort_events(
|
||||||
|
TxAbortReason::RxAckTimeout
|
||||||
|
| TxAbortReason::TxCoexBreak
|
||||||
|
| TxAbortReason::TxSecurityError
|
||||||
|
| TxAbortReason::CcaFailed
|
||||||
|
| TxAbortReason::CcaBusy
|
||||||
|
| TxAbortReason::TxStop,
|
||||||
|
);
|
||||||
|
enable_rx_abort_events(
|
||||||
|
RxAbortReason::TxAckTimeout | RxAbortReason::TxAckCoexBreak | RxAbortReason::RxStop,
|
||||||
|
);
|
||||||
|
|
||||||
|
set_ed_sample_mode(EdSampleMode::Avg);
|
||||||
|
|
||||||
|
unsafe { esp_coex_ieee802154_ack_pti_set(ieee802154_coex_event_t_IEEE802154_MIDDLE) };
|
||||||
|
ieee802154_set_txrx_pti(Ieee802154TxRxScene::Idle);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
bt_bb_set_zb_tx_on_delay(50); // set tx on delay for libbtbb.a
|
||||||
|
}
|
||||||
|
set_rx_on_delay(50);
|
||||||
|
|
||||||
|
// memset(s_rx_frame, 0, sizeof(s_rx_frame));
|
||||||
|
// s_ieee802154_state = IEEE802154_STATE_IDLE;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
esp_hal::interrupt::bind_interrupt(
|
||||||
|
esp_hal::peripherals::Interrupt::ZB_MAC,
|
||||||
|
ZB_MAC.handler(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
esp_hal::interrupt::enable(esp_hal::peripherals::Interrupt::ZB_MAC, ZB_MAC.priority()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ieee802154_set_txrx_pti(txrx_scene: Ieee802154TxRxScene) {
|
||||||
|
match txrx_scene {
|
||||||
|
Ieee802154TxRxScene::Idle => {
|
||||||
|
unsafe { esp_coex_ieee802154_txrx_pti_set(ieee802154_coex_event_t_IEEE802154_IDLE) };
|
||||||
|
}
|
||||||
|
Ieee802154TxRxScene::Tx | Ieee802154TxRxScene::Rx => {
|
||||||
|
unsafe { esp_coex_ieee802154_txrx_pti_set(ieee802154_coex_event_t_IEEE802154_LOW) };
|
||||||
|
}
|
||||||
|
Ieee802154TxRxScene::TxAt | Ieee802154TxRxScene::RxAt => {
|
||||||
|
unsafe { esp_coex_ieee802154_txrx_pti_set(ieee802154_coex_event_t_IEEE802154_MIDDLE) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tx_init(frame: *const u8) {
|
||||||
|
let tx_frame = frame;
|
||||||
|
stop_current_operation();
|
||||||
|
ieee802154_pib_update();
|
||||||
|
ieee802154_sec_update();
|
||||||
|
|
||||||
|
set_tx_addr(tx_frame);
|
||||||
|
|
||||||
|
if true
|
||||||
|
// ieee802154_frame_is_ack_required(frame)
|
||||||
|
{
|
||||||
|
// set rx pointer for ack frame
|
||||||
|
set_next_rx_buffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ieee802154_transmit(frame: *const u8, cca: bool) -> i32 {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
tx_init(frame);
|
||||||
|
|
||||||
|
ieee802154_set_txrx_pti(Ieee802154TxRxScene::Tx);
|
||||||
|
|
||||||
|
if cca {
|
||||||
|
// disable_events(IEEE802154_EVENT_ED_DONE);
|
||||||
|
// set_cmd(IEEE802154_CMD_CCA_TX_START);
|
||||||
|
// ieee802154_state = IEEE802154_STATE_TX_CCA;
|
||||||
|
} else {
|
||||||
|
set_cmd(Command::TxStart);
|
||||||
|
// if (ieee802154_frame_get_type(frame) == IEEE802154_FRAME_TYPE_ACK
|
||||||
|
// && ieee802154_frame_get_version(frame) == IEEE802154_FRAME_VERSION_2)
|
||||||
|
// {
|
||||||
|
// ieee802154_state = IEEE802154_STATE_TX_ENH_ACK;
|
||||||
|
// } else {
|
||||||
|
*STATE.borrow_ref_mut(cs) = Ieee802154State::Transmit;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
0 // ESP_OK
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ieee802154_receive() -> i32 {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
if *STATE.borrow_ref(cs) == Ieee802154State::Receive {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rx_init();
|
||||||
|
enable_rx();
|
||||||
|
|
||||||
|
*STATE.borrow_ref_mut(cs) = Ieee802154State::Receive;
|
||||||
|
});
|
||||||
|
|
||||||
|
0 // ESP-OK
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ieee802154_poll() -> Option<RawReceived> {
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut queue = RX_QUEUE.borrow_ref_mut(cs);
|
||||||
|
queue.dequeue()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rx_init() {
|
||||||
|
stop_current_operation();
|
||||||
|
ieee802154_pib_update();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enable_rx() {
|
||||||
|
set_next_rx_buffer();
|
||||||
|
ieee802154_set_txrx_pti(Ieee802154TxRxScene::Rx);
|
||||||
|
|
||||||
|
set_cmd(Command::RxStart);
|
||||||
|
|
||||||
|
// ieee802154_state = IEEE802154_STATE_RX;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop_current_operation() {
|
||||||
|
let events = get_events();
|
||||||
|
set_cmd(Command::Stop);
|
||||||
|
clear_events(events);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_next_rx_buffer() {
|
||||||
|
unsafe {
|
||||||
|
set_rx_addr(RX_BUFFER.as_mut_ptr() as *mut u8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_promiscuous(enable: bool) {
|
||||||
|
ieee802154_pib_set_promiscuous(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_auto_ack_tx(enable: bool) {
|
||||||
|
ieee802154_pib_set_auto_ack_tx(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_auto_ack_rx(enable: bool) {
|
||||||
|
ieee802154_pib_set_auto_ack_rx(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_enhance_ack_tx(enable: bool) {
|
||||||
|
ieee802154_pib_set_enhance_ack_tx(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_coordinator(enable: bool) {
|
||||||
|
ieee802154_pib_set_coordinator(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_rx_when_idle(enable: bool) {
|
||||||
|
ieee802154_pib_set_rx_when_idle(enable);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_tx_power(power: i8) {
|
||||||
|
ieee802154_pib_set_tx_power(power);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_channel(channel: u8) {
|
||||||
|
ieee802154_pib_set_channel(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn set_pending_mode(mode: PendingMode) {
|
||||||
|
ieee802154_pib_set_pending_mode(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn set_multipan_enable(mask: u8) {
|
||||||
|
set_multipan_enable_mask(mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_short_address(index: u8, address: u16) {
|
||||||
|
ieee802154_pib_set_short_address(index, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_extended_address(index: u8, address: [u8; IEEE802154_FRAME_EXT_ADDR_SIZE]) {
|
||||||
|
ieee802154_pib_set_extended_address(index, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_cca_theshold(cca_threshold: i8) {
|
||||||
|
ieee802154_pib_set_cca_theshold(cca_threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_cca_mode(mode: CcaMode) {
|
||||||
|
ieee802154_pib_set_cca_mode(mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_panid(index: u8, id: u16) {
|
||||||
|
ieee802154_pib_set_panid(index, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn ieee802154_sec_update() {
|
||||||
|
let is_security = false;
|
||||||
|
set_transmit_security(is_security);
|
||||||
|
// ieee802154_sec_clr_transmit_security();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_operation() {
|
||||||
|
let previous_operation = critical_section::with(|cs| {
|
||||||
|
let state = STATE.borrow_ref(cs).clone();
|
||||||
|
|
||||||
|
if ieee802154_pib_get_rx_when_idle() {
|
||||||
|
enable_rx();
|
||||||
|
*STATE.borrow_ref_mut(cs) = Ieee802154State::Receive;
|
||||||
|
} else {
|
||||||
|
*STATE.borrow_ref_mut(cs) = Ieee802154State::Idle;
|
||||||
|
}
|
||||||
|
|
||||||
|
state
|
||||||
|
});
|
||||||
|
|
||||||
|
match previous_operation {
|
||||||
|
Ieee802154State::Receive => crate::rx_available(),
|
||||||
|
Ieee802154State::Transmit => crate::tx_done(),
|
||||||
|
Ieee802154State::TxAck => crate::tx_done(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[handler(priority = "Priority::Priority1")]
|
||||||
|
fn ZB_MAC() {
|
||||||
|
log::trace!("ZB_MAC interrupt");
|
||||||
|
|
||||||
|
let events = get_events();
|
||||||
|
clear_events(events);
|
||||||
|
|
||||||
|
log::trace!("events = {:032b}", events);
|
||||||
|
|
||||||
|
if events & Event::RxSfdDone != 0 {
|
||||||
|
// IEEE802154_STATE_TX && IEEE802154_STATE_TX_CCA && IEEE802154_STATE_TX_ENH_ACK
|
||||||
|
// for isr processing delay
|
||||||
|
log::trace!("rx sfd done");
|
||||||
|
}
|
||||||
|
|
||||||
|
if events & Event::TxSfdDone != 0 {
|
||||||
|
// IEEE802154_STATE_RX for isr processing delay, only 821
|
||||||
|
// IEEE802154_STATE_TX_ACK for workaround jira ZB-81.
|
||||||
|
log::trace!("tx sfd done");
|
||||||
|
}
|
||||||
|
|
||||||
|
if events & Event::TxDone != 0 {
|
||||||
|
log::trace!("tx done");
|
||||||
|
next_operation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if events & Event::RxDone != 0 {
|
||||||
|
log::trace!("rx done");
|
||||||
|
unsafe {
|
||||||
|
log::trace!("Received raw {:x?}", RX_BUFFER);
|
||||||
|
critical_section::with(|cs| {
|
||||||
|
let mut queue = RX_QUEUE.borrow_ref_mut(cs);
|
||||||
|
if !queue.is_full() {
|
||||||
|
let item = RawReceived {
|
||||||
|
data: RX_BUFFER,
|
||||||
|
channel: freq_to_channel(get_freq()),
|
||||||
|
};
|
||||||
|
queue.enqueue(item).ok();
|
||||||
|
} else {
|
||||||
|
log::warn!("Receive queue full");
|
||||||
|
}
|
||||||
|
|
||||||
|
let frm = &RX_BUFFER[1..][..RX_BUFFER[0] as usize];
|
||||||
|
if will_auto_send_ack(frm) {
|
||||||
|
*STATE.borrow_ref_mut(cs) = Ieee802154State::TxAck;
|
||||||
|
} else if should_send_enhanced_ack(frm) {
|
||||||
|
// TODO
|
||||||
|
} else {
|
||||||
|
// esp_ieee802154_coex_pti_set(IEEE802154_IDLE_RX);
|
||||||
|
next_operation();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if events & Event::AckRxDone != 0 {
|
||||||
|
log::info!("EventAckRxDone");
|
||||||
|
}
|
||||||
|
|
||||||
|
if events & Event::AckTxDone != 0 {
|
||||||
|
log::trace!("EventAckTxDone");
|
||||||
|
next_operation();
|
||||||
|
}
|
||||||
|
|
||||||
|
if events & Event::TxAbort != 0 {
|
||||||
|
log::trace!("TxAbort");
|
||||||
|
abort_tx();
|
||||||
|
}
|
||||||
|
|
||||||
|
if events & Event::RxAbort != 0 {
|
||||||
|
log::trace!("RxAbort");
|
||||||
|
abort_rx();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn freq_to_channel(freq: u8) -> u8 {
|
||||||
|
(freq - 3) / 5 + 11
|
||||||
|
}
|
||||||
|
|
||||||
|
fn will_auto_send_ack(frame: &[u8]) -> bool {
|
||||||
|
frame_is_ack_required(frame) && frame_get_version(frame) <= FRAME_VERSION_1 && get_tx_auto_ack()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn should_send_enhanced_ack(frame: &[u8]) -> bool {
|
||||||
|
frame_is_ack_required(frame)
|
||||||
|
&& frame_get_version(frame) <= FRAME_VERSION_2
|
||||||
|
&& get_tx_enhance_ack()
|
||||||
|
}
|
||||||
@ -11,30 +11,32 @@ cfg-if = "1.0.0"
|
|||||||
critical-section = "1.1.2"
|
critical-section = "1.1.2"
|
||||||
crypto-bigint = { version = "0.5.5", default-features = false }
|
crypto-bigint = { version = "0.5.5", default-features = false }
|
||||||
elliptic-curve = { version = "0.13.8", default-features = false, features = ["sec1"] }
|
elliptic-curve = { version = "0.13.8", default-features = false, features = ["sec1"] }
|
||||||
# some examples use a huge amount of stack
|
|
||||||
embassy-executor = { version = "0.5.0", features = ["task-arena-size-40960"] }
|
embassy-executor = { version = "0.5.0", features = ["task-arena-size-40960"] }
|
||||||
embassy-sync = "0.5.0"
|
|
||||||
embassy-futures = "0.1.1"
|
embassy-futures = "0.1.1"
|
||||||
|
embassy-sync = "0.5.0"
|
||||||
embassy-time = "0.3.0"
|
embassy-time = "0.3.0"
|
||||||
embassy-time-driver = { version = "0.1.0", optional = true }
|
embassy-time-driver = { version = "0.1.0", optional = true }
|
||||||
embassy-usb = { version = "0.1.0", default-features = false, optional = true }
|
embassy-usb = { version = "0.1.0", default-features = false, optional = true }
|
||||||
|
embedded-can = "0.4.1"
|
||||||
embedded-graphics = "0.8.1"
|
embedded-graphics = "0.8.1"
|
||||||
embedded-hal = "1.0.0"
|
embedded-hal = "1.0.0"
|
||||||
embedded-hal-02 = { version = "0.2.7", package = "embedded-hal", features = ["unproven"] }
|
embedded-hal-02 = { version = "0.2.7", package = "embedded-hal", features = ["unproven"] }
|
||||||
embedded-hal-async = "1.0.0"
|
embedded-hal-async = "1.0.0"
|
||||||
embedded-hal-bus = "0.1.0"
|
embedded-hal-bus = "0.1.0"
|
||||||
embedded-io-async = "0.6.1"
|
embedded-io-async = "0.6.1"
|
||||||
embedded-can = "0.4.1"
|
|
||||||
esp-alloc = { version = "0.3.0", path = "../esp-alloc" }
|
esp-alloc = { version = "0.3.0", path = "../esp-alloc" }
|
||||||
esp-backtrace = { version = "0.11.1", features = ["exception-handler", "panic-handler", "println"] }
|
esp-backtrace = { version = "0.11.1", features = ["exception-handler", "panic-handler", "println"] }
|
||||||
esp-hal = { version = "0.17.0", path = "../esp-hal", features = ["log"] }
|
esp-hal = { version = "0.17.0", path = "../esp-hal", features = ["log"] }
|
||||||
esp-hal-smartled = { version = "0.10.0", path = "../esp-hal-smartled", optional = true }
|
esp-hal-smartled = { version = "0.10.0", path = "../esp-hal-smartled", optional = true }
|
||||||
|
esp-ieee802154 = { version = "0.1.0", path = "../esp-ieee802154", optional = true }
|
||||||
esp-println = { version = "0.9.1", features = ["log"] }
|
esp-println = { version = "0.9.1", features = ["log"] }
|
||||||
fugit = "0.3.7"
|
fugit = "0.3.7"
|
||||||
heapless = "0.8.0"
|
heapless = "0.8.0"
|
||||||
hex-literal = "0.4.1"
|
hex-literal = "0.4.1"
|
||||||
hmac = { version = "0.12.1", default-features = false }
|
hmac = { version = "0.12.1", default-features = false }
|
||||||
|
ieee802154 = "0.6.1"
|
||||||
lis3dh-async = "0.9.2"
|
lis3dh-async = "0.9.2"
|
||||||
|
log = "0.4.21"
|
||||||
nb = "1.1.0"
|
nb = "1.1.0"
|
||||||
p192 = { version = "0.13.0", default-features = false, features = ["arithmetic"] }
|
p192 = { version = "0.13.0", default-features = false, features = ["arithmetic"] }
|
||||||
p256 = { version = "0.13.2", default-features = false, features = ["arithmetic"] }
|
p256 = { version = "0.13.2", default-features = false, features = ["arithmetic"] }
|
||||||
@ -45,14 +47,13 @@ ssd1306 = "0.8.4"
|
|||||||
static_cell = { version = "2.0.0", features = ["nightly"] }
|
static_cell = { version = "2.0.0", features = ["nightly"] }
|
||||||
usb-device = "0.3.2"
|
usb-device = "0.3.2"
|
||||||
usbd-serial = "0.2.1"
|
usbd-serial = "0.2.1"
|
||||||
log = "0.4"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
esp32 = ["esp-hal/esp32", "esp-backtrace/esp32", "esp-println/esp32", "esp-hal-smartled/esp32"]
|
esp32 = ["esp-hal/esp32", "esp-backtrace/esp32", "esp-println/esp32", "esp-hal-smartled/esp32"]
|
||||||
esp32c2 = ["esp-hal/esp32c2", "esp-backtrace/esp32c2", "esp-println/esp32c2"]
|
esp32c2 = ["esp-hal/esp32c2", "esp-backtrace/esp32c2", "esp-println/esp32c2"]
|
||||||
esp32c3 = ["esp-hal/esp32c3", "esp-backtrace/esp32c3", "esp-println/esp32c3", "esp-hal-smartled/esp32c3"]
|
esp32c3 = ["esp-hal/esp32c3", "esp-backtrace/esp32c3", "esp-println/esp32c3", "esp-hal-smartled/esp32c3"]
|
||||||
esp32c6 = ["esp-hal/esp32c6", "esp-backtrace/esp32c6", "esp-println/esp32c6", "esp-hal-smartled/esp32c6"]
|
esp32c6 = ["esp-hal/esp32c6", "esp-backtrace/esp32c6", "esp-println/esp32c6", "esp-hal-smartled/esp32c6", "esp-ieee802154/esp32c6"]
|
||||||
esp32h2 = ["esp-hal/esp32h2", "esp-backtrace/esp32h2", "esp-println/esp32h2", "esp-hal-smartled/esp32h2"]
|
esp32h2 = ["esp-hal/esp32h2", "esp-backtrace/esp32h2", "esp-println/esp32h2", "esp-hal-smartled/esp32h2", "esp-ieee802154/esp32h2"]
|
||||||
esp32s2 = ["esp-hal/esp32s2", "esp-backtrace/esp32s2", "esp-println/esp32s2", "esp-hal-smartled/esp32s2"]
|
esp32s2 = ["esp-hal/esp32s2", "esp-backtrace/esp32s2", "esp-println/esp32s2", "esp-hal-smartled/esp32s2"]
|
||||||
esp32s3 = ["esp-hal/esp32s3", "esp-backtrace/esp32s3", "esp-println/esp32s3", "esp-hal-smartled/esp32s3"]
|
esp32s3 = ["esp-hal/esp32s3", "esp-backtrace/esp32s3", "esp-println/esp32s3", "esp-hal-smartled/esp32s3"]
|
||||||
|
|
||||||
|
|||||||
7
examples/build.rs
Normal file
7
examples/build.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
fn main() {
|
||||||
|
if cfg!(feature = "esp32c6") || cfg!(feature = "esp32h2") {
|
||||||
|
println!("cargo::rustc-link-arg=-Trom_coexist.x");
|
||||||
|
println!("cargo::rustc-link-arg=-Trom_functions.x");
|
||||||
|
println!("cargo::rustc-link-arg=-Trom_phy.x");
|
||||||
|
}
|
||||||
|
}
|
||||||
33
examples/src/bin/ieee802154_receive_all_frames.rs
Normal file
33
examples/src/bin/ieee802154_receive_all_frames.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//% CHIPS: esp32c6 esp32h2
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use esp_backtrace as _;
|
||||||
|
use esp_hal::{peripherals::Peripherals, prelude::*};
|
||||||
|
use esp_ieee802154::*;
|
||||||
|
use esp_println::println;
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
let mut peripherals = Peripherals::take();
|
||||||
|
let mut ieee802154 = Ieee802154::new(peripherals.IEEE802154, &mut peripherals.RADIO_CLK);
|
||||||
|
|
||||||
|
ieee802154.set_config(Config {
|
||||||
|
channel: 15,
|
||||||
|
promiscuous: true,
|
||||||
|
rx_when_idle: true,
|
||||||
|
auto_ack_rx: false,
|
||||||
|
auto_ack_tx: false,
|
||||||
|
..Config::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
println!("Start receiving:");
|
||||||
|
ieee802154.start_receive();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Some(frame) = ieee802154.get_received() {
|
||||||
|
println!("Received {:?}\n", &frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
examples/src/bin/ieee802154_receive_frame.rs
Normal file
35
examples/src/bin/ieee802154_receive_frame.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
//% CHIPS: esp32c6 esp32h2
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use esp_backtrace as _;
|
||||||
|
use esp_hal::{peripherals::Peripherals, prelude::*};
|
||||||
|
use esp_ieee802154::*;
|
||||||
|
use esp_println::println;
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
let mut peripherals = Peripherals::take();
|
||||||
|
let mut ieee802154 = Ieee802154::new(peripherals.IEEE802154, &mut peripherals.RADIO_CLK);
|
||||||
|
|
||||||
|
ieee802154.set_config(Config {
|
||||||
|
channel: 15,
|
||||||
|
promiscuous: false,
|
||||||
|
rx_when_idle: true,
|
||||||
|
auto_ack_rx: true,
|
||||||
|
auto_ack_tx: true,
|
||||||
|
pan_id: Some(0x4242),
|
||||||
|
short_addr: Some(0x2323),
|
||||||
|
..Config::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
println!("Start receiving:");
|
||||||
|
ieee802154.start_receive();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if let Some(frame) = ieee802154.get_received() {
|
||||||
|
println!("Received {:?}\n", &frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
71
examples/src/bin/ieee802154_send_broadcast_frame.rs
Normal file
71
examples/src/bin/ieee802154_send_broadcast_frame.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
//% CHIPS: esp32c6 esp32h2
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use esp_backtrace as _;
|
||||||
|
use esp_hal::{
|
||||||
|
clock::ClockControl,
|
||||||
|
delay::Delay,
|
||||||
|
peripherals::Peripherals,
|
||||||
|
prelude::*,
|
||||||
|
system::SystemControl,
|
||||||
|
};
|
||||||
|
use esp_ieee802154::*;
|
||||||
|
use esp_println::println;
|
||||||
|
use ieee802154::mac::{
|
||||||
|
Address,
|
||||||
|
FrameContent,
|
||||||
|
FrameType,
|
||||||
|
FrameVersion,
|
||||||
|
Header,
|
||||||
|
PanId,
|
||||||
|
ShortAddress,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
let mut peripherals = Peripherals::take();
|
||||||
|
let system = SystemControl::new(peripherals.SYSTEM);
|
||||||
|
let clocks = ClockControl::max(system.clock_control).freeze();
|
||||||
|
|
||||||
|
let delay = Delay::new(&clocks);
|
||||||
|
|
||||||
|
let mut ieee802154 = Ieee802154::new(peripherals.IEEE802154, &mut peripherals.RADIO_CLK);
|
||||||
|
|
||||||
|
ieee802154.set_config(Config {
|
||||||
|
channel: 15,
|
||||||
|
promiscuous: false,
|
||||||
|
pan_id: Some(0x4242),
|
||||||
|
short_addr: Some(0x2323),
|
||||||
|
..Config::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut seq_number = 0u8;
|
||||||
|
loop {
|
||||||
|
ieee802154
|
||||||
|
.transmit(&Frame {
|
||||||
|
header: Header {
|
||||||
|
frame_type: FrameType::Data,
|
||||||
|
frame_pending: false,
|
||||||
|
ack_request: false,
|
||||||
|
pan_id_compress: false,
|
||||||
|
seq_no_suppress: false,
|
||||||
|
ie_present: false,
|
||||||
|
version: FrameVersion::Ieee802154_2003,
|
||||||
|
seq: seq_number,
|
||||||
|
destination: Some(Address::Short(PanId(0xffff), ShortAddress(0xffff))),
|
||||||
|
source: None,
|
||||||
|
auxiliary_security_header: None,
|
||||||
|
},
|
||||||
|
content: FrameContent::Data,
|
||||||
|
payload: heapless::Vec::from_slice(b"Hello World").unwrap(),
|
||||||
|
footer: [0u8; 2],
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
println!("Send frame with sequence number {seq_number}");
|
||||||
|
delay.delay_millis(1000u32);
|
||||||
|
seq_number = seq_number.wrapping_add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
71
examples/src/bin/ieee802154_send_frame.rs
Normal file
71
examples/src/bin/ieee802154_send_frame.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
//% CHIPS: esp32c6 esp32h2
|
||||||
|
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
use esp_backtrace as _;
|
||||||
|
use esp_hal::{
|
||||||
|
clock::ClockControl,
|
||||||
|
delay::Delay,
|
||||||
|
peripherals::Peripherals,
|
||||||
|
prelude::*,
|
||||||
|
system::SystemControl,
|
||||||
|
};
|
||||||
|
use esp_ieee802154::*;
|
||||||
|
use esp_println::println;
|
||||||
|
use ieee802154::mac::{
|
||||||
|
Address,
|
||||||
|
FrameContent,
|
||||||
|
FrameType,
|
||||||
|
FrameVersion,
|
||||||
|
Header,
|
||||||
|
PanId,
|
||||||
|
ShortAddress,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[entry]
|
||||||
|
fn main() -> ! {
|
||||||
|
let mut peripherals = Peripherals::take();
|
||||||
|
let system = SystemControl::new(peripherals.SYSTEM);
|
||||||
|
let clocks = ClockControl::max(system.clock_control).freeze();
|
||||||
|
|
||||||
|
let delay = Delay::new(&clocks);
|
||||||
|
|
||||||
|
let mut ieee802154 = Ieee802154::new(peripherals.IEEE802154, &mut peripherals.RADIO_CLK);
|
||||||
|
|
||||||
|
ieee802154.set_config(Config {
|
||||||
|
channel: 15,
|
||||||
|
promiscuous: false,
|
||||||
|
pan_id: Some(0x4242),
|
||||||
|
short_addr: Some(0x2222),
|
||||||
|
..Config::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut seq_number = 0u8;
|
||||||
|
loop {
|
||||||
|
ieee802154
|
||||||
|
.transmit(&Frame {
|
||||||
|
header: Header {
|
||||||
|
frame_type: FrameType::Data,
|
||||||
|
frame_pending: false,
|
||||||
|
ack_request: true,
|
||||||
|
pan_id_compress: false,
|
||||||
|
seq_no_suppress: false,
|
||||||
|
ie_present: false,
|
||||||
|
version: FrameVersion::Ieee802154_2003,
|
||||||
|
seq: seq_number,
|
||||||
|
destination: Some(Address::Short(PanId(0x4242), ShortAddress(0x2323))),
|
||||||
|
source: None,
|
||||||
|
auxiliary_security_header: None,
|
||||||
|
},
|
||||||
|
content: FrameContent::Data,
|
||||||
|
payload: heapless::Vec::from_slice(b"Hello World").unwrap(),
|
||||||
|
footer: [0u8; 2],
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
println!("Send frame with sequence number {seq_number}");
|
||||||
|
delay.delay_millis(1000u32);
|
||||||
|
seq_number = seq_number.wrapping_add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user