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<()>;
23 fn send_with_crc(&self, device: &T) -> Result<()>;
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<()> {
32 let s = serde_json::to_string(self)?;
33 log::info!("Sending: {}", s);
34 device.write(s.as_bytes())?;
35 Ok(())
36 }
37
38 fn send_with_crc(&self, device: &T) -> Result<()> {
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 actual_crc.send(device)
46 }
47}
48
49pub trait ConsoleRecv<T>
50where
51 T: ConsoleDevice + ?Sized,
52{
53 fn recv(device: &T, timeout: Duration, quiet: bool) -> Result<Self>
54 where
55 Self: Sized;
56}
57
58impl<T, U> ConsoleRecv<T> for U
59where
60 T: ConsoleDevice + ?Sized,
61 U: DeserializeOwned,
62{
63 fn recv(device: &T, timeout: Duration, quiet: bool) -> Result<Self>
64 where
65 Self: Sized,
66 {
67 let device: &dyn ConsoleDevice = if quiet { &device } else { &device.logged() };
68 let result = device.wait_for_line(
69 PassFail(
70 regex!(r"RESP_OK:(.*) CRC:([0-9]+)"),
71 regex!(r"RESP_ERR:(.*) CRC:([0-9]+)"),
72 ),
73 timeout,
74 )?;
75 println!();
76 match result {
77 PassFailResult::Pass(cap) => {
78 let json_str = &cap[1];
79 let crc_str = &cap[2];
80 check_crc(json_str, crc_str)?;
81 Ok(serde_json::from_str::<Self>(json_str)?)
82 }
83 PassFailResult::Fail(cap) => {
84 let json_str = &cap[1];
85 let crc_str = &cap[2];
86 check_crc(json_str, crc_str)?;
87 Err(serde_json::from_str::<Status>(json_str)?)?
88 }
89 }
90 }
91}
92
93fn check_crc(json_str: &str, crc_str: &str) -> Result<()> {
94 let crc = crc_str.parse::<u32>()?;
95 let actual_crc = Crc::<u32>::new(&CRC_32_ISO_HDLC).checksum(json_str.as_bytes());
96 if crc != actual_crc {
97 return Err(
98 ConsoleError::GenericError("CRC didn't match received json body.".into()).into(),
99 );
100 }
101 Ok(())
102}