rxprog/command/
command.rs1use std::fmt;
2use std::io;
3use std::num::Wrapping;
4
5use crate::Result;
6
7pub trait Command {
9 type Response;
11
12 fn execute<T: io::Read + io::Write>(&self, p: &mut T) -> Result<Self::Response>;
14}
15
16pub trait Transmit {
17 fn tx<T: io::Write>(&self, p: &mut T) -> Result<()>;
18}
19
20pub struct CommandData {
21 pub opcode: u8,
22 pub has_size_field: bool,
23 pub payload: Vec<u8>,
24}
25
26impl CommandData {
27 fn bytes(&self) -> Vec<u8> {
28 let mut bytes = vec![];
29 let payload = &self.payload;
30 let payload_size = payload.len();
31
32 bytes.push(self.opcode);
33
34 if self.has_size_field {
35 bytes.push(payload_size as u8);
36 }
37
38 bytes.extend(payload);
39
40 if payload_size != 0 {
41 let sum = bytes.iter().map(|x| Wrapping(*x)).sum::<Wrapping<u8>>();
42 let checksum = !sum + Wrapping::<u8>(1);
43 bytes.push(checksum.0);
44 }
45
46 bytes
47 }
48}
49
50pub trait TransmitCommandData {
51 fn command_data(&self) -> CommandData;
52}
53
54impl<T: TransmitCommandData> Transmit for T {
55 fn tx<U: io::Write>(&self, p: &mut U) -> Result<()> {
56 p.write(&self.command_data().bytes())?;
57 p.flush()?;
58
59 Ok(())
60 }
61}
62
63pub trait Receive {
64 type Response;
65
66 fn rx<T: io::Read>(&self, p: &mut T) -> Result<Self::Response>;
67}
68
69impl<T: Transmit + Receive> Command for T {
70 type Response = T::Response;
71
72 fn execute<U: io::Read + io::Write>(&self, p: &mut U) -> Result<Self::Response> {
73 self.tx(p)?;
74 self.rx(p)
75 }
76}
77
78#[derive(Copy, Clone, Debug, PartialEq)]
80pub enum CommandError {
81 Address,
83 BitRateSelection,
86 BlockNumber,
88 Checksum,
90 ClockMode,
92 DataSize,
95 DeviceCode,
97 Erasure,
99 IDCodeMismatch,
101 InputFrequency,
103 MultiplicationRatio,
105 OperatingFrequency,
107 Programming,
109 ProgrammingErasureStateTransition,
111}
112
113impl fmt::Display for CommandError {
114 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115 write!(
116 f,
117 "{}",
118 match self {
119 CommandError::Address => "invalid address/area",
120 CommandError::BitRateSelection => "bit rate selection error too high",
121 CommandError::BlockNumber => "invalid block number",
122 CommandError::Checksum => "checksum mismatch",
123 CommandError::ClockMode => "invalid clock mode",
124 CommandError::DataSize => "invalid data size",
125 CommandError::DeviceCode => "invalid device code",
126 CommandError::Erasure => "erasure error",
127 CommandError::IDCodeMismatch => "ID code mismatch",
128 CommandError::InputFrequency => "input frequency out of range",
129 CommandError::MultiplicationRatio => "invalid multiplication ratio",
130 CommandError::OperatingFrequency => "calculated operating frequency out of range",
131 CommandError::Programming => "programming error",
132 CommandError::ProgrammingErasureStateTransition => {
133 "failed to transition into programming/erasure state"
134 }
135 }
136 )
137 }
138}