opentitanlib/test_utils/
rpc.rs1use anyhow::Result;
5use crc::{CRC_32_ISO_HDLC, Crc};
6use serde::Serialize;
7use serde::de::DeserializeOwned;
8use std::time::Duration;
9
10use crate::io::console::ext::{PassFail, PassFailResult};
11use crate::io::console::{ConsoleDevice, ConsoleError, ConsoleExt};
12use crate::regex;
13use crate::test_utils::status::Status;
14
15include!(env!("ottf"));
17
18pub trait ConsoleSend<T>
19where
20 T: ConsoleDevice + ?Sized,
21{
22 fn send(&self, device: &T) -> Result<String>;
23 fn send_with_crc(&self, device: &T) -> Result<String>;
24}
25
26impl<T, U> ConsoleSend<T> for U
27where
28 T: ConsoleDevice + ?Sized,
29 U: Serialize,
30{
31 fn send(&self, device: &T) -> Result<String> {
32 let s = serde_json::to_string(self)?;
33 log::info!("Sending: {}", s);
34 device.write(s.as_bytes())?;
35 Ok(s)
36 }
37
38 fn send_with_crc(&self, device: &T) -> Result<String> {
39 let s = serde_json::to_string(self)?;
40 log::info!("Sending: {}", s);
41 device.write(s.as_bytes())?;
42 let actual_crc = OttfCrc {
43 crc: Crc::<u32>::new(&CRC_32_ISO_HDLC).checksum(s.as_bytes()),
44 };
45 let crc_s = actual_crc.send(device)?;
46 Ok(s + &crc_s)
47 }
48}
49
50pub trait ConsoleRecv<T>
51where
52 T: ConsoleDevice + ?Sized,
53{
54 fn recv(device: &T, timeout: Duration, quiet: bool) -> Result<Self>
55 where
56 Self: Sized;
57}
58
59impl<T, U> ConsoleRecv<T> for U
60where
61 T: ConsoleDevice + ?Sized,
62 U: DeserializeOwned,
63{
64 fn recv(device: &T, timeout: Duration, quiet: bool) -> Result<Self>
65 where
66 Self: Sized,
67 {
68 let device: &dyn ConsoleDevice = if quiet { &device } else { &device.logged() };
69 let result = device.wait_for_line(
70 PassFail(
71 regex!(r"RESP_OK:(.*) CRC:([0-9]+)"),
72 regex!(r"RESP_ERR:(.*) CRC:([0-9]+)"),
73 ),
74 timeout,
75 )?;
76 println!();
77 match result {
78 PassFailResult::Pass(cap) => {
79 let json_str = &cap[1];
80 let crc_str = &cap[2];
81 check_crc(json_str, crc_str)?;
82 Ok(serde_json::from_str::<Self>(json_str)?)
83 }
84 PassFailResult::Fail(cap) => {
85 let json_str = &cap[1];
86 let crc_str = &cap[2];
87 check_crc(json_str, crc_str)?;
88 Err(serde_json::from_str::<Status>(json_str)?)?
89 }
90 }
91 }
92}
93
94fn check_crc(json_str: &str, crc_str: &str) -> Result<()> {
95 let crc = crc_str.parse::<u32>()?;
96 let actual_crc = Crc::<u32>::new(&CRC_32_ISO_HDLC).checksum(json_str.as_bytes());
97 if crc != actual_crc {
98 return Err(
99 ConsoleError::GenericError("CRC didn't match received json body.".into()).into(),
100 );
101 }
102 Ok(())
103}