capsules_extra/ieee802154/
mac.rs1use crate::net::ieee802154::{Header, MacAddress};
19use kernel::hil::radio::{self, MAX_FRAME_SIZE, PSDU_OFFSET};
20use kernel::utilities::cells::OptionalCell;
21use kernel::ErrorCode;
22
23pub trait Mac<'a> {
24 fn initialize(&self) -> Result<(), ErrorCode>;
26
27 fn set_config_client(&self, client: &'a dyn radio::ConfigClient);
29 fn set_transmit_client(&self, client: &'a dyn radio::TxClient);
31 fn set_receive_client(&self, client: &'a dyn radio::RxClient);
33 fn set_receive_buffer(&self, buffer: &'static mut [u8]);
35
36 fn get_address(&self) -> u16;
38 fn get_address_long(&self) -> [u8; 8];
40 fn get_pan(&self) -> u16;
42
43 fn set_address(&self, addr: u16);
45 fn set_address_long(&self, addr: [u8; 8]);
47 fn set_pan(&self, id: u16);
49
50 fn config_commit(&self);
56
57 fn is_on(&self) -> bool;
59
60 fn start(&self) -> Result<(), ErrorCode>;
70
71 fn transmit(
74 &self,
75 full_mac_frame: &'static mut [u8],
76 frame_len: usize,
77 ) -> Result<(), (ErrorCode, &'static mut [u8])>;
78}
79
80pub struct AwakeMac<'a, R: radio::Radio<'a>> {
86 radio: &'a R,
87
88 tx_client: OptionalCell<&'a dyn radio::TxClient>,
89 rx_client: OptionalCell<&'a dyn radio::RxClient>,
90}
91
92impl<'a, R: radio::Radio<'a>> AwakeMac<'a, R> {
93 pub fn new(radio: &'a R) -> AwakeMac<'a, R> {
94 AwakeMac {
95 radio,
96 tx_client: OptionalCell::empty(),
97 rx_client: OptionalCell::empty(),
98 }
99 }
100}
101
102impl<'a, R: radio::Radio<'a>> Mac<'a> for AwakeMac<'a, R> {
103 fn initialize(&self) -> Result<(), ErrorCode> {
104 Ok(())
106 }
107
108 fn is_on(&self) -> bool {
109 self.radio.is_on()
110 }
111
112 fn start(&self) -> Result<(), ErrorCode> {
113 self.radio.start()
114 }
115
116 fn set_config_client(&self, client: &'a dyn radio::ConfigClient) {
117 self.radio.set_config_client(client)
118 }
119
120 fn set_address(&self, addr: u16) {
121 self.radio.set_address(addr)
122 }
123
124 fn set_address_long(&self, addr: [u8; 8]) {
125 self.radio.set_address_long(addr)
126 }
127
128 fn set_pan(&self, id: u16) {
129 self.radio.set_pan(id)
130 }
131
132 fn get_address(&self) -> u16 {
133 self.radio.get_address()
134 }
135
136 fn get_address_long(&self) -> [u8; 8] {
137 self.radio.get_address_long()
138 }
139
140 fn get_pan(&self) -> u16 {
141 self.radio.get_pan()
142 }
143
144 fn config_commit(&self) {
145 self.radio.config_commit()
146 }
147
148 fn set_transmit_client(&self, client: &'a dyn radio::TxClient) {
149 self.tx_client.set(client);
150 }
151
152 fn set_receive_client(&self, client: &'a dyn radio::RxClient) {
153 self.rx_client.set(client);
154 }
155
156 fn set_receive_buffer(&self, buffer: &'static mut [u8]) {
157 self.radio.set_receive_buffer(buffer);
158 }
159
160 fn transmit(
161 &self,
162 full_mac_frame: &'static mut [u8],
163 frame_len: usize,
164 ) -> Result<(), (ErrorCode, &'static mut [u8])> {
165 if full_mac_frame.len() < frame_len + PSDU_OFFSET {
170 return Err((ErrorCode::NOMEM, full_mac_frame));
171 }
172
173 if frame_len > MAX_FRAME_SIZE {
174 return Err((ErrorCode::INVAL, full_mac_frame));
175 }
176
177 full_mac_frame.copy_within(0..frame_len, PSDU_OFFSET);
178 self.radio.transmit(full_mac_frame, frame_len)
179 }
180}
181
182impl<'a, R: radio::Radio<'a>> radio::TxClient for AwakeMac<'a, R> {
183 fn send_done(&self, buf: &'static mut [u8], acked: bool, result: Result<(), ErrorCode>) {
184 self.tx_client.map(move |c| {
185 c.send_done(buf, acked, result);
186 });
187 }
188}
189
190impl<'a, R: radio::Radio<'a>> radio::RxClient for AwakeMac<'a, R> {
191 fn receive(
192 &self,
193 buf: &'static mut [u8],
194 frame_len: usize,
195 lqi: u8,
196 crc_valid: bool,
197 result: Result<(), ErrorCode>,
198 ) {
199 let mut addr_match = false;
201 if let Some((_, (header, _))) = Header::decode(&buf[radio::PSDU_OFFSET..], false).done() {
202 if let Some(dst_addr) = header.dst_addr {
203 addr_match = match dst_addr {
204 MacAddress::Short(addr) => {
205 (addr == self.radio.get_address()) || (addr == 0xFFFF)
207 }
208 MacAddress::Long(long_addr) => long_addr == self.radio.get_address_long(),
209 };
210 }
211 }
212 if addr_match {
213 self.rx_client.map(move |c| {
215 c.receive(buf, frame_len, lqi, crc_valid, result);
216 });
217 } else {
218 self.radio.set_receive_buffer(buf);
220 }
221 }
222}