rust_powered_lego/lego/
communicator.rs1use std::pin::Pin;
2
3use btleplug::api::{Peripheral as _, Characteristic, Service, WriteType, ValueNotification};
4use btleplug::platform::{Peripheral};
5
6use anyhow::{Result, anyhow, Ok};
7use num_traits::ToPrimitive;
8use tokio_stream::Stream;
9
10
11use super::check_for_lego_error;
12use super::{MessageTypes, message_parameters::Serialized};
13
14pub const MAX_MESSAGE_SIZE: usize = 130;
15
16
17
18pub struct CommonMessageHeader {}
19
20impl CommonMessageHeader {
21 fn get_header(msg_type: MessageTypes) -> Vec<u8> {
22 vec![0x0, 0x0, msg_type as u8] }
24}
25
26
27pub struct Communicator {
28 peripheral: Peripheral,
29 characteristic: Characteristic,
30}
31
32impl Communicator {
33 pub async fn new(peripheral: Peripheral) -> Result<Self> {
34 peripheral.discover_services().await?;
35
36 let srvc: Option<Service>;
37 let mut c: Option<Characteristic> = None;
38 for service in peripheral.services() {
39 srvc = Some(service);
40 for characteristic in srvc.unwrap().characteristics {
41 c = Some(characteristic);
42 break;
43 }
44 break;
45 }
46 println!("Characteristics: {:?}", c);
47 Ok(Self { peripheral, characteristic: c.unwrap() })
48 }
49
50 pub async fn send_message<T>(&self, mt: MessageTypes, mp: T) -> Result<()>
51 where
52 T: Serialized,
53 {
54 let write_type = WriteType::WithResponse;
55
56 let mut data = CommonMessageHeader::get_header(mt);
57 data.append(mp.serialize().as_mut());
58 let size = data.len();
59 data[0] = size.to_u8().unwrap();
60 if size > 127 {
61 data.insert(1, 0x01);
62 }
63
64 let res = self.peripheral.write(
65 &self.characteristic,
66 &data,
67 write_type).await;
68
69 if res.is_err() {
70 Err(anyhow!("Couldn't send the message"))
71 } else {
72 Ok(())
73 }
74 }
75
76 pub async fn read_message(&self) -> Result<Vec<u8>> {
77 let mut res = self.peripheral.read(&self.characteristic).await?;
78 if res.is_empty() {
79 res = self.peripheral.read(&self.characteristic).await?;
80 }
81 check_for_lego_error(&res)?;
82 Ok(res)
83 }
84
85 pub async fn get_notification_stream(&self) -> Result<Pin<Box<dyn Stream<Item = ValueNotification> + Send>>> {
86 self.peripheral.subscribe(&self.characteristic).await?;
87 Ok(self.peripheral.notifications().await?)
88 }
89
90 pub async fn get_message_only<T>(&self, mt: MessageTypes, mp: T) -> Result<Vec<u8>>
92 where
93 T: Serialized,
94 {
95 let mut data = CommonMessageHeader::get_header(mt);
96 data.append(mp.serialize().as_mut());
97 let size = data.len();
98
99 data[0] = size.to_u8().unwrap();
101 if size > 127 {
102 data.insert(1, 0x01);
103 }
104
105 Ok(data)
106 }
107}