cat_dev/mion/cgis/
dump_eeprom.rs1use crate::{
5 errors::NetworkError,
6 mion::{
7 cgis::{do_simple_request, encode_url_parameters},
8 proto::cgis::MionCGIErrors,
9 },
10};
11use bytes::{BufMut, Bytes, BytesMut};
12use reqwest::{Client, Method};
13use std::{fmt::Display, net::Ipv4Addr, ops::Deref, time::Duration};
14use tracing::debug;
15
16const EEPROM_MAX_ADDRESS: usize = 0x1E00;
17const TABLE_START_SIGIL: &str = "<table border=0 cellspacing=3 cellpadding=3>";
18const TABLE_END_SIGIL: &str = "</table>";
19
20pub async fn dump_eeprom(mion_ip: Ipv4Addr) -> Result<Bytes, NetworkError> {
30 dump_eeprom_with_raw_client(&Client::default(), mion_ip).await
31}
32
33pub async fn dump_eeprom_with_raw_client(
43 client: &Client,
44 mion_ip: Ipv4Addr,
45) -> Result<Bytes, NetworkError> {
46 let mut memory_buffer = BytesMut::with_capacity(0x2000);
47
48 while memory_buffer.len() <= EEPROM_MAX_ADDRESS {
49 debug!(
50 bridge.ip = %mion_ip,
51 address = %format!("{:04X}", memory_buffer.len()),
52 "Dumping eeprom memory area",
53 );
54
55 let body_as_string = do_raw_eeprom_request(
56 client,
57 mion_ip,
58 &[("start_addr", format!("{:04X}", memory_buffer.len()))],
59 )
60 .await?;
61
62 let table = extract_memory_table_body(&body_as_string)?;
63 for table_row in table.split("<tr>").skip(3) {
64 for table_column in table_row
65 .trim()
66 .trim_end_matches("</tbody>")
67 .trim_end()
68 .trim_end_matches("</tr>")
69 .trim_end()
70 .replace("</td>", "")
71 .split("<td>")
72 .skip(3)
73 {
74 if table_column.trim().len() != 2 {
75 return Err(MionCGIErrors::HtmlResponseBadByte(table_column.to_owned()).into());
76 }
77 memory_buffer
78 .put_u8(u8::from_str_radix(table_column.trim(), 16).map_err(|_| {
79 MionCGIErrors::HtmlResponseBadByte(table_column.to_owned())
80 })?);
81 }
82 }
83 }
84
85 Ok(memory_buffer.freeze())
86}
87
88fn extract_memory_table_body(body: &str) -> Result<String, MionCGIErrors> {
89 let start = body
90 .find(TABLE_START_SIGIL)
91 .ok_or_else(|| MionCGIErrors::HtmlResponseMissingMemoryDumpSigil(body.to_owned()))?;
92 let body_minus_start = &body[start + TABLE_START_SIGIL.len()..];
93 let end = body_minus_start
94 .find(TABLE_END_SIGIL)
95 .ok_or_else(|| MionCGIErrors::HtmlResponseMissingMemoryDumpSigil(body.to_owned()))?;
96
97 Ok(body_minus_start[..end].to_owned())
98}
99
100pub async fn do_raw_eeprom_request(
111 client: &Client,
112 mion_ip: Ipv4Addr,
113 url_parameters: &[(impl Deref<Target = str>, impl Display)],
114) -> Result<String, NetworkError> {
115 do_simple_request::<String>(
116 client,
117 Method::POST,
118 format!("http://{mion_ip}/dbg/eeprom_dump.cgi"),
119 Some(encode_url_parameters(url_parameters)),
120 Some(Duration::from_secs(60)),
122 )
123 .await
124}