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