1 use log::warn; 2 3 use crate::packets::att; 4 5 use super::att_database::AttDatabase; 6 7 /// This struct handles all ATT commands. 8 pub struct AttCommandHandler<Db: AttDatabase> { 9 db: Db, 10 } 11 12 impl<Db: AttDatabase> AttCommandHandler<Db> { new(db: Db) -> Self13 pub fn new(db: Db) -> Self { 14 Self { db } 15 } 16 process_packet(&self, packet: att::Att)17 pub fn process_packet(&self, packet: att::Att) { 18 let snapshotted_db = self.db.snapshot(); 19 match packet.opcode { 20 att::AttOpcode::WriteCommand => { 21 let Ok(packet) = att::AttWriteCommand::try_from(packet) else { 22 warn!("failed to parse WRITE_COMMAND packet"); 23 return; 24 }; 25 snapshotted_db.write_no_response_attribute(packet.handle.into(), &packet.value); 26 } 27 _ => { 28 warn!("Dropping unsupported opcode {:?}", packet.opcode); 29 } 30 } 31 } 32 } 33 34 #[cfg(test)] 35 mod test { 36 use crate::core::uuid::Uuid; 37 use crate::gatt::ids::AttHandle; 38 use crate::gatt::server::att_database::{AttAttribute, AttDatabase}; 39 use crate::gatt::server::command_handler::AttCommandHandler; 40 use crate::gatt::server::gatt_database::AttPermissions; 41 use crate::gatt::server::test::test_att_db::TestAttDatabase; 42 use crate::packets::att; 43 use crate::utils::task::block_on_locally; 44 45 #[test] test_write_command()46 fn test_write_command() { 47 // arrange 48 let db = TestAttDatabase::new(vec![( 49 AttAttribute { 50 handle: AttHandle(3), 51 type_: Uuid::new(0x1234), 52 permissions: AttPermissions::READABLE | AttPermissions::WRITABLE_WITHOUT_RESPONSE, 53 }, 54 vec![1, 2, 3], 55 )]); 56 let handler = AttCommandHandler { db: db.clone() }; 57 let data = [1, 2]; 58 59 // act: send write command 60 let att_view = att::AttWriteCommand { handle: AttHandle(3).into(), value: data.to_vec() } 61 .try_into() 62 .unwrap(); 63 handler.process_packet(att_view); 64 65 // assert: the db has been updated 66 assert_eq!(block_on_locally(db.read_attribute(AttHandle(3))).unwrap(), data); 67 } 68 69 #[test] test_unsupported_command()70 fn test_unsupported_command() { 71 // arrange 72 let db = TestAttDatabase::new(vec![]); 73 let handler = AttCommandHandler { db }; 74 75 // act: send a packet that should not be handled here 76 let att_view = att::AttErrorResponse { 77 opcode_in_error: att::AttOpcode::ExchangeMtuRequest, 78 handle_in_error: AttHandle(1).into(), 79 error_code: att::AttErrorCode::UnlikelyError, 80 } 81 .try_into() 82 .unwrap(); 83 handler.process_packet(att_view); 84 85 // assert: nothing happens (we crash if anything is unhandled within a mock) 86 } 87 } 88