2017-08-07 10:42:43 +08:00
|
|
|
use core::fmt;
|
2017-08-05 15:51:54 +08:00
|
|
|
use core::fmt::Write;
|
2017-08-07 10:42:43 +08:00
|
|
|
use core::cell::RefCell;
|
2017-08-08 11:05:09 +08:00
|
|
|
use core::str;
|
2017-08-07 10:42:43 +08:00
|
|
|
use cortex_m;
|
|
|
|
use cortex_m::interrupt::Mutex;
|
2017-08-05 15:51:54 +08:00
|
|
|
use smoltcp::socket::TcpSocket;
|
2017-08-07 10:42:43 +08:00
|
|
|
|
2017-08-05 15:51:54 +08:00
|
|
|
use http;
|
2017-08-08 11:05:09 +08:00
|
|
|
use config;
|
2017-08-07 10:42:43 +08:00
|
|
|
use loop_anode;
|
|
|
|
use loop_cathode;
|
|
|
|
use electrometer;
|
|
|
|
|
2017-08-08 13:13:41 +08:00
|
|
|
macro_rules! opn_fmt {
|
|
|
|
($struct_name:ident, $error:expr) => {
|
|
|
|
struct $struct_name(Option<f32>);
|
2017-08-07 10:42:43 +08:00
|
|
|
|
2017-08-08 13:13:41 +08:00
|
|
|
impl fmt::Display for $struct_name {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self.0 {
|
|
|
|
None => f.write_str($error),
|
|
|
|
Some(x) => x.fmt(f)
|
|
|
|
}
|
|
|
|
}
|
2017-08-07 10:42:43 +08:00
|
|
|
}
|
2017-08-05 15:51:54 +08:00
|
|
|
|
2017-08-08 13:13:41 +08:00
|
|
|
impl fmt::LowerExp for $struct_name {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
match self.0 {
|
|
|
|
None => f.write_str($error),
|
|
|
|
Some(x) => x.fmt(f)
|
|
|
|
}
|
|
|
|
}
|
2017-08-07 10:42:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-08 13:13:41 +08:00
|
|
|
opn_fmt!(OpnFmt, "ERROR");
|
|
|
|
opn_fmt!(OpnFmtJSON, "null");
|
|
|
|
|
2017-08-07 10:42:43 +08:00
|
|
|
pub fn serve(output: &mut TcpSocket, request: &http::Request,
|
2017-08-08 11:05:09 +08:00
|
|
|
config: &mut config::Config,
|
2017-08-07 10:42:43 +08:00
|
|
|
loop_anode_m: &Mutex<RefCell<loop_anode::Controller>>,
|
|
|
|
loop_cathode_m: &Mutex<RefCell<loop_cathode::Controller>>,
|
|
|
|
electrometer_m: &Mutex<RefCell<electrometer::Electrometer>>) {
|
2017-08-05 15:51:54 +08:00
|
|
|
match request.get_path().unwrap() {
|
|
|
|
b"/" => {
|
2017-08-07 10:42:43 +08:00
|
|
|
let (anode, cathode, electrometer) = cortex_m::interrupt::free(|cs| {
|
|
|
|
(loop_anode_m.borrow(cs).borrow().get_status(),
|
|
|
|
loop_cathode_m.borrow(cs).borrow().get_status(),
|
|
|
|
electrometer_m.borrow(cs).borrow().get_status())
|
|
|
|
});
|
|
|
|
|
|
|
|
let pressure = electrometer.ic.and_then(|ic| {
|
|
|
|
if ic > 1.0e-12 {
|
|
|
|
cathode.fbi.and_then(|fbi| Some(ic/fbi/18.75154))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
});
|
2017-08-05 15:51:54 +08:00
|
|
|
http::write_reply_header(output, 200, "text/html; charset=utf-8", false).unwrap();
|
2017-08-07 10:42:43 +08:00
|
|
|
write!(output, include_str!("index.html"),
|
|
|
|
pressure=OpnFmt(pressure),
|
|
|
|
anode_ready=anode.ready,
|
|
|
|
anode_av=OpnFmt(anode.av),
|
|
|
|
cathode_ready=cathode.ready,
|
|
|
|
cathode_fbi=OpnFmt(cathode.fbi.and_then(|x| Some(x*1.0e6))),
|
|
|
|
cathode_fv=OpnFmt(cathode.fv),
|
|
|
|
cathode_fv_target=OpnFmt(cathode.fv_target),
|
|
|
|
cathode_fbv=OpnFmt(cathode.fbv),
|
|
|
|
ion_current=OpnFmt(electrometer.ic.and_then(|x| Some(x*1.0e9)))).unwrap();
|
2017-08-05 15:51:54 +08:00
|
|
|
},
|
2017-08-08 13:13:41 +08:00
|
|
|
b"/measure.json" => {
|
|
|
|
let (cathode, electrometer) = cortex_m::interrupt::free(|cs| {
|
|
|
|
(loop_cathode_m.borrow(cs).borrow().get_status(),
|
|
|
|
electrometer_m.borrow(cs).borrow().get_status())
|
|
|
|
});
|
|
|
|
|
|
|
|
// TODO: factor this
|
|
|
|
let pressure = electrometer.ic.and_then(|ic| {
|
|
|
|
if ic > 1.0e-12 {
|
|
|
|
cathode.fbi.and_then(|fbi| Some(ic/fbi/18.75154))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
});
|
|
|
|
http::write_reply_header(output, 200, "application/json", false).unwrap();
|
|
|
|
write!(output, "{{\"pressure\": {:.1e}, \"current\": {:.3e}}}",
|
|
|
|
OpnFmtJSON(pressure), OpnFmtJSON(electrometer.ic)).unwrap();
|
|
|
|
}
|
2017-08-08 11:05:09 +08:00
|
|
|
b"/network_settings.html" => {
|
|
|
|
let mut status = "";
|
|
|
|
|
|
|
|
let ip_arg = request.get_arg(b"ip");
|
|
|
|
if ip_arg.is_ok() {
|
|
|
|
let ip_arg = str::from_utf8(ip_arg.unwrap());
|
|
|
|
if ip_arg.is_ok() {
|
|
|
|
let ip = ip_arg.unwrap().parse();
|
|
|
|
if ip.is_ok() {
|
|
|
|
let ip = ip.unwrap();
|
|
|
|
status = "IP address has been updated and will be active after a reboot.";
|
|
|
|
config.ip = ip;
|
|
|
|
config.save();
|
|
|
|
} else {
|
|
|
|
status = "failed to parse IP address";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
status = "IP address contains an invalid UTF-8 character";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
http::write_reply_header(output, 200, "text/html; charset=utf-8", false).unwrap();
|
|
|
|
write!(output, include_str!("network_settings.html"),
|
|
|
|
status=status, ip=config.ip).unwrap();
|
|
|
|
},
|
2017-08-07 17:54:25 +08:00
|
|
|
b"/firmware.html" => {
|
|
|
|
http::write_reply_header(output, 200, "text/html; charset=utf-8", false).unwrap();
|
|
|
|
write!(output, include_str!("firmware.html"),
|
|
|
|
version=include_str!(concat!(env!("OUT_DIR"), "/git-describe"))).unwrap();
|
|
|
|
}
|
2017-08-05 15:51:54 +08:00
|
|
|
b"/style.css" => {
|
|
|
|
let data = include_bytes!("style.css.gz");
|
|
|
|
http::write_reply_header(output, 200, "text/css", true).unwrap();
|
|
|
|
output.send_slice(data).unwrap();
|
|
|
|
},
|
|
|
|
b"/logo.svg" => {
|
|
|
|
let data = include_bytes!("logo.svg.gz");
|
|
|
|
http::write_reply_header(output, 200, "image/svg+xml", true).unwrap();
|
|
|
|
output.send_slice(data).unwrap();
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
http::write_reply_header(output, 404, "text/plain", false).unwrap();
|
|
|
|
write!(output, "Not found").unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|