1#![allow(dead_code)]
12
13#[cfg(feature = "alloc")]
14use alloc::collections::BTreeMap;
15#[cfg(feature = "alloc")]
16use alloc::string::String;
17#[cfg(feature = "alloc")]
18use alloc::vec::Vec;
19
20use crate::error::KernelError;
21
22#[derive(Debug, Clone, PartialEq, Eq)]
28pub enum SdpAttribute {
29 Nil,
31 Uint8(u8),
33 Uint16(u16),
35 Uint32(u32),
37 Int8(i8),
39 Int16(i16),
41 Int32(i32),
43 Uuid16(u16),
45 Uuid128([u8; 16]),
47 #[cfg(feature = "alloc")]
49 Text(String),
50 Bool(bool),
52 #[cfg(feature = "alloc")]
54 Sequence(Vec<SdpAttribute>),
55}
56
57impl SdpAttribute {
58 pub(crate) fn is_nil(&self) -> bool {
60 matches!(self, Self::Nil)
61 }
62
63 pub(crate) fn as_u16(&self) -> Option<u16> {
65 match self {
66 Self::Uint16(v) => Some(*v),
67 Self::Uint8(v) => Some(*v as u16),
68 _ => None,
69 }
70 }
71
72 pub(crate) fn as_uuid16(&self) -> Option<u16> {
74 match self {
75 Self::Uuid16(v) => Some(*v),
76 _ => None,
77 }
78 }
79}
80
81pub const ATTR_SERVICE_RECORD_HANDLE: u16 = 0x0000;
87
88pub const ATTR_SERVICE_CLASS_ID_LIST: u16 = 0x0001;
90
91pub const ATTR_PROTOCOL_DESCRIPTOR_LIST: u16 = 0x0004;
93
94pub const ATTR_BROWSE_GROUP_LIST: u16 = 0x0005;
96
97pub const ATTR_PROFILE_DESCRIPTOR_LIST: u16 = 0x0009;
99
100pub const ATTR_SERVICE_NAME: u16 = 0x0100;
102
103pub const ATTR_SERVICE_DESCRIPTION: u16 = 0x0101;
105
106pub const UUID_L2CAP: u16 = 0x0100;
112
113pub const UUID_RFCOMM: u16 = 0x0003;
115
116pub const UUID_SDP: u16 = 0x0001;
118
119pub const UUID_OBEX: u16 = 0x0008;
121
122pub const UUID_SERIAL_PORT: u16 = 0x1101;
124
125pub const UUID_OBEX_PUSH: u16 = 0x1105;
127
128pub const UUID_A2DP_SOURCE: u16 = 0x110A;
130
131pub const UUID_A2DP_SINK: u16 = 0x110B;
133
134pub const UUID_AVRCP_TARGET: u16 = 0x110C;
136
137pub const UUID_AVRCP_CONTROLLER: u16 = 0x110E;
139
140pub const UUID_HFP_AG: u16 = 0x111F;
142
143pub const UUID_HFP_HF: u16 = 0x111E;
145
146pub const UUID_HID: u16 = 0x1124;
148
149pub const UUID_PNP_INFO: u16 = 0x1200;
151
152pub const UUID_PUBLIC_BROWSE_GROUP: u16 = 0x1002;
154
155#[cfg(feature = "alloc")]
161#[derive(Debug, Clone)]
162pub struct SdpRecord {
163 pub handle: u32,
165 pub service_class_uuid: u16,
167 pub protocol_list: Vec<u16>,
169 pub profile_list: Vec<(u16, u16)>,
171 pub service_name: String,
173 pub attributes: BTreeMap<u16, SdpAttribute>,
175}
176
177#[cfg(feature = "alloc")]
178impl SdpRecord {
179 pub fn new(handle: u32, service_class_uuid: u16, name: &str) -> Self {
181 Self {
182 handle,
183 service_class_uuid,
184 protocol_list: Vec::new(),
185 profile_list: Vec::new(),
186 service_name: String::from(name),
187 attributes: BTreeMap::new(),
188 }
189 }
190
191 pub(crate) fn add_protocol(&mut self, uuid: u16) {
193 self.protocol_list.push(uuid);
194 }
195
196 pub(crate) fn add_profile(&mut self, uuid: u16, version: u16) {
198 self.profile_list.push((uuid, version));
199 }
200
201 pub(crate) fn set_attribute(&mut self, id: u16, value: SdpAttribute) {
203 self.attributes.insert(id, value);
204 }
205
206 pub(crate) fn get_attribute(&self, id: u16) -> Option<&SdpAttribute> {
208 self.attributes.get(&id)
209 }
210
211 pub(crate) fn matches_uuid(&self, uuid: u16) -> bool {
213 self.service_class_uuid == uuid
214 }
215}
216
217#[cfg(feature = "alloc")]
223pub struct SdpDatabase {
224 records: Vec<SdpRecord>,
226 next_handle: u32,
228}
229
230#[cfg(feature = "alloc")]
231impl Default for SdpDatabase {
232 fn default() -> Self {
233 Self::new()
234 }
235}
236
237#[cfg(feature = "alloc")]
238impl SdpDatabase {
239 pub fn new() -> Self {
241 Self {
242 records: Vec::new(),
243 next_handle: 0x00010001, }
245 }
246
247 pub(crate) fn record_count(&self) -> usize {
249 self.records.len()
250 }
251
252 pub(crate) fn register_service(&mut self, service_class_uuid: u16, name: &str) -> u32 {
256 let handle = self.next_handle;
257 self.next_handle += 1;
258 let record = SdpRecord::new(handle, service_class_uuid, name);
259 self.records.push(record);
260 handle
261 }
262
263 pub(crate) fn register_record(&mut self, mut record: SdpRecord) -> u32 {
265 let handle = self.next_handle;
266 self.next_handle += 1;
267 record.handle = handle;
268 self.records.push(record);
269 handle
270 }
271
272 pub(crate) fn remove_service(&mut self, handle: u32) -> bool {
274 let initial_len = self.records.len();
275 self.records.retain(|r| r.handle != handle);
276 self.records.len() < initial_len
277 }
278
279 pub(crate) fn find_by_uuid(&self, uuid: u16) -> Option<&SdpRecord> {
281 self.records.iter().find(|r| r.matches_uuid(uuid))
282 }
283
284 pub(crate) fn search(&self, uuid: u16) -> Vec<&SdpRecord> {
286 self.records
287 .iter()
288 .filter(|r| r.matches_uuid(uuid))
289 .collect()
290 }
291
292 pub(crate) fn get_by_handle(&self, handle: u32) -> Option<&SdpRecord> {
294 self.records.iter().find(|r| r.handle == handle)
295 }
296
297 pub(crate) fn get_by_handle_mut(&mut self, handle: u32) -> Option<&mut SdpRecord> {
299 self.records.iter_mut().find(|r| r.handle == handle)
300 }
301}
302
303#[derive(Debug, Clone, Copy, PartialEq, Eq)]
309#[repr(u8)]
310pub enum A2dpCodec {
311 Sbc = 0x00,
313 Mpeg12 = 0x01,
315 Aac = 0x02,
317 Atrac = 0x04,
319 VendorSpecific = 0xFF,
321}
322
323impl A2dpCodec {
324 pub(crate) fn from_u8(val: u8) -> Option<Self> {
326 match val {
327 0x00 => Some(Self::Sbc),
328 0x01 => Some(Self::Mpeg12),
329 0x02 => Some(Self::Aac),
330 0x04 => Some(Self::Atrac),
331 0xFF => Some(Self::VendorSpecific),
332 _ => None,
333 }
334 }
335}
336
337#[derive(Debug, Clone, Copy, PartialEq, Eq)]
339#[repr(u8)]
340pub enum SbcChannelMode {
341 Mono = 0x08,
343 DualChannel = 0x04,
345 Stereo = 0x02,
347 JointStereo = 0x01,
349}
350
351#[derive(Debug, Clone, Copy, PartialEq, Eq)]
353#[repr(u8)]
354pub enum SbcAllocationMethod {
355 Snr = 0x02,
357 Loudness = 0x01,
359}
360
361#[derive(Debug, Clone, Copy, PartialEq, Eq)]
363#[repr(u8)]
364pub enum SbcSampleFrequency {
365 Freq16000 = 0x80,
367 Freq32000 = 0x40,
369 Freq44100 = 0x20,
371 Freq48000 = 0x10,
373}
374
375#[derive(Debug, Clone, Copy, PartialEq, Eq)]
377pub struct SbcConfig {
378 pub subbands: u8,
380 pub block_length: u8,
382 pub allocation_method: SbcAllocationMethod,
384 pub channel_mode: SbcChannelMode,
386 pub sample_frequency: SbcSampleFrequency,
388 pub bitpool_min: u8,
390 pub bitpool_max: u8,
392}
393
394impl Default for SbcConfig {
395 fn default() -> Self {
396 Self {
397 subbands: 8,
398 block_length: 16,
399 allocation_method: SbcAllocationMethod::Loudness,
400 channel_mode: SbcChannelMode::JointStereo,
401 sample_frequency: SbcSampleFrequency::Freq44100,
402 bitpool_min: 2,
403 bitpool_max: 53,
404 }
405 }
406}
407
408impl SbcConfig {
409 pub(crate) fn validate(&self) -> Result<(), KernelError> {
411 if self.subbands != 4 && self.subbands != 8 {
412 return Err(KernelError::InvalidArgument {
413 name: "subbands",
414 value: "must be 4 or 8",
415 });
416 }
417 if !matches!(self.block_length, 4 | 8 | 12 | 16) {
418 return Err(KernelError::InvalidArgument {
419 name: "block_length",
420 value: "must be 4, 8, 12, or 16",
421 });
422 }
423 if self.bitpool_min < 2 || self.bitpool_max > 250 {
424 return Err(KernelError::InvalidArgument {
425 name: "bitpool",
426 value: "must be in range 2-250",
427 });
428 }
429 if self.bitpool_min > self.bitpool_max {
430 return Err(KernelError::InvalidArgument {
431 name: "bitpool_min",
432 value: "must not exceed bitpool_max",
433 });
434 }
435 Ok(())
436 }
437
438 #[allow(clippy::wrong_self_convention)]
440 pub(crate) fn to_bytes(&self) -> [u8; 4] {
441 let mut bytes = [0u8; 4];
442 bytes[0] = (self.sample_frequency as u8) | (self.channel_mode as u8);
444 let bl = match self.block_length {
446 4 => 0x80u8,
447 8 => 0x40,
448 12 => 0x20,
449 16 => 0x10,
450 _ => 0x10,
451 };
452 let sb = if self.subbands == 4 { 0x08u8 } else { 0x04 };
453 bytes[1] = bl | sb | (self.allocation_method as u8);
454 bytes[2] = self.bitpool_min;
456 bytes[3] = self.bitpool_max;
458 bytes
459 }
460}
461
462#[derive(Debug, Clone, Copy)]
464pub struct A2dpEndpoint {
465 pub codec: A2dpCodec,
467 pub sample_rate: u32,
469 pub channels: u8,
471 pub bitpool_min: u8,
473 pub bitpool_max: u8,
475}
476
477impl Default for A2dpEndpoint {
478 fn default() -> Self {
479 Self {
480 codec: A2dpCodec::Sbc,
481 sample_rate: 44100,
482 channels: 2,
483 bitpool_min: 2,
484 bitpool_max: 53,
485 }
486 }
487}
488
489#[derive(Debug, Clone, Copy, PartialEq, Eq)]
491pub enum A2dpState {
492 Idle,
494 Configured,
496 Streaming,
498 Suspended,
500}
501
502pub struct A2dpSink {
504 pub endpoint: A2dpEndpoint,
506 pub sbc_config: SbcConfig,
508 pub state: A2dpState,
510 pub seid: u8,
512 pub transport_cid: u16,
514}
515
516impl Default for A2dpSink {
517 fn default() -> Self {
518 Self::new()
519 }
520}
521
522impl A2dpSink {
523 pub fn new() -> Self {
525 Self {
526 endpoint: A2dpEndpoint::default(),
527 sbc_config: SbcConfig::default(),
528 state: A2dpState::Idle,
529 seid: 1,
530 transport_cid: 0,
531 }
532 }
533
534 pub(crate) fn configure(
536 &mut self,
537 codec: A2dpCodec,
538 sample_rate: u32,
539 channels: u8,
540 ) -> Result<(), KernelError> {
541 if self.state != A2dpState::Idle && self.state != A2dpState::Configured {
542 return Err(KernelError::InvalidState {
543 expected: "Idle or Configured",
544 actual: "Streaming or Suspended",
545 });
546 }
547 if channels == 0 || channels > 2 {
548 return Err(KernelError::InvalidArgument {
549 name: "channels",
550 value: "must be 1 or 2",
551 });
552 }
553
554 self.endpoint.codec = codec;
555 self.endpoint.sample_rate = sample_rate;
556 self.endpoint.channels = channels;
557
558 if codec == A2dpCodec::Sbc {
560 self.sbc_config.channel_mode = if channels == 1 {
561 SbcChannelMode::Mono
562 } else {
563 SbcChannelMode::JointStereo
564 };
565 self.sbc_config.sample_frequency = match sample_rate {
567 16000 => SbcSampleFrequency::Freq16000,
568 32000 => SbcSampleFrequency::Freq32000,
569 44100 => SbcSampleFrequency::Freq44100,
570 48000 => SbcSampleFrequency::Freq48000,
571 _ => SbcSampleFrequency::Freq44100,
572 };
573 }
574
575 self.state = A2dpState::Configured;
576 Ok(())
577 }
578
579 pub(crate) fn start_stream(&mut self) -> Result<(), KernelError> {
581 if self.state != A2dpState::Configured && self.state != A2dpState::Suspended {
582 return Err(KernelError::InvalidState {
583 expected: "Configured or Suspended",
584 actual: "Idle or Streaming",
585 });
586 }
587 self.state = A2dpState::Streaming;
588 Ok(())
589 }
590
591 pub(crate) fn suspend(&mut self) -> Result<(), KernelError> {
593 if self.state != A2dpState::Streaming {
594 return Err(KernelError::InvalidState {
595 expected: "Streaming",
596 actual: "not Streaming",
597 });
598 }
599 self.state = A2dpState::Suspended;
600 Ok(())
601 }
602
603 pub(crate) fn close(&mut self) {
605 self.state = A2dpState::Idle;
606 self.transport_cid = 0;
607 }
608}
609
610#[derive(Debug, Clone, Copy, PartialEq, Eq)]
616#[repr(u8)]
617pub enum HidReportType {
618 Input = 0x01,
620 Output = 0x02,
622 Feature = 0x03,
624}
625
626impl HidReportType {
627 pub(crate) fn from_u8(val: u8) -> Option<Self> {
629 match val {
630 0x01 => Some(Self::Input),
631 0x02 => Some(Self::Output),
632 0x03 => Some(Self::Feature),
633 _ => None,
634 }
635 }
636}
637
638pub const HID_MAX_REPORT_SIZE: usize = 64;
640
641#[derive(Debug, Clone)]
643pub struct HidReport {
644 pub report_type: HidReportType,
646 pub report_id: u8,
648 pub data: [u8; HID_MAX_REPORT_SIZE],
650 pub data_len: usize,
652}
653
654impl HidReport {
655 pub fn new(report_type: HidReportType, report_id: u8) -> Self {
657 Self {
658 report_type,
659 report_id,
660 data: [0u8; HID_MAX_REPORT_SIZE],
661 data_len: 0,
662 }
663 }
664
665 pub(crate) fn with_data(report_type: HidReportType, report_id: u8, data: &[u8]) -> Self {
667 let copy_len = data.len().min(HID_MAX_REPORT_SIZE);
668 let mut report = Self::new(report_type, report_id);
669 report.data[..copy_len].copy_from_slice(&data[..copy_len]);
670 report.data_len = copy_len;
671 report
672 }
673
674 pub(crate) fn as_bytes(&self) -> &[u8] {
676 &self.data[..self.data_len]
677 }
678}
679
680#[derive(Debug, Clone, Copy, PartialEq, Eq)]
682pub struct HidDescriptor {
683 pub usage_page: u16,
685 pub usage: u16,
687 pub report_size: u8,
689 pub report_count: u8,
691}
692
693impl HidDescriptor {
694 pub(crate) fn keyboard() -> Self {
696 Self {
697 usage_page: 0x01, usage: 0x06, report_size: 8,
700 report_count: 6, }
702 }
703
704 pub(crate) fn mouse() -> Self {
706 Self {
707 usage_page: 0x01, usage: 0x02, report_size: 8,
710 report_count: 3, }
712 }
713
714 pub(crate) fn gamepad() -> Self {
716 Self {
717 usage_page: 0x01, usage: 0x05, report_size: 8,
720 report_count: 8, }
722 }
723
724 pub(crate) fn report_byte_size(&self) -> usize {
726 let total_bits = (self.report_size as usize) * (self.report_count as usize);
727 total_bits.div_ceil(8)
728 }
729}
730
731#[derive(Debug, Clone, Copy, PartialEq, Eq)]
733pub enum HidState {
734 Disconnected,
736 Connected,
738 Ready,
740 Suspended,
742}
743
744pub struct HidDevice {
746 pub descriptor: HidDescriptor,
748 pub state: HidState,
750 pub control_cid: u16,
752 pub interrupt_cid: u16,
754 pub last_input_report: HidReport,
756}
757
758impl Default for HidDevice {
759 fn default() -> Self {
760 Self::new(HidDescriptor::keyboard())
761 }
762}
763
764impl HidDevice {
765 pub fn new(descriptor: HidDescriptor) -> Self {
767 Self {
768 descriptor,
769 state: HidState::Disconnected,
770 control_cid: 0,
771 interrupt_cid: 0,
772 last_input_report: HidReport::new(HidReportType::Input, 0),
773 }
774 }
775
776 pub(crate) fn send_report(&self, report: &HidReport) -> Result<(), KernelError> {
778 if self.state != HidState::Ready {
779 return Err(KernelError::InvalidState {
780 expected: "Ready",
781 actual: "not Ready",
782 });
783 }
784 if report.report_type != HidReportType::Output
785 && report.report_type != HidReportType::Feature
786 {
787 return Err(KernelError::InvalidArgument {
788 name: "report_type",
789 value: "send_report expects Output or Feature",
790 });
791 }
792 let _ = report;
794 Ok(())
795 }
796
797 pub(crate) fn receive_report(&mut self, data: &[u8]) -> Result<HidReport, KernelError> {
799 if self.state != HidState::Ready {
800 return Err(KernelError::InvalidState {
801 expected: "Ready",
802 actual: "not Ready",
803 });
804 }
805 if data.is_empty() {
806 return Err(KernelError::InvalidArgument {
807 name: "data",
808 value: "empty report data",
809 });
810 }
811
812 let report = HidReport::with_data(HidReportType::Input, 0, data);
813 self.last_input_report = report.clone();
814 Ok(report)
815 }
816
817 pub(crate) fn parse_report(&self, report: &HidReport) -> Result<ParsedHidReport, KernelError> {
822 if report.data_len == 0 {
823 return Err(KernelError::InvalidArgument {
824 name: "report",
825 value: "empty report data",
826 });
827 }
828
829 let report_size = self.descriptor.report_size as usize;
830 let report_count = self.descriptor.report_count as usize;
831 let mut fields = [0u32; 16]; let mut field_count = 0;
833
834 for (i, field) in fields.iter_mut().enumerate().take(report_count.min(16)) {
835 let bit_offset = i * report_size;
836 let byte_offset = bit_offset / 8;
837 let bit_shift = bit_offset % 8;
838
839 if byte_offset >= report.data_len {
840 break;
841 }
842
843 let mut value = report.data[byte_offset] as u32 >> bit_shift;
844 if bit_shift + report_size > 8 && byte_offset + 1 < report.data_len {
846 value |= (report.data[byte_offset + 1] as u32) << (8 - bit_shift);
847 }
848 value &= (1u32 << report_size) - 1;
849 *field = value;
850 field_count += 1;
851 }
852
853 Ok(ParsedHidReport {
854 fields,
855 field_count,
856 })
857 }
858
859 pub(crate) fn connect(&mut self, control_cid: u16, interrupt_cid: u16) {
861 self.control_cid = control_cid;
862 self.interrupt_cid = interrupt_cid;
863 self.state = HidState::Connected;
864 }
865
866 pub(crate) fn set_ready(&mut self) {
868 if self.state == HidState::Connected {
869 self.state = HidState::Ready;
870 }
871 }
872
873 pub(crate) fn disconnect(&mut self) {
875 self.state = HidState::Disconnected;
876 self.control_cid = 0;
877 self.interrupt_cid = 0;
878 }
879}
880
881#[derive(Debug, Clone)]
883pub struct ParsedHidReport {
884 pub fields: [u32; 16],
886 pub field_count: usize,
888}
889
890impl ParsedHidReport {
891 pub(crate) fn field(&self, index: usize) -> Option<u32> {
893 if index < self.field_count {
894 Some(self.fields[index])
895 } else {
896 None
897 }
898 }
899}
900
901pub struct SerialPortProfile {
907 pub dlci: u8,
909 pub connected: bool,
911 pub baud_rate: u32,
913 pub data_bits: u8,
915 pub stop_bits: u8,
917 pub parity: u8,
919 pub read_buf: [u8; 256],
921 pub read_len: usize,
923}
924
925impl Default for SerialPortProfile {
926 fn default() -> Self {
927 Self::new(1)
928 }
929}
930
931impl SerialPortProfile {
932 pub fn new(dlci: u8) -> Self {
934 Self {
935 dlci,
936 connected: false,
937 baud_rate: 115200,
938 data_bits: 8,
939 stop_bits: 1,
940 parity: 0,
941 read_buf: [0u8; 256],
942 read_len: 0,
943 }
944 }
945
946 pub(crate) fn connect(&mut self) -> Result<(), KernelError> {
948 if self.connected {
949 return Err(KernelError::InvalidState {
950 expected: "disconnected",
951 actual: "connected",
952 });
953 }
954 self.connected = true;
955 Ok(())
956 }
957
958 pub(crate) fn disconnect(&mut self) -> Result<(), KernelError> {
960 if !self.connected {
961 return Err(KernelError::InvalidState {
962 expected: "connected",
963 actual: "disconnected",
964 });
965 }
966 self.connected = false;
967 self.read_len = 0;
968 Ok(())
969 }
970
971 pub(crate) fn write<'a>(&self, data: &'a [u8]) -> Result<&'a [u8], KernelError> {
975 if !self.connected {
976 return Err(KernelError::InvalidState {
977 expected: "connected",
978 actual: "disconnected",
979 });
980 }
981 if data.is_empty() {
982 return Err(KernelError::InvalidArgument {
983 name: "data",
984 value: "empty write data",
985 });
986 }
987 Ok(data)
989 }
990
991 pub(crate) fn receive(&mut self, data: &[u8]) -> Result<usize, KernelError> {
993 if !self.connected {
994 return Err(KernelError::InvalidState {
995 expected: "connected",
996 actual: "disconnected",
997 });
998 }
999 let available = self.read_buf.len() - self.read_len;
1000 let copy_len = data.len().min(available);
1001 self.read_buf[self.read_len..self.read_len + copy_len].copy_from_slice(&data[..copy_len]);
1002 self.read_len += copy_len;
1003 Ok(copy_len)
1004 }
1005
1006 pub(crate) fn read(&mut self, buf: &mut [u8]) -> usize {
1010 let copy_len = buf.len().min(self.read_len);
1011 buf[..copy_len].copy_from_slice(&self.read_buf[..copy_len]);
1012 if copy_len < self.read_len {
1014 let remaining = self.read_len - copy_len;
1015 let mut temp = [0u8; 256];
1017 temp[..remaining].copy_from_slice(&self.read_buf[copy_len..copy_len + remaining]);
1018 self.read_buf[..remaining].copy_from_slice(&temp[..remaining]);
1019 }
1020 self.read_len -= copy_len;
1021 copy_len
1022 }
1023}
1024
1025#[cfg(test)]
1030mod tests {
1031 #[cfg(feature = "alloc")]
1032 #[allow(unused_imports)]
1033 use alloc::vec;
1034
1035 use super::*;
1036
1037 #[test]
1038 fn test_sdp_attribute_types() {
1039 assert!(SdpAttribute::Nil.is_nil());
1040 assert!(!SdpAttribute::Uint8(0).is_nil());
1041 assert_eq!(SdpAttribute::Uint16(0x1101).as_u16(), Some(0x1101));
1042 assert_eq!(SdpAttribute::Uuid16(0x0003).as_uuid16(), Some(0x0003));
1043 assert_eq!(SdpAttribute::Uint32(42).as_u16(), None);
1044 }
1045
1046 #[cfg(feature = "alloc")]
1047 #[test]
1048 fn test_sdp_database_register_find() {
1049 let mut db = SdpDatabase::new();
1050 let h1 = db.register_service(UUID_SERIAL_PORT, "Serial Port");
1051 let h2 = db.register_service(UUID_A2DP_SINK, "A2DP Sink");
1052 assert_eq!(db.record_count(), 2);
1053
1054 let rec = db.find_by_uuid(UUID_SERIAL_PORT).unwrap();
1055 assert_eq!(rec.handle, h1);
1056 assert_eq!(rec.service_name, "Serial Port");
1057
1058 let rec2 = db.find_by_uuid(UUID_A2DP_SINK).unwrap();
1059 assert_eq!(rec2.handle, h2);
1060 }
1061
1062 #[cfg(feature = "alloc")]
1063 #[test]
1064 fn test_sdp_database_remove() {
1065 let mut db = SdpDatabase::new();
1066 let h = db.register_service(UUID_HID, "HID");
1067 assert_eq!(db.record_count(), 1);
1068 assert!(db.remove_service(h));
1069 assert_eq!(db.record_count(), 0);
1070 assert!(!db.remove_service(h)); }
1072
1073 #[cfg(feature = "alloc")]
1074 #[test]
1075 fn test_sdp_search() {
1076 let mut db = SdpDatabase::new();
1077 db.register_service(UUID_SERIAL_PORT, "SPP 1");
1078 db.register_service(UUID_SERIAL_PORT, "SPP 2");
1079 db.register_service(UUID_A2DP_SINK, "A2DP");
1080 let results = db.search(UUID_SERIAL_PORT);
1081 assert_eq!(results.len(), 2);
1082 }
1083
1084 #[test]
1085 fn test_sbc_config_default_valid() {
1086 let config = SbcConfig::default();
1087 assert!(config.validate().is_ok());
1088 }
1089
1090 #[test]
1091 fn test_sbc_config_invalid_subbands() {
1092 let mut config = SbcConfig::default();
1093 config.subbands = 3;
1094 assert!(config.validate().is_err());
1095 }
1096
1097 #[test]
1098 fn test_sbc_config_to_bytes() {
1099 let config = SbcConfig::default();
1100 let bytes = config.to_bytes();
1101 assert_eq!(bytes[0], 0x21);
1103 assert_eq!(bytes[1], 0x15);
1105 assert_eq!(bytes[2], 2); assert_eq!(bytes[3], 53); }
1108
1109 #[test]
1110 fn test_a2dp_sink_lifecycle() {
1111 let mut sink = A2dpSink::new();
1112 assert_eq!(sink.state, A2dpState::Idle);
1113
1114 sink.configure(A2dpCodec::Sbc, 44100, 2).unwrap();
1115 assert_eq!(sink.state, A2dpState::Configured);
1116
1117 sink.start_stream().unwrap();
1118 assert_eq!(sink.state, A2dpState::Streaming);
1119
1120 sink.suspend().unwrap();
1121 assert_eq!(sink.state, A2dpState::Suspended);
1122
1123 sink.start_stream().unwrap();
1124 assert_eq!(sink.state, A2dpState::Streaming);
1125
1126 sink.close();
1127 assert_eq!(sink.state, A2dpState::Idle);
1128 }
1129
1130 #[test]
1131 fn test_hid_report_creation() {
1132 let data = [0x01, 0x02, 0x03];
1133 let report = HidReport::with_data(HidReportType::Input, 1, &data);
1134 assert_eq!(report.report_type, HidReportType::Input);
1135 assert_eq!(report.report_id, 1);
1136 assert_eq!(report.as_bytes(), &data);
1137 }
1138
1139 #[test]
1140 fn test_hid_descriptor_keyboard() {
1141 let desc = HidDescriptor::keyboard();
1142 assert_eq!(desc.usage_page, 0x01);
1143 assert_eq!(desc.usage, 0x06);
1144 assert_eq!(desc.report_byte_size(), 6);
1145 }
1146
1147 #[test]
1148 fn test_hid_device_lifecycle() {
1149 let mut dev = HidDevice::new(HidDescriptor::keyboard());
1150 assert_eq!(dev.state, HidState::Disconnected);
1151
1152 dev.connect(0x0011, 0x0013);
1153 assert_eq!(dev.state, HidState::Connected);
1154
1155 dev.set_ready();
1156 assert_eq!(dev.state, HidState::Ready);
1157
1158 let data = [0x00, 0x00, 0x04, 0x00, 0x00, 0x00]; let report = dev.receive_report(&data).unwrap();
1160 assert_eq!(report.data_len, 6);
1161
1162 dev.disconnect();
1163 assert_eq!(dev.state, HidState::Disconnected);
1164 }
1165
1166 #[test]
1167 fn test_hid_parse_report() {
1168 let dev = HidDevice::new(HidDescriptor {
1169 usage_page: 0x01,
1170 usage: 0x02,
1171 report_size: 8,
1172 report_count: 3,
1173 });
1174 let report = HidReport::with_data(HidReportType::Input, 0, &[0x01, 0x0A, 0xF0]);
1175 let parsed = dev.parse_report(&report).unwrap();
1177 assert_eq!(parsed.field_count, 3);
1178 assert_eq!(parsed.field(0), Some(0x01));
1179 assert_eq!(parsed.field(1), Some(0x0A));
1180 assert_eq!(parsed.field(2), Some(0xF0));
1181 assert_eq!(parsed.field(3), None);
1182 }
1183
1184 #[test]
1185 fn test_spp_read_write() {
1186 let mut spp = SerialPortProfile::new(5);
1187 spp.connect().unwrap();
1188
1189 let data = [0x48, 0x65, 0x6C, 0x6C, 0x6F]; let result = spp.write(&data).unwrap();
1192 assert_eq!(result, &data);
1193
1194 let incoming = [0x41, 0x42, 0x43]; let received = spp.receive(&incoming).unwrap();
1197 assert_eq!(received, 3);
1198
1199 let mut buf = [0u8; 10];
1201 let read = spp.read(&mut buf);
1202 assert_eq!(read, 3);
1203 assert_eq!(&buf[..3], &incoming);
1204
1205 spp.disconnect().unwrap();
1206 }
1207
1208 #[test]
1209 fn test_spp_errors() {
1210 let mut spp = SerialPortProfile::new(1);
1211 assert!(spp.write(&[0x01]).is_err());
1213 assert!(spp.disconnect().is_err());
1215 spp.connect().unwrap();
1217 assert!(spp.connect().is_err());
1218 }
1219}