1#![no_std]
2
3#[macro_use]
9extern crate bitflags;
10extern crate byteorder;
11#[macro_use(block)]
12extern crate nb;
13extern crate embedded_hal as hal;
14
15use commands::SimpleCmd;
16use core::marker::PhantomData;
17use core::time::Duration;
18use hal::serial;
19
20mod hex;
21
22pub mod mode {
24 pub struct Run;
26 pub struct Sleep;
28 pub struct Stop;
30}
31
32#[derive(Debug)]
33pub struct Multitech3<RX, TX, MODE>
35where
36 RX: serial::Read<u8>,
37 TX: serial::Write<u8>,
38{
39 rx: RX,
41 tx: TX,
43 #[doc(hidden)]
44 _mode: PhantomData<MODE>,
45}
46
47pub fn new<RX, TX>(rx: RX, tx: TX) -> Multitech3<RX, TX, mode::Run>
49where
50 RX: serial::Read<u8>,
51 TX: serial::Write<u8>,
52{
53 Multitech3::<RX, TX, mode::Run> {
54 rx,
55 tx,
56 _mode: PhantomData,
57 }
58}
59
60impl<RX, TX, MODE> Multitech3<RX, TX, MODE>
61where
62 RX: serial::Read<u8>,
63 TX: serial::Write<u8>,
64{
65 fn read_byte(&mut self) -> Result<u8, Error> {
67 match block!(self.rx.read()) {
68 Ok(c) => Ok(c),
69 Err(_e) => Err(Error::Read),
70 }
71 }
72
73 fn read_hex_byte(&mut self) -> Result<u8, Error> {
75 match hex::hex_byte_to_byte(self.read_byte()?, self.read_byte()?) {
76 Ok(b) => Ok(b),
77 Err(e) => Err(Error::Hex(e)),
78 }
79 }
80
81 fn read_err(&mut self) -> Result<ReaderError, Error> {
83 Ok(ReaderError::from(self.read_hex_byte()?))
84 }
85
86 fn read_resp(&mut self, buf: &mut [u8]) -> Result<ReaderError, Error> {
88 let err = self.read_err()?;
89 match err {
90 ReaderError::None(_) => {
91 let mut i = 0;
92 loop {
93 if i > buf.len() {
94 return Err(Error::BufferFull);
95 }
96
97 let c = match block!(self.rx.read()) {
98 Ok(c) => c,
99 Err(_e) => return Err(Error::Read),
100 };
101 if c == '\r' as u8 {
102 break;
103 }
104 buf[i] = c;
105 i += 1;
106 }
107 Ok(ReaderError::None(i))
108 }
109 _ => Err(Error::Reader(err)),
110 }
111 }
112}
113
114impl<RX, TX> Multitech3<RX, TX, mode::Sleep>
115where
116 RX: serial::Read<u8>,
117 TX: serial::Write<u8>,
118{
119 pub fn into_running(
121 mut self,
122 ) -> Result<(Multitech3<RX, TX, mode::Run>, WakeReason), (Self, Error)> {
123 let mut resp_buf = [0u8; 2];
124 match self.read_resp(&mut resp_buf) {
125 Ok(resp) => match resp {
126 ReaderError::None(_) => {
127 let reason_code = match hex::hex_byte_to_byte(resp_buf[0], resp_buf[1]) {
128 Ok(c) => c,
129 Err(e) => return Err((self, Error::Hex(e))),
130 };
131
132 Ok((
133 Multitech3::<RX, TX, mode::Run> {
134 rx: self.rx,
135 tx: self.tx,
136 _mode: PhantomData,
137 },
138 WakeReason::from(reason_code),
139 ))
140 }
141 _ => Err((self, Error::Reader(resp))),
142 },
143 Err(e) => Err((self, e)),
144 }
145 }
146}
147
148impl<RX, TX> Multitech3<RX, TX, mode::Run>
149where
150 RX: serial::Read<u8>,
151 TX: serial::Write<u8>,
152{
153 fn issue_cmd<C: SimpleCmd>(&mut self, buf: &mut [u8], cmd: &C) -> Result<(), Error> {
155 let sz = cmd.get_cmd_hex(buf)?;
156 self.write_buf(&buf[..sz])?;
157 self.write_buf("\r".as_bytes())?;
158 Ok(())
159 }
160
161 fn write_buf(&mut self, buf: &[u8]) -> Result<(), Error> {
163 for c in buf.iter() {
164 match block!(self.tx.write(*c)) {
165 Ok(_) => {}
166 Err(_) => return Err(Error::Write),
167 }
168 }
169 Ok(())
170 }
171
172 pub fn reset(&mut self) -> Result<(), Error> {
174 let cmd = commands::Reset;
175 self.issue_cmd(&mut [0u8; commands::Reset::CMD_LEN], &cmd)
176 }
177
178 pub fn sleep(mut self, dur: Duration) -> Result<Multitech3<RX, TX, mode::Sleep>, Error> {
180 let sleep_cmd = commands::Sleep {
181 period: dur,
182 flags: commands::SleepFlags::WAKEUP_BY_TIMEOUT_MSK
183 | commands::SleepFlags::WAKEUP_BY_LPCD_MSK,
184 };
185 match self.issue_cmd(&mut [0u8; commands::Sleep::CMD_LEN], &sleep_cmd) {
186 Ok(_) => Ok(Multitech3::<RX, TX, mode::Sleep> {
187 rx: self.rx,
188 tx: self.tx,
189 _mode: PhantomData,
190 }),
191 Err(e) => Err(e),
192 }
193 }
194
195 pub fn get_sys_ticks(&mut self) -> Result<u32, Error> {
197 const RESP_LEN: usize = 8;
198 let mut resp_buf = [0u8; RESP_LEN];
199 let cmd = commands::GetSysTicks;
200 match self.issue_cmd(&mut [0u8; commands::GetSysTicks::CMD_LEN], &cmd) {
201 Ok(_) => {
202 let resp = self.read_resp(&mut resp_buf)?;
203 match resp {
204 ReaderError::None(n) => cmd.parse_response(&mut resp_buf[..n]),
205 _ => Err(Error::Reader(resp)),
206 }
207 }
208 Err(e) => Err(e),
209 }
210 }
211
212 pub fn get_version_string(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
214 let cmd = commands::GetVersionString {
215 max_resp_len: core::cmp::min(0xFF as usize, buf.len()) as u16,
216 };
217 match self.issue_cmd(&mut [0u8; commands::GetVersionString::CMD_LEN], &cmd) {
218 Ok(()) => {
219 let resp = self.read_resp(buf)?;
220 match resp {
221 ReaderError::None(n) => cmd.parse_response(&mut buf[..n]),
222 _ => Err(Error::Reader(resp)),
223 }
224 }
225 Err(e) => Err(e),
226 }
227 }
228
229 pub fn search_tag(&mut self, buf: &mut [u8]) -> Result<Option<usize>, Error> {
237 let cmd = commands::SearchTag;
238 match self.issue_cmd(&mut [0u8; commands::SearchTag::CMD_LEN], &cmd) {
239 Ok(()) => {
240 let rdr_resp = ReaderError::from(self.read_hex_byte()?);
245 match rdr_resp {
246 ReaderError::None(_) => {}
247 _ => return Err(Error::Reader(rdr_resp)),
248 };
249
250 let result = self.read_hex_byte()?;
251 if result != 1u8 {
252 return Ok(None);
253 }
254
255 if buf.len() < 2 {
256 return Err(Error::BufferTooSmall(2));
257 }
258
259 buf[0] = self.read_hex_byte()?; let bit_count = self.read_hex_byte()?; if bit_count == 0 {
263 return Ok(None);
264 } else {
265 buf[1] = bit_count;
266 }
267
268 let id_bytes = self.read_hex_byte()? as usize;
269
270 if buf.len() < id_bytes + 2 {
271 return Err(Error::BufferTooSmall(id_bytes + 2));
272 }
273
274 let mut i = 0;
275 loop {
276 if i == id_bytes {
277 break;
278 }
279 buf[i + 2] = self.read_hex_byte()?;
280 i += 1;
281 }
282
283 Ok(Some(id_bytes + 2))
284 }
285 Err(e) => Err(e),
286 }
287 }
288}
289
290#[derive(Debug)]
291pub enum Error {
293 BadResponse(usize),
295 BufferFull,
297 BufferTooSmall(usize),
299 Read,
303 Write,
305 StillAsleep,
307 Other,
309 Unimplemented,
311 Reader(ReaderError),
313 Hex(hex::Error),
315}
316
317#[derive(Debug)]
318pub enum ReaderError {
320 None(usize),
322 UnknownFunction,
324 MissingParameter,
326 UnusedParameters,
328 InvalidFunction,
330 Parser,
332 Unknown(u8),
334}
335
336impl From<u8> for ReaderError {
337 fn from(code: u8) -> Self {
339 match code {
340 0 => ReaderError::None(0),
341 1 => ReaderError::UnknownFunction,
342 2 => ReaderError::MissingParameter,
343 3 => ReaderError::UnusedParameters,
344 4 => ReaderError::InvalidFunction,
345 5 => ReaderError::Parser,
346 _ => ReaderError::Unknown(code),
347 }
348 }
349}
350
351impl From<hex::Error> for Error {
352 fn from(e: hex::Error) -> Self {
354 Error::Hex(e)
355 }
356}
357
358impl From<nb::Error<Error>> for Error {
359 fn from(e: nb::Error<Error>) -> Error {
361 match e {
362 nb::Error::Other(e) => e,
363 _ => Error::Other,
364 }
365 }
366}
367
368#[derive(Debug)]
369pub enum WakeReason {
371 Unknown,
373 USB,
375 COM1,
377 COM2,
379 Timeout,
381 LPCD,
383}
384
385impl From<u8> for WakeReason {
386 fn from(n: u8) -> Self {
388 match n {
389 1 => WakeReason::USB,
390 2 => WakeReason::COM1,
391 3 => WakeReason::COM2,
392 4 => WakeReason::Timeout,
393 5 => WakeReason::LPCD,
394 _ => WakeReason::Unknown,
395 }
396 }
397}
398
399pub struct TagInfo<'i> {
400 pub tag_type: u8,
401 pub id_bit_count: u8,
402 pub id: &'i [u8],
403}
404
405mod commands {
406 use super::hex;
407 use super::Error;
408 use byteorder::{ByteOrder, LittleEndian};
409 use core::time::Duration;
410
411 fn copy_all_bytes(dest: &mut [u8], src: &[u8]) {
412 dest[..src.len()].copy_from_slice(&src[..]);
413 }
414
415 fn check_bufsz(l: usize, b: &[u8]) -> Result<(), Error> {
416 if b.len() < l {
417 Err(Error::BufferTooSmall(l))
418 } else {
419 Ok(())
420 }
421 }
422
423 pub trait SimpleCmd {
425 const CMD_LEN: usize;
427 type Response;
429
430 fn get_cmd_hex(&self, buf: &mut [u8]) -> Result<usize, Error>;
432 fn parse_response(&self, _buf: &mut [u8]) -> Result<Self::Response, Error> {
434 Err(Error::Unimplemented)
435 }
436 }
437
438 pub struct Reset;
440
441 impl SimpleCmd for Reset {
442 const CMD_LEN: usize = 2;
443 type Response = ();
444
445 fn get_cmd_hex(&self, buf: &mut [u8]) -> Result<usize, Error> {
446 check_bufsz(Reset::CMD_LEN, buf)?;
447 copy_all_bytes(buf, "0001".as_bytes());
448 Ok(2)
449 }
450 }
451
452 bitflags! {
453 pub struct SleepFlags: u32 {
455 const WAKEUP_BY_USB_MSK = 0x1;
456 const WAKEUP_BY_COM1_MSK = 0x2;
457 const WAKEUP_BY_COM2_MSK = 0x4;
458 const WAKEUP_BY_TIMEOUT_MSK = 0x10;
459 const WAKEUP_BY_LPCD_MSK = 0x20;
460 const SLEEPMODE_SLEEP = 0x0000;
461 const SLEEPMODE_STOP = 0x0100;
462 }
463 }
464
465 pub struct Sleep {
469 pub period: Duration,
470 pub flags: SleepFlags,
471 }
472
473 impl SimpleCmd for Sleep {
474 const CMD_LEN: usize = 20;
475 type Response = ();
476
477 fn get_cmd_hex(&self, buf: &mut [u8]) -> Result<usize, Error> {
478 check_bufsz(Sleep::CMD_LEN, buf)?;
479
480 copy_all_bytes(buf, "0007".as_bytes());
481 let mut u32_buf = [0u8; 4];
482 LittleEndian::write_u32(
483 &mut u32_buf,
484 self.period.as_secs() as u32 * 1000 + self.period.subsec_millis(),
485 );
486 hex::bytes_to_hex(&u32_buf, &mut buf[4..12])?;
487 LittleEndian::write_u32(&mut u32_buf, self.flags.bits());
488 hex::bytes_to_hex(&u32_buf, &mut buf[12..20])?;
489 Ok(Self::CMD_LEN)
490 }
491 }
492
493 pub struct GetSysTicks;
495
496 impl SimpleCmd for GetSysTicks {
497 const CMD_LEN: usize = 4;
498 type Response = u32;
499
500 fn get_cmd_hex(&self, buf: &mut [u8]) -> Result<usize, Error> {
501 check_bufsz(GetSysTicks::CMD_LEN, buf)?;
502
503 copy_all_bytes(buf, "0003".as_bytes());
504 Ok(GetSysTicks::CMD_LEN)
505 }
506
507 fn parse_response(&self, buf: &mut [u8]) -> Result<u32, Error> {
508 if buf.len() != 8 {
509 return Err(Error::BadResponse(buf.len()));
510 }
511
512 let mut result_buf = [0u8; 4];
513 hex::hex_to_bytes(&buf, &mut result_buf)?;
514 Ok(LittleEndian::read_u32(&result_buf))
515 }
516 }
517
518 pub struct GetVersionString {
520 pub max_resp_len: u16,
521 }
522
523 impl SimpleCmd for GetVersionString {
524 const CMD_LEN: usize = 6;
525 type Response = usize;
526
527 fn get_cmd_hex(&self, buf: &mut [u8]) -> Result<usize, Error> {
528 check_bufsz(GetVersionString::CMD_LEN, buf)?;
529 copy_all_bytes(buf, "0004".as_bytes());
530 hex::bytes_to_hex(&[0xFFu8], &mut buf[4..])?;
531 Ok(GetVersionString::CMD_LEN)
532 }
533
534 fn parse_response(&self, buf: &mut [u8]) -> Result<usize, Error> {
535 const MAX_RESP_LEN: usize = 0xFF;
536 let mut resp_len = [0u8];
537 hex::hex_to_bytes(&[buf[0], buf[1]], &mut resp_len)?;
538 let resp_len = resp_len[0] as usize;
539
540 if resp_len * 2 != buf.len() - 2 || resp_len > MAX_RESP_LEN {
541 return Err(Error::BadResponse(resp_len));
542 }
543
544 let mut resp_buf = [0u8; MAX_RESP_LEN];
545 hex::hex_to_bytes(&buf[2..], &mut resp_buf)?;
546 copy_all_bytes(buf, &resp_buf[..resp_len]);
547 Ok(resp_len)
548 }
549 }
550
551 pub struct SearchTag;
557
558 impl SimpleCmd for SearchTag {
559 const CMD_LEN: usize = 6;
560 type Response = Option<usize>;
561
562 fn get_cmd_hex(&self, buf: &mut [u8]) -> Result<usize, Error> {
563 check_bufsz(SearchTag::CMD_LEN, buf)?;
564 copy_all_bytes(buf, "0500".as_bytes());
565 hex::bytes_to_hex(&[0xFFu8], &mut buf[4..])?;
566 Ok(SearchTag::CMD_LEN)
567 }
568 }
569}