bm1397_protocol/
response.rs

1use crate::crc::crc5;
2use crate::registers::Register;
3use crate::Error;
4use byteorder::{BigEndian, ByteOrder};
5
6#[derive(Debug)]
7pub struct RegisterResponse {
8    pub value: u32,
9    pub chip_addr: u8,
10    pub register: Register,
11}
12
13#[derive(Debug)]
14pub struct JobResponse {
15    pub nonce: u32,
16    pub job_id: u8,
17    pub midstate_id: u8,
18}
19
20#[derive(Debug)]
21pub enum ResponseType {
22    Reg(RegisterResponse),
23    Job(JobResponse),
24}
25
26pub struct Response;
27
28impl Response {
29    /// # Parse Response
30    ///
31    /// Parse raw bytes from RO signal of BM1397.
32    ///
33    /// The packet must have a lenght of 9 bytes.
34    ///
35    /// ## Return
36    /// - `Err(Error::InvalidPreamble)` if it first 2 bytes are not `[0xAA, 0x55]`.
37    /// - `Err(Error::InvalidCrc)` if the CRC5 is not valid.
38    /// - `Ok(ResponseType::Reg(r))` with the `RegisterResponse`.
39    /// - `Err(Error::UnknownRegister(u8))` with the register address if it do not match a known `Register`.
40    /// - `Ok(ResponseType::Job(j))` with the `JobResponse`.
41    ///
42    /// ## Example
43    ///
44    /// ```
45    /// use bm1397_protocol::{Error, Register, Response, ResponseType};
46    ///
47    /// // Error::InvalidPreamble
48    /// let resp = Response::parse(&[0x00,0x55,0x13,0x97,0x18,0x00,0x00,0x00,0x06]);
49    /// assert!(resp.is_err());
50    /// assert_eq!(resp.unwrap_err(), Error::InvalidPreamble);
51    ///
52    /// let resp = Response::parse(&[0xAA,0x00,0x13,0x97,0x18,0x00,0x00,0x00,0x06]);
53    /// assert!(resp.is_err());
54    /// assert_eq!(resp.unwrap_err(), Error::InvalidPreamble);
55    ///
56    /// let resp = Response::parse(&[0x00,0x00,0x13,0x97,0x18,0x00,0x00,0x00,0x06]);
57    /// assert!(resp.is_err());
58    /// assert_eq!(resp.unwrap_err(), Error::InvalidPreamble);
59    ///
60    /// // Error::InvalidCrc
61    /// let resp = Response::parse(&[0xAA,0x55,0x13,0x97,0x18,0x00,0x00,0x00,0x00]);
62    /// assert!(resp.is_err());
63    /// assert_eq!(resp.unwrap_err(), Error::InvalidCrc);
64    ///
65    /// // Register::ChipAddress == 0x13971800
66    /// let resp = Response::parse(&[0xAA,0x55,0x13,0x97,0x18,0x00,0x00,0x00,0x06]);
67    /// assert!(resp.is_ok());
68    /// match resp.unwrap() {
69    ///     ResponseType::Reg(r) => {
70    ///         assert_eq!(r.value, 0x13971800);
71    ///         assert_eq!(r.chip_addr, 0);
72    ///         assert_eq!(r.register, Register::ChipAddress);
73    ///     },
74    ///     _ => panic!(),
75    /// };
76    ///
77    /// // Error::UnknownRegister(0xF0)
78    /// let resp = Response::parse(&[0xAA,0x55,0x00,0x00,0x00,0x00,0x04,0xF0,0x03]);
79    /// assert!(resp.is_err());
80    /// assert_eq!(resp.unwrap_err(), Error::UnknownRegister(0xF0));
81    ///
82    /// // Nonce == 0x97C328B6
83    /// let resp = Response::parse(&[0xAA,0x55,0x97,0xC3,0x28,0xB6,0x01,0x63,0x9C]);
84    /// assert!(resp.is_ok());
85    /// match resp.unwrap() {
86    ///     ResponseType::Job(j) => {
87    ///         assert_eq!(j.nonce, 0x97C328B6);
88    ///         assert_eq!(j.midstate_id, 1);
89    ///         assert_eq!(j.job_id, 0x63);
90    ///     },
91    ///     _ => panic!(),
92    /// };
93    /// ```
94    pub fn parse(data: &[u8; 9]) -> Result<ResponseType, Error> {
95        if data[0] != 0xAA || data[1] != 0x55 {
96            return Err(Error::InvalidPreamble);
97        }
98        if crc5(&data[2..9]) != 0x00 {
99            return Err(Error::InvalidCrc);
100        }
101        if data[8] & 0x80 == 0x80 {
102            return Ok(ResponseType::Job(JobResponse {
103                nonce: BigEndian::read_u32(&data[2..]),
104                midstate_id: data[6],
105                job_id: data[7],
106            }));
107        }
108        match Register::try_from(data[7]) {
109            Err(e) => Err(Error::UnknownRegister(e)),
110            Ok(r) => Ok(ResponseType::Reg(RegisterResponse {
111                value: BigEndian::read_u32(&data[2..]),
112                chip_addr: data[6],
113                register: r,
114            })),
115        }
116    }
117}