embedded_aim_motor/motor/
mod.rs1mod parameters;
2
3use crate::{Error, Result, RtuBaud};
4use defmt::debug;
5use embassy_time::{Duration, Instant, Timer, with_timeout};
6use modbus_core::{
7 Data, FunctionCode, Request, RequestPdu, Response,
8 rtu::{Header, RequestAdu},
9};
10
11pub struct Motor<I: embedded_io_async::Read + embedded_io_async::Write> {
12 comm: I,
13
14 t15: Duration,
15 t35: Duration,
16 response_timeout: Duration,
17
18 address: u8,
19
20 buffer: [u8; 64],
21 earliest_next_frame: Instant,
22}
23
24impl<I: embedded_io_async::Read + embedded_io_async::Write> Motor<I> {
25 pub fn new(comm: I, baud: RtuBaud, address: u8, response_timeout: Duration) -> Self {
26 Self {
27 comm,
28 t15: baud.t15(),
29 t35: baud.t35(),
30 response_timeout,
31 address,
32 buffer: [0u8; 64],
33 earliest_next_frame: Instant::now(),
34 }
35 }
36
37 async fn modbus_transaction<'a>(&'a mut self, req: RequestPdu<'a>) -> Result<Response<'a>> {
38 Timer::at(self.earliest_next_frame).await;
40
41 let request = RequestAdu {
43 hdr: Header {
44 slave: self.address,
45 },
46 pdu: req,
47 };
48
49 let n = modbus_core::rtu::client::encode_request(request, &mut self.buffer)
51 .map_err(|_| Error::Transport)?;
52 let data = &self.buffer[..n];
53 debug!("Encoded request: ({}) {:x}", n, data);
54
55 self.comm
57 .write_all(data)
58 .await
59 .map_err(|_| Error::Transport)?;
60
61 let mut timeout = self.response_timeout;
62 let mut total_read = 0;
63
64 'rx: loop {
66 match with_timeout(timeout, self.comm.read(&mut self.buffer[total_read..])).await {
67 Ok(Ok(n)) => {
68 total_read += n;
69 self.earliest_next_frame = Instant::now() + self.t35;
70 }
71 Ok(Err(_)) => {
72 return Err(Error::Transport);
73 }
74 Err(_) => break 'rx,
75 }
76
77 timeout = self.t15;
78 }
79
80 if total_read == 0 {
81 Err(Error::Timeout)
83 } else {
84 let data = &self.buffer[..total_read];
85 debug!("Received: ({}) {:x}", total_read, data);
86
87 let response = modbus_core::rtu::client::decode_response(data)
89 .map_err(|_| Error::Transport)?
90 .ok_or(Error::Modbus)?;
91
92 Ok(response.pdu.0.map_err(|_| Error::Modbus)?)
93 }
94 }
95
96 async fn read_one_word_parameter<T, F>(&mut self, address: u16, transform: F) -> Result<T>
97 where
98 F: Fn(u16) -> Result<T>,
99 {
100 let request = RequestPdu(Request::ReadHoldingRegisters(address, 1));
101
102 match self.modbus_transaction(request).await? {
103 Response::ReadHoldingRegisters(data) => {
104 if data.len() == 1 {
105 let raw = data.get(0).unwrap();
106 Ok(transform(raw)?)
107 } else {
108 Err(Error::UnexpectedResponseLength(data.len(), 1))
109 }
110 }
111 _ => Err(Error::UnexpectedResponseType),
112 }
113 }
114
115 async fn read_two_word_parameter<T, F>(&mut self, address: u16, transform: F) -> Result<T>
116 where
117 F: Fn(u16, u16) -> Result<T>,
118 {
119 let request = RequestPdu(Request::ReadHoldingRegisters(address, 2));
120
121 match self.modbus_transaction(request).await? {
122 Response::ReadHoldingRegisters(data) => {
123 if data.len() == 2 {
124 let raw_0 = data.get(0).unwrap();
125 let raw_1 = data.get(1).unwrap();
126 Ok(transform(raw_0, raw_1)?)
127 } else {
128 Err(Error::UnexpectedResponseLength(data.len(), 2))
129 }
130 }
131 _ => Err(Error::UnexpectedResponseType),
132 }
133 }
134
135 async fn write_one_word_parameter<T, F>(
136 &mut self,
137 address: u16,
138 value: T,
139 transform: F,
140 ) -> Result<()>
141 where
142 F: Fn(T) -> Result<u16>,
143 {
144 let data = transform(value)?;
145
146 let request = RequestPdu(Request::WriteSingleRegister(address, data));
147
148 match self.modbus_transaction(request).await? {
149 Response::WriteSingleRegister(a, d) => {
150 if a == address && d == data {
151 Ok(())
152 } else {
153 Err(Error::UnexpectedResponseData)
154 }
155 }
156 _ => Err(Error::UnexpectedResponseType),
157 }
158 }
159
160 async fn write_two_word_parameter<T, F>(
161 &mut self,
162 address: u16,
163 value: T,
164 transform: F,
165 ) -> Result<()>
166 where
167 F: Fn(T) -> Result<[u16; 2]>,
168 {
169 let data = transform(value)?;
170
171 let mut buff = [0u8; 4];
172 let data = Data::from_words(&data, &mut buff).unwrap();
173
174 let request = RequestPdu(Request::WriteMultipleRegisters(address, data));
175
176 match self.modbus_transaction(request).await? {
177 Response::WriteMultipleRegisters(a, 2) => {
178 if a == address {
179 Ok(())
180 } else {
181 Err(Error::UnexpectedResponseData)
182 }
183 }
184 _ => Err(Error::UnexpectedResponseType),
185 }
186 }
187
188 pub async fn set_baud_rate(&mut self, baud: RtuBaud) -> Result<()> {
189 let baud = match baud {
190 RtuBaud::Baud115200 => 803,
191 RtuBaud::Baud38400 => 802,
192 RtuBaud::Baud19200 => 801,
193 RtuBaud::Baud9600 => 800,
194 };
195
196 self.write_one_word_parameter(0x00, 1, Ok).await?;
197 self.write_one_word_parameter(0x02, baud, Ok).await?;
198 self.write_one_word_parameter(0x03, 129, Ok).await?;
199 self.write_one_word_parameter(0x00, 506, Ok).await?;
200
201 Ok(())
202 }
203
204 pub async fn set_target_position_custom(&mut self, value: u32) -> Result<()> {
205 const FC: FunctionCode = FunctionCode::Custom(0x78);
206
207 let data = value.to_be_bytes();
208 let request = RequestPdu(Request::Custom(FC, &data));
209
210 match self.modbus_transaction(request).await? {
211 Response::Custom(FC, d) => {
212 if d == data {
213 Ok(())
214 } else {
215 Err(Error::UnexpectedResponseData)
216 }
217 }
218 _ => Err(Error::UnexpectedResponseType),
219 }
220 }
221
222 pub async fn set_absolute_position_custom(&mut self, value: u32) -> Result<()> {
223 const FC: FunctionCode = FunctionCode::Custom(0x7B);
224
225 let data = value.to_be_bytes();
226 let request = RequestPdu(Request::Custom(FC, &data));
227
228 match self.modbus_transaction(request).await? {
229 Response::Custom(FC, d) => {
230 if d == data {
231 Ok(())
232 } else {
233 Err(Error::UnexpectedResponseData)
234 }
235 }
236 _ => Err(Error::UnexpectedResponseType),
237 }
238 }
239}