1use crate::mac::frame::{
6 header::{PanId, ShortAddress},
7 DecodeError,
8};
9use crate::utils::OptionalFrom;
10use byte::{check_len, BytesExt, TryRead, TryWrite};
11
12extended_enum!(
13 CommandId, u8,
15 AssociationRequest => 1,
17 AssociationResponse => 2,
19 DisassociationNotification => 3,
21 DataRequest => 4,
23 PanIdConflictNotification => 5,
25 OrphanNotification => 6,
27 BeaconRequest => 7,
29 CoordinatorRealignment => 8,
31 GuaranteedTimeSlotRequest => 9,
33);
34
35const CAP_FFD: u8 = 0x02;
36const CAP_MAINS_POWER: u8 = 0x04;
37const CAP_IDLE_RECEIVE: u8 = 0x08;
38const CAP_FRAME_PROTECTION: u8 = 0x40;
39const CAP_ALLOCATE_ADDRESS: u8 = 0x80;
40
41#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
45#[cfg_attr(feature = "defmt", derive(defmt::Format))]
46pub struct CapabilityInformation {
47 pub full_function_device: bool,
50 pub mains_power: bool,
52 pub idle_receive: bool,
54 pub frame_protection: bool,
56 pub allocate_address: bool,
58}
59
60impl From<u8> for CapabilityInformation {
61 fn from(byte: u8) -> Self {
62 let full_function_device = byte & CAP_FFD == CAP_FFD;
63 let mains_power = byte & CAP_MAINS_POWER == CAP_MAINS_POWER;
64 let idle_receive = byte & CAP_IDLE_RECEIVE == CAP_IDLE_RECEIVE;
65 let frame_protection =
66 byte & CAP_FRAME_PROTECTION == CAP_FRAME_PROTECTION;
67 let allocate_address =
68 byte & CAP_ALLOCATE_ADDRESS == CAP_ALLOCATE_ADDRESS;
69 Self {
70 full_function_device,
71 mains_power,
72 idle_receive,
73 frame_protection,
74 allocate_address,
75 }
76 }
77}
78
79impl From<CapabilityInformation> for u8 {
80 fn from(ar: CapabilityInformation) -> Self {
81 let mut byte = 0u8;
82 if ar.full_function_device {
83 byte = byte | CAP_FFD;
84 }
85 if ar.mains_power {
86 byte = byte | CAP_MAINS_POWER;
87 }
88 if ar.idle_receive {
89 byte = byte | CAP_IDLE_RECEIVE;
90 }
91 if ar.frame_protection {
92 byte = byte | CAP_FRAME_PROTECTION;
93 }
94 if ar.allocate_address {
95 byte = byte | CAP_ALLOCATE_ADDRESS;
96 }
97 byte
98 }
99}
100
101extended_enum!(
102 AssociationStatus, u8,
104 Successful => 0x00,
106 NetworkAtCapacity => 0x01,
108 AccessDenied => 0x02,
110 HoppingSequenceOffsetDuplication => 0x03,
112 FastAssociationSuccesful => 0x80,
114);
115
116extended_enum!(
117 DisassociationReason, u8,
119 CoordinatorLeave => 1,
121 DeviceLeave => 2,
123);
124
125#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
129#[cfg_attr(feature = "defmt", derive(defmt::Format))]
130pub struct CoordinatorRealignmentData {
131 pub pan_id: PanId,
133 pub coordinator_address: ShortAddress,
135 pub channel: u8,
137 pub device_address: ShortAddress,
139 pub channel_page: Option<u8>,
141}
142
143impl TryWrite for CoordinatorRealignmentData {
144 fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
145 let offset = &mut 0;
146 bytes.write(offset, self.pan_id)?;
147 bytes.write(offset, self.coordinator_address)?;
148 bytes.write(offset, self.channel)?;
149 bytes.write(offset, self.device_address)?;
150 if let Some(channel_page) = self.channel_page {
151 bytes.write(offset, channel_page)?;
152 }
153 Ok(*offset)
154 }
155}
156
157impl TryRead<'_> for CoordinatorRealignmentData {
158 fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
159 let offset = &mut 0;
160 check_len(&bytes, 7)?;
161 let pan_id = bytes.read(offset)?;
162 let coordinator_address = bytes.read(offset)?;
163 let channel = bytes.read(offset)?;
164 let device_address = bytes.read(offset)?;
165 let channel_page = if bytes.len() > *offset {
166 Some(bytes.read(offset)?)
167 } else {
168 None
169 };
170 Ok((
171 Self {
172 pan_id,
173 coordinator_address,
174 channel,
175 device_address,
176 channel_page,
177 },
178 *offset,
179 ))
180 }
181}
182
183const GTSC_RECEIVE_ONLY: u8 = 0x10;
184const GTSC_ALLOCATION: u8 = 0x20;
185
186#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
190#[cfg_attr(feature = "defmt", derive(defmt::Format))]
191pub struct GuaranteedTimeSlotCharacteristics {
192 pub count: u8,
194 pub receive_only: bool,
196 pub allocation: bool,
198}
199
200impl From<u8> for GuaranteedTimeSlotCharacteristics {
201 fn from(byte: u8) -> Self {
202 let receive_only = byte & GTSC_RECEIVE_ONLY == GTSC_RECEIVE_ONLY;
203 let allocation = byte & GTSC_ALLOCATION == GTSC_ALLOCATION;
204 Self {
205 count: (byte & 0x0f),
206 receive_only,
207 allocation,
208 }
209 }
210}
211
212impl From<GuaranteedTimeSlotCharacteristics> for u8 {
213 fn from(gtsc: GuaranteedTimeSlotCharacteristics) -> Self {
214 let mut byte = gtsc.count & 0x0f;
215 if gtsc.receive_only {
216 byte = byte | GTSC_RECEIVE_ONLY;
217 }
218 if gtsc.allocation {
219 byte = byte | GTSC_ALLOCATION;
220 }
221 byte
222 }
223}
224
225#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
227#[cfg_attr(feature = "defmt", derive(defmt::Format))]
228pub enum Command {
229 AssociationRequest(CapabilityInformation),
231 AssociationResponse(ShortAddress, AssociationStatus),
233 DisassociationNotification(DisassociationReason),
235 DataRequest,
237 PanIdConflictNotification,
239 OrphanNotification,
241 BeaconRequest,
243 CoordinatorRealignment(CoordinatorRealignmentData),
245 GuaranteedTimeSlotRequest(GuaranteedTimeSlotCharacteristics),
247}
248
249impl TryWrite for Command {
250 fn try_write(self, bytes: &mut [u8], _ctx: ()) -> byte::Result<usize> {
251 let offset = &mut 0;
252 match self {
253 Command::AssociationRequest(capability) => {
254 bytes.write(offset, u8::from(CommandId::AssociationRequest))?;
255 bytes.write(offset, u8::from(capability))?;
256 }
257 Command::AssociationResponse(address, status) => {
258 bytes
259 .write(offset, u8::from(CommandId::AssociationResponse))?;
260 bytes.write(offset, address)?;
261 bytes.write(offset, u8::from(status))?;
262 }
263 Command::DisassociationNotification(reason) => {
264 bytes.write(
265 offset,
266 u8::from(CommandId::DisassociationNotification),
267 )?;
268 bytes.write(offset, u8::from(reason))?;
269 }
270 Command::DataRequest => {
271 bytes.write(offset, u8::from(CommandId::DataRequest))?;
272 }
273 Command::PanIdConflictNotification => {
274 bytes.write(
275 offset,
276 u8::from(CommandId::PanIdConflictNotification),
277 )?;
278 }
279 Command::OrphanNotification => {
280 bytes.write(offset, u8::from(CommandId::OrphanNotification))?;
281 }
282 Command::BeaconRequest => {
283 bytes.write(offset, u8::from(CommandId::BeaconRequest))?;
284 }
285 Command::CoordinatorRealignment(data) => {
286 bytes.write(
287 offset,
288 u8::from(CommandId::CoordinatorRealignment),
289 )?;
290 bytes.write(offset, data)?;
291 }
292 Command::GuaranteedTimeSlotRequest(characteristics) => {
293 bytes.write(
294 offset,
295 u8::from(CommandId::GuaranteedTimeSlotRequest),
296 )?;
297 bytes.write(offset, u8::from(characteristics))?;
298 }
299 }
300 Ok(*offset)
301 }
302}
303
304impl TryRead<'_> for Command {
305 fn try_read(bytes: &[u8], _ctx: ()) -> byte::Result<(Self, usize)> {
306 let offset = &mut 0;
307 let cmd = CommandId::optional_from(bytes.read::<u8>(offset)?)
308 .ok_or(DecodeError::InvalidValue)?;
309 Ok((
310 match cmd {
311 CommandId::AssociationRequest => {
312 let capability =
313 CapabilityInformation::from(bytes.read::<u8>(offset)?);
314 Command::AssociationRequest(capability)
315 }
316 CommandId::AssociationResponse => {
317 let address: ShortAddress = bytes.read(offset)?;
318 let status =
319 AssociationStatus::optional_from(bytes.read(offset)?)
320 .ok_or(DecodeError::InvalidValue)?;
321 Command::AssociationResponse(address, status)
322 }
323 CommandId::DisassociationNotification => {
324 let reason = DisassociationReason::optional_from(
325 bytes.read(offset)?,
326 )
327 .ok_or(DecodeError::InvalidValue)?;
328 Command::DisassociationNotification(reason)
329 }
330 CommandId::DataRequest => Command::DataRequest,
331 CommandId::PanIdConflictNotification => {
332 Command::PanIdConflictNotification
333 }
334 CommandId::OrphanNotification => Command::OrphanNotification,
335 CommandId::BeaconRequest => Command::BeaconRequest,
336 CommandId::CoordinatorRealignment => {
337 Command::CoordinatorRealignment(bytes.read(offset)?)
338 }
339 CommandId::GuaranteedTimeSlotRequest => {
340 let characteristics =
341 GuaranteedTimeSlotCharacteristics::from(
342 bytes.read::<u8>(offset)?,
343 );
344 Command::GuaranteedTimeSlotRequest(characteristics)
345 }
346 },
347 *offset,
348 ))
349 }
350}
351
352#[cfg(test)]
353mod tests {
354 use super::*;
355
356 #[test]
357 fn decode_association_request() {
358 let data = [0x01, 0x8e];
359 let mut len = 0usize;
360 let command: Command = data.read(&mut len).unwrap();
361 assert_eq!(len, data.len());
362 assert_eq!(
363 command,
364 Command::AssociationRequest(CapabilityInformation {
365 full_function_device: true,
366 mains_power: true,
367 idle_receive: true,
368 frame_protection: false,
369 allocate_address: true,
370 })
371 );
372 }
373
374 #[test]
375 fn encode_association_request() {
376 let command = Command::AssociationRequest(CapabilityInformation {
377 full_function_device: false,
378 mains_power: false,
379 idle_receive: false,
380 frame_protection: false,
381 allocate_address: false,
382 });
383 let mut data = [0u8; 32];
384 let mut len = 0usize;
385 data.write(&mut len, command).unwrap();
386
387 assert_eq!(len, 2);
388 assert_eq!(data[..len], [0x01, 0x00]);
389
390 let command = Command::AssociationRequest(CapabilityInformation {
391 full_function_device: true,
392 mains_power: false,
393 idle_receive: false,
394 frame_protection: false,
395 allocate_address: false,
396 });
397 let mut len = 0usize;
398 data.write(&mut len, command).unwrap();
399
400 assert_eq!(len, 2);
401 assert_eq!(data[..len], [0x01, 0x02]);
402
403 let command = Command::AssociationRequest(CapabilityInformation {
404 full_function_device: false,
405 mains_power: true,
406 idle_receive: false,
407 frame_protection: false,
408 allocate_address: false,
409 });
410 let mut len = 0usize;
411 data.write(&mut len, command).unwrap();
412
413 assert_eq!(len, 2);
414 assert_eq!(data[..len], [0x01, 0x04]);
415
416 let command = Command::AssociationRequest(CapabilityInformation {
417 full_function_device: false,
418 mains_power: false,
419 idle_receive: true,
420 frame_protection: false,
421 allocate_address: false,
422 });
423 let mut len = 0usize;
424 data.write(&mut len, command).unwrap();
425
426 assert_eq!(len, 2);
427 assert_eq!(data[..len], [0x01, 0x08]);
428
429 let command = Command::AssociationRequest(CapabilityInformation {
430 full_function_device: false,
431 mains_power: false,
432 idle_receive: false,
433 frame_protection: true,
434 allocate_address: false,
435 });
436 let mut len = 0usize;
437 data.write(&mut len, command).unwrap();
438
439 assert_eq!(len, 2);
440 assert_eq!(data[..len], [0x01, 0x40]);
441
442 let command = Command::AssociationRequest(CapabilityInformation {
443 full_function_device: false,
444 mains_power: false,
445 idle_receive: false,
446 frame_protection: false,
447 allocate_address: true,
448 });
449 let mut len = 0usize;
450 data.write(&mut len, command).unwrap();
451
452 assert_eq!(len, 2);
453 assert_eq!(data[..len], [0x01, 0x80]);
454 }
455
456 #[test]
457 fn decode_association_response() {
458 let data = [0x02, 0x40, 0x77, 0x00];
459 let mut len = 0usize;
460 let command: Command = data.read(&mut len).unwrap();
461 assert_eq!(len, data.len());
462 assert_eq!(
463 command,
464 Command::AssociationResponse(
465 ShortAddress(0x7740),
466 AssociationStatus::Successful
467 )
468 );
469
470 let data = [0x02, 0xaa, 0x55, 0x01];
471 let mut len = 0usize;
472 let command: Command = data.read(&mut len).unwrap();
473 assert_eq!(len, data.len());
474 assert_eq!(
475 command,
476 Command::AssociationResponse(
477 ShortAddress(0x55aa),
478 AssociationStatus::NetworkAtCapacity
479 )
480 );
481
482 let data = [0x02, 0x00, 0x00, 0x02];
483 let mut len = 0usize;
484 let command: Command = data.read(&mut len).unwrap();
485 assert_eq!(len, data.len());
486 assert_eq!(
487 command,
488 Command::AssociationResponse(
489 ShortAddress(0x0000),
490 AssociationStatus::AccessDenied
491 )
492 );
493
494 let data = [0x02, 0x00, 0x00, 0x03];
495 let mut len = 0usize;
496 let command: Command = data.read(&mut len).unwrap();
497 assert_eq!(len, data.len());
498 assert_eq!(
499 command,
500 Command::AssociationResponse(
501 ShortAddress(0x0000),
502 AssociationStatus::HoppingSequenceOffsetDuplication
503 )
504 );
505
506 let data = [0x02, 0x00, 0x00, 0x80];
507 let mut len = 0usize;
508 let command: Command = data.read(&mut len).unwrap();
509 assert_eq!(len, data.len());
510 assert_eq!(
511 command,
512 Command::AssociationResponse(
513 ShortAddress(0x0000),
514 AssociationStatus::FastAssociationSuccesful
515 )
516 );
517
518 let data = [0x02, 0x00, 0x00, 0x04];
519 let result = data.read::<Command>(&mut len);
520 assert!(result.is_err());
521
522 let data = [0x02, 0x00, 0x00, 0x7f];
523 let result = data.read::<Command>(&mut len);
524 assert!(result.is_err());
525
526 let data = [0x02, 0x00, 0x00, 0x81];
527 let result = data.read::<Command>(&mut len);
528 assert!(result.is_err());
529 }
530
531 #[test]
532 fn encode_association_response() {
533 let mut data = [0u8; 4];
534 let command = Command::AssociationResponse(
535 ShortAddress(0x55aa),
536 AssociationStatus::Successful,
537 );
538 let mut len = 0usize;
539 data.write(&mut len, command).unwrap();
540
541 assert_eq!(len, data.len());
542 assert_eq!(data[..len], [0x02, 0xaa, 0x55, 0x00]);
543
544 let command = Command::AssociationResponse(
545 ShortAddress(0x1234),
546 AssociationStatus::NetworkAtCapacity,
547 );
548 let mut len = 0usize;
549 data.write(&mut len, command).unwrap();
550
551 assert_eq!(len, data.len());
552 assert_eq!(data[..len], [0x02, 0x34, 0x12, 0x01]);
553
554 let command = Command::AssociationResponse(
555 ShortAddress(0xcffe),
556 AssociationStatus::AccessDenied,
557 );
558 let mut len = 0usize;
559 data.write(&mut len, command).unwrap();
560
561 assert_eq!(len, data.len());
562 assert_eq!(data[..len], [0x02, 0xfe, 0xcf, 0x02]);
563
564 let command = Command::AssociationResponse(
565 ShortAddress(0xfedc),
566 AssociationStatus::HoppingSequenceOffsetDuplication,
567 );
568 let mut len = 0usize;
569 data.write(&mut len, command).unwrap();
570
571 assert_eq!(len, data.len());
572 assert_eq!(data[..len], [0x02, 0xdc, 0xfe, 0x03]);
573
574 let command = Command::AssociationResponse(
575 ShortAddress(0x0ff0),
576 AssociationStatus::FastAssociationSuccesful,
577 );
578 let mut len = 0usize;
579 data.write(&mut len, command).unwrap();
580
581 assert_eq!(len, data.len());
582 assert_eq!(data[..len], [0x02, 0xf0, 0x0f, 0x80]);
583 }
584
585 #[test]
586 fn decode_disassociation_notification() {
587 let data = [0x03, 0x01];
588 let mut len = 0usize;
589 let command: Command = data.read(&mut len).unwrap();
590 assert_eq!(len, data.len());
591 assert_eq!(
592 command,
593 Command::DisassociationNotification(
594 DisassociationReason::CoordinatorLeave
595 )
596 );
597
598 let data = [0x03, 0x02];
599 let mut len = 0usize;
600 let command: Command = data.read(&mut len).unwrap();
601 assert_eq!(len, data.len());
602 assert_eq!(
603 command,
604 Command::DisassociationNotification(
605 DisassociationReason::DeviceLeave
606 )
607 );
608
609 let data = [0x03, 0x00];
610 let result = data.read::<Command>(&mut len);
611 assert!(result.is_err());
612
613 let data = [0x03, 0x03];
614 let result = data.read::<Command>(&mut len);
615 assert!(result.is_err());
616 }
617
618 #[test]
619 fn encode_disassociation_notification() {
620 let mut data = [0u8; 32];
621
622 let command = Command::DisassociationNotification(
623 DisassociationReason::CoordinatorLeave,
624 );
625 let mut len = 0usize;
626 data.write(&mut len, command).unwrap();
627
628 assert_eq!(len, 2);
629 assert_eq!(data[..len], [0x03, 0x01]);
630
631 let command = Command::DisassociationNotification(
632 DisassociationReason::DeviceLeave,
633 );
634 let mut len = 0usize;
635 data.write(&mut len, command).unwrap();
636
637 assert_eq!(len, 2);
638 assert_eq!(data[..len], [0x03, 0x02]);
639 }
640
641 #[test]
642 fn decode_coordinator_realignment() {
643 let data = [0x08, 0x23, 0x11, 0x01, 0x00, 0x0f, 0x34, 0x12];
644 let mut len = 0usize;
645 let command: Command = data.read(&mut len).unwrap();
646 assert_eq!(len, data.len());
647 assert_eq!(
648 command,
649 Command::CoordinatorRealignment(CoordinatorRealignmentData {
650 pan_id: PanId(0x1123),
651 coordinator_address: ShortAddress(0x0001),
652 channel: 15,
653 device_address: ShortAddress(0x1234),
654 channel_page: None,
655 })
656 );
657
658 let data = [0x08, 0x34, 0x12, 0x21, 0x43, 0x0b, 0xcd, 0xab, 0x01];
659 let mut len = 0usize;
660 let command: Command = data.read(&mut len).unwrap();
661 assert_eq!(len, data.len());
662 assert_eq!(
663 command,
664 Command::CoordinatorRealignment(CoordinatorRealignmentData {
665 pan_id: PanId(0x1234),
666 coordinator_address: ShortAddress(0x4321),
667 channel: 11,
668 device_address: ShortAddress(0xabcd),
669 channel_page: Some(1),
670 })
671 );
672 }
673
674 #[test]
675 fn encode_coordinator_realignment() {
676 let mut data = [0u8; 32];
677
678 let command =
679 Command::CoordinatorRealignment(CoordinatorRealignmentData {
680 pan_id: PanId(0x1123),
681 coordinator_address: ShortAddress(0x0001),
682 channel: 15,
683 device_address: ShortAddress(0x1234),
684 channel_page: None,
685 });
686 let mut len = 0usize;
687 data.write(&mut len, command).unwrap();
688
689 assert_eq!(len, 8);
690 assert_eq!(
691 &data[..len],
692 [0x08, 0x23, 0x11, 0x01, 0x00, 0x0f, 0x34, 0x12]
693 );
694
695 let command =
696 Command::CoordinatorRealignment(CoordinatorRealignmentData {
697 pan_id: PanId(0xbeef),
698 coordinator_address: ShortAddress(0xfeed),
699 channel: 26,
700 device_address: ShortAddress(0x1234),
701 channel_page: Some(15),
702 });
703 let mut len = 0usize;
704 data.write(&mut len, command).unwrap();
705
706 assert_eq!(len, 9);
707 assert_eq!(
708 &data[..len],
709 [0x08, 0xef, 0xbe, 0xed, 0xfe, 0x1a, 0x34, 0x12, 0x0f]
710 );
711 }
712
713 #[test]
714 fn decode_guaranteed_time_slot_request() {
715 let data = [0x09, 0x01];
716 let mut len = 0usize;
717 let command: Command = data.read(&mut len).unwrap();
718 assert_eq!(len, data.len());
719 assert_eq!(
720 command,
721 Command::GuaranteedTimeSlotRequest(
722 GuaranteedTimeSlotCharacteristics {
723 count: 1,
724 receive_only: false,
725 allocation: false,
726 }
727 )
728 );
729
730 let data = [0x09, 0x12];
731 let mut len = 0usize;
732 let command: Command = data.read(&mut len).unwrap();
733 assert_eq!(len, data.len());
734 assert_eq!(
735 command,
736 Command::GuaranteedTimeSlotRequest(
737 GuaranteedTimeSlotCharacteristics {
738 count: 2,
739 receive_only: true,
740 allocation: false,
741 }
742 )
743 );
744
745 let data = [0x09, 0x23];
746 let mut len = 0usize;
747 let command: Command = data.read(&mut len).unwrap();
748 assert_eq!(len, data.len());
749 assert_eq!(
750 command,
751 Command::GuaranteedTimeSlotRequest(
752 GuaranteedTimeSlotCharacteristics {
753 count: 3,
754 receive_only: false,
755 allocation: true,
756 }
757 )
758 );
759 }
760
761 #[test]
762 fn encode_guaranteed_time_slot_request() {
763 let mut data = [0u8; 32];
764
765 let command = Command::GuaranteedTimeSlotRequest(
766 GuaranteedTimeSlotCharacteristics {
767 count: 1,
768 receive_only: false,
769 allocation: false,
770 },
771 );
772 let mut len = 0usize;
773 data.write(&mut len, command).unwrap();
774
775 assert_eq!(len, 2);
776
777 assert_eq!(data[..len], [0x09, 0x01]);
778
779 let command = Command::GuaranteedTimeSlotRequest(
780 GuaranteedTimeSlotCharacteristics {
781 count: 15,
782 receive_only: true,
783 allocation: false,
784 },
785 );
786 let mut len = 0usize;
787 data.write(&mut len, command).unwrap();
788
789 assert_eq!(len, 2);
790 assert_eq!(data[..len], [0x09, 0x1f]);
791
792 let command = Command::GuaranteedTimeSlotRequest(
793 GuaranteedTimeSlotCharacteristics {
794 count: 15,
795 receive_only: false,
796 allocation: true,
797 },
798 );
799 let mut len = 0usize;
800 data.write(&mut len, command).unwrap();
801
802 assert_eq!(len, 2);
803 assert_eq!(data[..len], [0x09, 0x2f]);
804 }
805
806 #[test]
807 fn decode_other_commands() {
808 let data = [0x04];
809 let mut len = 0usize;
810 let command: Command = data.read(&mut len).unwrap();
811 assert_eq!(len, data.len());
812 assert_eq!(command, Command::DataRequest);
813
814 let data = [0x05];
815 let mut len = 0usize;
816 let command: Command = data.read(&mut len).unwrap();
817 assert_eq!(len, data.len());
818 assert_eq!(command, Command::PanIdConflictNotification);
819
820 let data = [0x06];
821 let mut len = 0usize;
822 let command: Command = data.read(&mut len).unwrap();
823 assert_eq!(len, data.len());
824 assert_eq!(command, Command::OrphanNotification);
825
826 let data = [0x07];
827 let mut len = 0usize;
828 let command: Command = data.read(&mut len).unwrap();
829 assert_eq!(len, data.len());
830 assert_eq!(command, Command::BeaconRequest);
831 }
832
833 #[test]
834 fn encode_other_commands() {
835 let mut data = [0u8; 32];
836
837 let command = Command::DataRequest;
838 let mut len = 0usize;
839 data.write(&mut len, command).unwrap();
840
841 assert_eq!(len, 1);
842 assert_eq!(data[..len], [0x04]);
843
844 let command = Command::PanIdConflictNotification;
845 let mut len = 0usize;
846 data.write(&mut len, command).unwrap();
847
848 assert_eq!(len, 1);
849 assert_eq!(data[..len], [0x05]);
850
851 let command = Command::OrphanNotification;
852 let mut len = 0usize;
853 data.write(&mut len, command).unwrap();
854
855 assert_eq!(len, 1);
856 assert_eq!(data[..len], [0x06]);
857
858 let command = Command::BeaconRequest;
859 let mut len = 0usize;
860 data.write(&mut len, command).unwrap();
861
862 assert_eq!(len, 1);
863 assert_eq!(data[..len], [0x07]);
864 }
865}