1#![allow(dead_code)]
2#![allow(unused_imports)]
3
4use arrayvec::ArrayVec;
5
6use addr::EEPReadData;
7use addr::RamReadData;
8use addr::WritableEEPAddr;
9use addr::WritableRamAddr;
10
11pub const TRAME_READER_INTERNAL_BUFFER_SIZE: usize = 64;
13
14#[derive(Debug, PartialEq, Eq)]
16pub struct ACKPacket {
17 pub pid: u8,
19 pub cmd: Command,
21 pub error: StatusError,
23 pub detail: StatusDetail,
25}
26
27impl From<RawACKPacket> for ACKPacket {
28 fn from(packet: RawACKPacket) -> ACKPacket {
29 ACKPacket {
30 pid: packet.pid,
31 cmd: packet.cmd,
32 error: packet.error,
33 detail: packet.detail,
34 }
35 }
36}
37
38#[derive(Debug, PartialEq, Eq)]
39struct RawACKPacket {
40 pub psize: u8,
42 pub pid: u8,
44 pub cmd: Command,
46 pub chk1: u8,
48 pub chk2: u8,
50 pub error: StatusError,
52 pub detail: StatusDetail,
54}
55
56impl RawACKPacket {
57 pub fn is_valid(&self) -> bool {
58 use addr::ReadableEEPAddr;
59 use addr::ReadableRamAddr;
60 use reader::Command::*;
61
62 let mut chk1 = self.psize;
64 chk1 ^= self.pid;
65 chk1 ^= u8::from(self.cmd);
66
67 match self.cmd {
68 Command::EEPRead { data } => {
69 let a: u8 = data.addr.into();
70 chk1 ^= a;
71 chk1 ^= data.data_len;
72 for i in &data.data[0..data.data_len as usize] {
73 chk1 ^= i;
74 }
75 }
76 Command::RamRead { data } => {
77 let a: u8 = data.addr.into();
78 chk1 ^= a;
79 chk1 ^= data.data_len;
80 for i in &data.data[0..data.data_len as usize] {
81 chk1 ^= i;
82 }
83 }
84 _ => (),
85 };
86 chk1 &= 0xFE;
87 self.chk1 == chk1 && self.chk2 == !chk1 & 0xFE
88 }
89}
90
91impl Into<Command> for RawACKPacket {
92 fn into(self) -> Command {
93 self.cmd
94 }
95}
96
97#[derive(Copy, Clone, Debug, PartialEq, Eq)]
99pub enum Command {
100 EEPWrite,
102 EEPRead {
104 data: EEPReadData,
106 },
107 RamWrite,
109 RamRead {
111 data: RamReadData,
113 },
114 IJog,
116 SJog,
118 Stat,
120 Rollback,
122 Reboot,
124}
125
126#[derive(Copy, Clone, Debug, PartialEq)]
127enum InternalCommand {
128 EEPWrite,
129 EEPRead,
130 RamWrite,
131 RamRead,
132 IJog,
133 SJog,
134 Stat,
135 Rollback,
136 Reboot,
137}
138
139impl InternalCommand {
140 fn inject_payload(self, payload: AssociatedData) -> Command {
141 use self::Command::*;
142 match (self, payload) {
143 (InternalCommand::EEPWrite, AssociatedData::Nothing) => EEPWrite,
144 (InternalCommand::RamWrite, AssociatedData::Nothing) => RamWrite,
145 (InternalCommand::IJog, AssociatedData::Nothing) => IJog,
146 (InternalCommand::SJog, AssociatedData::Nothing) => SJog,
147 (InternalCommand::Stat, AssociatedData::Nothing) => Stat,
148 (InternalCommand::Rollback, AssociatedData::Nothing) => Rollback,
149 (InternalCommand::Reboot, AssociatedData::Nothing) => Reboot,
150 (InternalCommand::EEPRead, AssociatedData::EEP(data)) => EEPRead { data },
151 (InternalCommand::RamRead, AssociatedData::Ram(data)) => RamRead { data },
152 _ => unreachable!(),
153 }
154 }
155}
156
157impl From<Command> for u8 {
158 fn from(cmd: Command) -> Self {
159 use reader::Command::*;
160 match cmd {
161 EEPWrite => 0x41,
162 EEPRead { .. } => 0x42,
163 RamWrite => 0x43,
164 RamRead { .. } => 0x44,
165 IJog => 0x45,
166 SJog => 0x46,
167 Stat => 0x47,
168 Rollback => 0x48,
169 Reboot => 0x49,
170 }
171 }
172}
173
174#[allow(missing_docs)]
176#[derive(Copy, Clone, Debug, PartialEq, Eq)]
177pub enum StatusError {
178 ExceedInputVoltageLimit,
179 ExceedAllowedPOTLimit,
180 ExceedTemperatureLimit,
181 InvalidPacket,
182 OverloadDetected,
183 DriverFaultDetected,
184 EEPREGDistorded,
185 NoError,
186}
187
188#[allow(missing_docs)]
190#[derive(Copy, Clone, Debug, PartialEq, Eq)]
191pub enum StatusDetail {
192 MovingFlag,
193 ImpositionFlag,
194 ChecksumError,
195 UnknownCommand,
196 ExceedREGRange,
197 GarbageDetected,
198 MotorOnFlag,
199 NoDetail,
200}
201
202#[derive(Copy, Clone, Debug)]
203enum AssociatedData {
204 EEP(EEPReadData),
205 Ram(RamReadData),
206 Nothing,
207}
208
209pub struct ACKReader {
212 state: ReaderState,
213 buffer: ArrayVec<[ACKPacket; TRAME_READER_INTERNAL_BUFFER_SIZE]>,
214}
215
216impl Default for ACKReader {
217 fn default() -> ACKReader {
218 ACKReader {
219 state: ReaderState::H1,
220 buffer: ArrayVec::new(),
221 }
222 }
223}
224
225#[derive(Debug, Clone, Copy)]
227enum ReaderState {
228 H1,
229 H2,
230 Psize,
231 Pid {
232 size: u8,
233 },
234 Cmd {
235 size: u8,
236 pid: u8,
237 },
238 Checksum1 {
239 size: u8,
240 pid: u8,
241 cmd: InternalCommand,
242 },
243 Checksum2 {
244 size: u8,
245 pid: u8,
246 cmd: InternalCommand,
247 chk1: u8,
248 },
249 DataAddr {
250 size: u8,
251 pid: u8,
252 cmd: InternalCommand,
253 chk1: u8,
254 chk2: u8,
255 },
256 DataLenEEP {
257 size: u8,
258 pid: u8,
259 cmd: InternalCommand,
260 chk1: u8,
261 chk2: u8,
262 data: EEPReadData,
263 },
264 Data1EEP {
265 size: u8,
266 pid: u8,
267 cmd: InternalCommand,
268 chk1: u8,
269 chk2: u8,
270 data: EEPReadData,
271 },
272 Data2EEP {
273 size: u8,
274 pid: u8,
275 cmd: InternalCommand,
276 chk1: u8,
277 chk2: u8,
278 data: EEPReadData,
279 },
280 DataLenRAM {
281 size: u8,
282 pid: u8,
283 cmd: InternalCommand,
284 chk1: u8,
285 chk2: u8,
286 data: RamReadData,
287 },
288 Data1RAM {
289 size: u8,
290 pid: u8,
291 cmd: InternalCommand,
292 chk1: u8,
293 chk2: u8,
294 data: RamReadData,
295 },
296 Data2RAM {
297 size: u8,
298 pid: u8,
299 cmd: InternalCommand,
300 chk1: u8,
301 chk2: u8,
302 data: RamReadData,
303 },
304 Error {
305 size: u8,
306 pid: u8,
307 cmd: InternalCommand,
308 chk1: u8,
309 chk2: u8,
310 payload: AssociatedData,
311 },
312 Detail {
313 size: u8,
314 pid: u8,
315 cmd: InternalCommand,
316 chk1: u8,
317 chk2: u8,
318 payload: AssociatedData,
319 status_error: StatusError,
320 },
321}
322
323impl ReaderState {
324 fn step(&mut self, byte: u8) -> Option<RawACKPacket> {
325 use addr::EEPReadData;
326 use addr::RamReadData;
327 use addr::ReadableEEPAddr;
328 use addr::ReadableRamAddr;
329 use addr::WritableEEPAddr::*;
330 use addr::WritableRamAddr::*;
331 use reader::AssociatedData::*;
332 use reader::InternalCommand::*;
333 use reader::ReaderState::*;
334 use reader::StatusDetail::*;
335 use reader::StatusError::*;
336 use try_from::TryFrom;
337
338 let mut result: Option<RawACKPacket> = None;
339 match *self {
340 H1 => *self = H2,
341 H2 => *self = Psize,
342 Psize => *self = Pid { size: byte },
343 Pid { size } => *self = Cmd { size, pid: byte },
344 Cmd { size, pid } => {
345 let mut command: Option<InternalCommand> = None;
346 match byte {
347 0x41 => command = Some(EEPWrite),
348 0x42 => command = Some(EEPRead),
349 0x43 => command = Some(RamWrite),
350 0x44 => command = Some(RamRead),
351 0x45 => command = Some(IJog),
352 0x46 => command = Some(SJog),
353 0x47 => command = Some(Stat),
354 0x48 => command = Some(Rollback),
355 0x49 => command = Some(Reboot),
356 _ => *self = H1,
357 }
358 if let Some(command) = command {
359 *self = Checksum1 {
360 size,
361 pid,
362 cmd: command,
363 }
364 }
365 }
366 Checksum1 { size, pid, cmd } => {
367 *self = Checksum2 {
368 size,
369 pid,
370 cmd,
371 chk1: byte,
372 }
373 }
374 Checksum2 {
375 size,
376 pid,
377 cmd,
378 chk1,
379 }
380 if (cmd == EEPRead || cmd == RamRead) =>
381 {
382 *self = DataAddr {
383 size,
384 pid,
385 cmd,
386 chk1,
387 chk2: byte,
388 }
389 }
390 Checksum2 {
391 size,
392 pid,
393 cmd,
394 chk1,
395 } => {
396 *self = Error {
397 size,
398 pid,
399 cmd,
400 chk1,
401 chk2: byte,
402 payload: Nothing,
403 }
404 }
405 DataAddr {
406 size,
407 pid,
408 cmd,
409 chk1,
410 chk2,
411 } => match cmd {
412 EEPRead => {
413 *self = match TryFrom::try_from(byte) {
414 Ok(data_addr) => DataLenEEP {
415 size,
416 pid,
417 cmd,
418 chk1,
419 chk2,
420 data: EEPReadData {
421 addr: data_addr,
422 data_len: 0,
423 data: [0, 0],
424 },
425 },
426 Err(_) => H1,
427 }
428 }
429 RamRead => {
430 *self = match TryFrom::try_from(byte) {
431 Ok(data_addr) => DataLenRAM {
432 size,
433 pid,
434 cmd,
435 chk1,
436 chk2,
437 data: RamReadData {
438 addr: data_addr,
439 data_len: 0,
440 data: [0, 0],
441 },
442 },
443 Err(_) => H1,
444 }
445 }
446 _ => unreachable!(),
447 },
448 DataLenEEP {
449 size,
450 pid,
451 cmd,
452 chk1,
453 chk2,
454 data,
455 } => {
456 let new_data = EEPReadData {
457 addr: data.addr,
458 data_len: byte,
459 data: [0, 0],
460 };
461 *self = Data1EEP {
462 size,
463 pid,
464 cmd,
465 chk1,
466 chk2,
467 data: new_data,
468 };
469 }
470 DataLenRAM {
471 size,
472 pid,
473 cmd,
474 chk1,
475 chk2,
476 data,
477 } => {
478 let new_data = RamReadData {
479 addr: data.addr,
480 data_len: byte,
481 data: [0, 0],
482 };
483 *self = Data1RAM {
484 size,
485 pid,
486 cmd,
487 chk1,
488 chk2,
489 data: new_data,
490 }
491 }
492 Data1EEP {
493 size,
494 pid,
495 chk1,
496 chk2,
497 data,
498 ..
499 } => {
500 let new_data = EEPReadData {
501 addr: data.addr,
502 data_len: data.data_len,
503 data: [byte, 0],
504 };
505 if data.data_len == 2 {
506 *self = Data2EEP {
507 size,
508 pid,
509 cmd: InternalCommand::EEPRead,
510 chk1,
511 chk2,
512 data: new_data,
513 }
514 } else {
515 *self = Error {
516 size,
517 pid,
518 cmd: InternalCommand::EEPRead,
519 chk1,
520 chk2,
521 payload: AssociatedData::EEP(new_data),
522 }
523 }
524 }
525 Data2EEP {
526 size,
527 pid,
528 cmd,
529 chk1,
530 chk2,
531 data,
532 } => {
533 let new_data = EEPReadData {
534 addr: data.addr,
535 data_len: data.data_len,
536 data: [data.data[0], byte],
537 };
538 *self = Error {
539 size,
540 pid,
541 cmd,
542 chk1,
543 chk2,
544 payload: AssociatedData::EEP(new_data),
545 }
546 }
547 Data1RAM {
548 size,
549 pid,
550 chk1,
551 chk2,
552 data,
553 ..
554 } => {
555 let new_data = RamReadData {
556 addr: data.addr,
557 data_len: data.data_len,
558 data: [byte, 0],
559 };
560 if data.data_len == 2 {
561 *self = Data2RAM {
562 size,
563 pid,
564 cmd: InternalCommand::RamRead,
565 chk1,
566 chk2,
567 data: new_data,
568 }
569 } else {
570 *self = Error {
571 size,
572 pid,
573 cmd: InternalCommand::RamRead,
574 chk1,
575 chk2,
576 payload: AssociatedData::Ram(new_data),
577 }
578 }
579 }
580 Data2RAM {
581 size,
582 pid,
583 cmd,
584 chk1,
585 chk2,
586 data,
587 } => {
588 let new_data = RamReadData {
589 addr: data.addr,
590 data_len: data.data_len,
591 data: [data.data[0], byte],
592 };
593 *self = Error {
594 size,
595 pid,
596 cmd,
597 chk1,
598 chk2,
599 payload: AssociatedData::Ram(new_data),
600 }
601 }
602 Error {
603 size,
604 pid,
605 cmd,
606 chk1,
607 chk2,
608 payload,
609 } => {
610 let status_error = match byte {
611 0x00 => Some(NoError),
612 0x01 => Some(ExceedInputVoltageLimit),
613 0x02 => Some(ExceedAllowedPOTLimit),
614 0x04 => Some(ExceedTemperatureLimit),
615 0x08 => Some(InvalidPacket),
616 0x10 => Some(OverloadDetected),
617 0x20 => Some(DriverFaultDetected),
618 0x40 => Some(EEPREGDistorded),
619 _ => None,
620 };
621 if let Some(valid_error) = status_error {
622 *self = Detail {
623 size,
624 pid,
625 cmd,
626 chk1,
627 chk2,
628 payload,
629 status_error: valid_error,
630 };
631 } else {
632 *self = H1;
633 }
634 }
635 Detail {
636 size,
637 pid,
638 cmd,
639 chk1,
640 chk2,
641 payload,
642 status_error,
643 } => {
644 let mut status_detail = None;
645 match byte {
646 0x00 => status_detail = Some(NoDetail),
647 0x01 => status_detail = Some(MovingFlag),
648 0x02 => status_detail = Some(ImpositionFlag),
649 0x04 => status_detail = Some(ChecksumError),
650 0x08 => status_detail = Some(UnknownCommand),
651 0x10 => status_detail = Some(ExceedREGRange),
652 0x20 => status_detail = Some(GarbageDetected),
653 0x40 => status_detail = Some(MotorOnFlag),
654 _ => (),
655 };
656 if let Some(status_detail) = status_detail {
657 result = self.make_packet(
658 size,
659 pid,
660 cmd,
661 chk1,
662 chk2,
663 payload,
664 status_error,
665 status_detail,
666 );
667 }
668 *self = H1;
669 }
670 };
671 result
672 }
673
674 fn make_packet(
675 &mut self,
676 size: u8,
677 pid: u8,
678 cmd: InternalCommand,
679 chk1: u8,
680 chk2: u8,
681 payload: AssociatedData,
682 status_error: StatusError,
683 status_detail: StatusDetail,
684 ) -> Option<RawACKPacket> {
685 let cmd = cmd.inject_payload(payload);
686 let packet = RawACKPacket {
687 psize: size,
688 pid,
689 cmd,
690 chk1,
691 chk2,
692 error: status_error,
693 detail: status_detail,
694 };
695 if packet.is_valid() {
696 Some(packet)
697 } else {
698 None
699 }
700 }
701}
702
703impl ACKReader {
704 pub fn new() -> ACKReader {
706 ACKReader {
707 state: ReaderState::H1,
708 buffer: ArrayVec::new(),
709 }
710 }
711
712 pub fn pop_ack_packet(&mut self) -> Option<ACKPacket> {
714 self.buffer.pop()
715 }
716
717 pub fn available_messages(&mut self) -> usize {
719 self.buffer.len()
720 }
721
722 pub fn parse(&mut self, buf: &[u8]) {
724 for byte in buf {
725 if let Some(trame) = self.state.step(*byte) {
726 self.buffer.push(ACKPacket::from(trame));
727 }
728 }
729 }
730}
731
732#[cfg(test)]
733mod test {
734 use addr::*;
735 use reader::{
736 ACKPacket, ACKReader, AssociatedData, Command, RawACKPacket, StatusDetail, StatusError,
737 };
738
739 fn test_eepread() {
741 let mut reader = ACKReader::new();
742
743 let packet_eepread = [
746 0xFF, 0xFF, 0x0F, 0xFD, 0x42, 0x14, 0xEA, 0x1E, 0x02, 0xB8, 0x01, 0x08, 0x20,
747 ];
748
749 reader.parse(&packet_eepread);
750
751 let data_eepread = EEPReadData {
752 addr: ReadableEEPAddr::PositionKp,
753 data_len: 2,
754 data: [0xB8, 0x01],
755 };
756
757 assert_eq!(
758 reader.pop_ack_packet().unwrap(),
759 ACKPacket {
760 pid: 0xFD,
761 cmd: Command::EEPRead { data: data_eepread },
762 error: StatusError::InvalidPacket,
763 detail: StatusDetail::GarbageDetected,
764 }
765 );
766 }
767
768 fn test_ramread() {
770 let mut reader = ACKReader::new();
771
772 let packet_ramread = [
775 0xFF, 0xFF, 0x0C, 0xFD, 0x44, 0xA0, 0x5E, 0x14, 0x01, 0x01, 0x10, 0x40,
776 ];
777
778 reader.parse(&packet_ramread);
779
780 let data_ramread = RamReadData {
781 addr: ReadableRamAddr::MinPosition, data_len: 1,
783 data: [0x01, 0x00],
784 };
785
786 assert_eq!(
787 reader.pop_ack_packet().unwrap(),
788 ACKPacket {
789 pid: 0xFD,
790 cmd: Command::RamRead { data: data_ramread },
791 error: StatusError::OverloadDetected,
792 detail: StatusDetail::MotorOnFlag,
793 }
794 );
795 }
796
797 #[test]
798 fn test_sjog() {
799 let mut reader = ACKReader::new();
800
801 let packet_sjog = [
804 0xFF, 0xFF, 0x09, 0xFD, 0x46, 0xB2, 0x4C, 0x08, 0x08,
805 ];
806
807 reader.parse(&packet_sjog);
808
809 assert_eq!(
810 reader.pop_ack_packet().unwrap(),
811 ACKPacket {
812 pid: 0xFD,
813 cmd: Command::SJog,
814 error: StatusError::InvalidPacket,
815 detail: StatusDetail::UnknownCommand,
816 }
817 );
818 }
819}