cat_dev/mion/cgis/
dump_eeprom.rs

1//! API's for interacting with `/dbg/eeprom_dump.cgi`, a page for live
2//! accessing the memory of the EEPROM on the MION devices.
3
4use 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
18/// Dump the existing EEPROM for a MION.
19///
20/// ## Errors
21///
22/// - If we cannot encode the parameters as a form url encoded.
23/// - If we cannot make the HTTP request.
24/// - If the server does not respond with a 200.
25/// - If we cannot read the body from HTTP.
26/// - If we cannot parse the HTML response.
27pub async fn dump_eeprom(mion_ip: Ipv4Addr) -> Result<Bytes, NetworkError> {
28	dump_eeprom_with_raw_client(&Client::default(), mion_ip).await
29}
30
31/// Perform an EEPROM DUMP request, but with an already existing HTTP client.
32///
33/// ## Errors
34///
35/// - If we cannot encode the parameters as a form url encoded.
36/// - If we cannot make the HTTP request.
37/// - If the server does not respond with a 200.
38/// - If we cannot read the body from HTTP.
39/// - If we cannot parse the HTML response.
40pub 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
98/// Perform a raw request on the MION board's `eeprom_dump.cgi` page.
99///
100/// *note: you probably want to call one of the actual methods, as this is
101/// basically just a thin wrapper around an HTTP Post Request. Not doing much
102/// else more. A lot of it requires that you set things up correctly.*
103///
104/// ## Errors
105///
106/// - If we cannot make an HTTP request to the MION Request.
107/// - If we fail to encode your parameters into a request body.
108pub 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}