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}