Compare commits

..

2 Commits

Author SHA1 Message Date
Astro 4c00548646 main: revert resampling, report per-channel 2019-09-17 01:42:50 +02:00
Astro a7ee2107ea command_parser: rm outdated TODO note 2019-09-17 01:38:12 +02:00
3 changed files with 65 additions and 92 deletions

View File

@ -10,7 +10,6 @@ use nom::{
error::ErrorKind, error::ErrorKind,
}; };
use lexical_core as lexical; use lexical_core as lexical;
use super::session::ReportMode;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -63,7 +62,8 @@ impl fmt::Display for Error {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ShowCommand { pub enum ShowCommand {
ReportMode, Input,
Reporting,
Pid, Pid,
} }
@ -83,7 +83,7 @@ pub enum PidParameter {
pub enum Command { pub enum Command {
Quit, Quit,
Show(ShowCommand), Show(ShowCommand),
Report(ReportMode), Reporting(bool),
Pwm { Pwm {
width: u32, width: u32,
total: u32, total: u32,
@ -112,10 +112,9 @@ fn float(input: &[u8]) -> IResult<&[u8], Result<f32, lexical::Error>> {
Ok((input, result)) Ok((input, result))
} }
fn report_mode(input: &[u8]) -> IResult<&[u8], ReportMode> { fn off_on(input: &[u8]) -> IResult<&[u8], bool> {
alt((value(ReportMode::Off, tag("off")), alt((value(false, tag("off")),
value(ReportMode::Once, tag("once")), value(true, tag("on"))
value(ReportMode::Continuous, tag("continuous"))
))(input) ))(input)
} }
@ -133,13 +132,16 @@ fn report(input: &[u8]) -> IResult<&[u8], Command> {
alt(( alt((
preceded( preceded(
whitespace, whitespace,
map(report_mode, // `report mode <on | off>` - Switch repoting mode
|mode| Command::Report(mode)) map(off_on,
|reporting| Command::Reporting(reporting))
), ),
|input| Ok((input, Command::Show(ShowCommand::ReportMode))) // `report mode` - Show current reporting state
|input| Ok((input, Command::Show(ShowCommand::Reporting)))
)) ))
)), )),
|input| Ok((input, Command::Report(ReportMode::Once))) // `report` - Report once
|input| Ok((input, Command::Show(ShowCommand::Input)))
)) ))
)(input) )(input)
} }
@ -173,7 +175,6 @@ fn pid_parameter(input: &[u8]) -> IResult<&[u8], Result<Command, Error>> {
value(PidParameter::IntegralMax, tag("integral_max")) value(PidParameter::IntegralMax, tag("integral_max"))
))(input)?; ))(input)?;
let (input, _) = whitespace(input)?; let (input, _) = whitespace(input)?;
// TODO: parse float
let (input, value) = float(input)?; let (input, value) = float(input)?;
let result = value let result = value
.map(|value| Command::Pid { parameter, value }) .map(|value| Command::Pid { parameter, value })

View File

@ -76,8 +76,6 @@ macro_rules! create_socket {
) )
} }
/// In nanoseconds
const REPORT_INTERVAL: u64 = 100_000;
const DEFAULT_PID_PARAMETERS: pid::Parameters = pid::Parameters { const DEFAULT_PID_PARAMETERS: pid::Parameters = pid::Parameters {
kp: 1.0, kp: 1.0,
ki: 1.0, ki: 1.0,
@ -88,6 +86,8 @@ const DEFAULT_PID_PARAMETERS: pid::Parameters = pid::Parameters {
integral_max: 0xffff as f32, integral_max: 0xffff as f32,
}; };
pub const CHANNELS: usize = 2;
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
let mut stdout = hio::hstdout().unwrap(); let mut stdout = hio::hstdout().unwrap();
@ -204,11 +204,7 @@ fn main() -> ! {
(Session::new(), tcp_handle7), (Session::new(), tcp_handle7),
]; ];
let mut last_report = get_time(); let mut report = [None; CHANNELS];
let mut next_report = get_time();
// cumulative (sum, count)
let mut sample = [(0u64, 0usize); 2];
let mut report = [None; 2];
loop { loop {
// ADC input // ADC input
adc.data_ready() adc.data_ready()
@ -216,30 +212,14 @@ fn main() -> ! {
writeln!(stdout, "ADC error: {:?}", e).unwrap(); writeln!(stdout, "ADC error: {:?}", e).unwrap();
None None
}).map(|channel| { }).map(|channel| {
let data = adc.read_data().unwrap();
sample[usize::from(channel)].0 += u64::from(data);
sample[usize::from(channel)].1 += 1;
});
let now = get_time(); let now = get_time();
if now >= next_report { let data = adc.read_data().unwrap();
if now < next_report + REPORT_INTERVAL { report[usize::from(channel)] = Some((now, data));
// Try to keep interval constant
next_report += REPORT_INTERVAL;
} else {
// Bad jitter, catch up
next_report = now + REPORT_INTERVAL;
}
for (channel, sample) in sample.iter().enumerate() {
if sample.1 > 0 {
// TODO: calculate med instead of avg?
report[channel] = Some(sample.0 / (sample.1 as u64));
}
}
for (session, _) in sessions_handles.iter_mut() { for (session, _) in sessions_handles.iter_mut() {
session.set_report_pending(); session.set_report_pending(channel.into());
}
last_report = get_time();
} }
});
for (session, tcp_handle) in sessions_handles.iter_mut() { for (session, tcp_handle) in sessions_handles.iter_mut() {
let socket = &mut *sockets.get::<TcpSocket>(*tcp_handle); let socket = &mut *sockets.get::<TcpSocket>(*tcp_handle);
@ -260,11 +240,18 @@ fn main() -> ! {
Ok(SessionOutput::Command(command)) => match command { Ok(SessionOutput::Command(command)) => match command {
Command::Quit => Command::Quit =>
socket.close(), socket.close(),
Command::Report(mode) => { Command::Reporting(reporting) => {
let _ = writeln!(socket, "Report mode: {}", mode); let _ = writeln!(socket, "Report mode set to {}", if reporting { "on" } else { "off" });
}
Command::Show(ShowCommand::Reporting) => {
let _ = writeln!(socket, "Report mode: {}", if session.reporting() { "on" } else { "off" });
}
Command::Show(ShowCommand::Input) => {
for (channel, report) in report.iter().enumerate() {
report.map(|(time, data)| {
let _ = writeln!(socket, "t={}, sens{}={}", time, channel, data);
});
} }
Command::Show(ShowCommand::ReportMode) => {
let _ = writeln!(socket, "Report mode: {}", session.report_mode());
} }
Command::Show(ShowCommand::Pid) => { Command::Show(ShowCommand::Pid) => {
let _ = writeln!(socket, "PID settings"); let _ = writeln!(socket, "PID settings");
@ -316,15 +303,13 @@ fn main() -> ! {
Err(_) => {} Err(_) => {}
} }
} }
if socket.may_send() && session.is_report_pending() { if socket.may_send() {
let _ = write!(socket, "t={}", last_report); if let Some(channel) = session.is_report_pending() {
for (channel, report_data) in report.iter().enumerate() { report[channel].map(|(time, data)| {
report_data.map(|report_data| { let _ = writeln!(socket, "t={} sens{}={:06X}", time, channel, data);
let _ = write!(socket, " sens{}={:06X}", channel, report_data);
}); });
session.mark_report_sent(channel);
} }
let _ = writeln!(socket, "");
session.mark_report_sent();
} }
} }
match iface.poll(&mut sockets, Instant::from_millis((get_time() / 1000) as i64)) { match iface.poll(&mut sockets, Instant::from_millis((get_time() / 1000) as i64)) {

View File

@ -1,6 +1,6 @@
use core::ops::Deref; use core::ops::Deref;
use core::fmt;
use super::command_parser::{Command, Error as ParserError}; use super::command_parser::{Command, Error as ParserError};
use super::CHANNELS;
const MAX_LINE_LEN: usize = 64; const MAX_LINE_LEN: usize = 64;
@ -54,23 +54,6 @@ impl Deref for LineResult {
} }
} }
#[derive(Debug, Clone, Copy)]
pub enum ReportMode {
Off,
Once,
Continuous,
}
impl fmt::Display for ReportMode {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self {
ReportMode::Off => "off",
ReportMode::Once => "once",
ReportMode::Continuous => "continuous",
}.fmt(fmt)
}
}
pub enum SessionOutput { pub enum SessionOutput {
Nothing, Nothing,
Command(Command), Command(Command),
@ -86,16 +69,16 @@ impl From<Result<Command, ParserError>> for SessionOutput {
pub struct Session { pub struct Session {
reader: LineReader, reader: LineReader,
report_mode: ReportMode, reporting: bool,
report_pending: bool, report_pending: [bool; CHANNELS],
} }
impl Session { impl Session {
pub fn new() -> Self { pub fn new() -> Self {
Session { Session {
reader: LineReader::new(), reader: LineReader::new(),
report_mode: ReportMode::Off, reporting: false,
report_pending: false, report_pending: [false; CHANNELS],
} }
} }
@ -103,30 +86,34 @@ impl Session {
self.reader.pos > 0 self.reader.pos > 0
} }
pub fn report_mode(&self) -> ReportMode { pub fn reporting(&self) -> bool {
self.report_mode self.reporting
} }
pub fn set_report_pending(&mut self) { pub fn set_report_pending(&mut self, channel: usize) {
self.report_pending = true; if self.reporting {
} self.report_pending[channel] = true;
pub fn is_report_pending(&self) -> bool {
match self.report_mode {
ReportMode::Off => false,
_ => self.report_pending,
} }
} }
pub fn mark_report_sent(&mut self) { pub fn is_report_pending(&self) -> Option<usize> {
self.report_pending = false; if ! self.reporting {
match self.report_mode { None
ReportMode::Once => } else {
self.report_mode = ReportMode::Off, self.report_pending.iter()
_ => {} .enumerate()
.fold(None, |result, (channel, report_pending)| {
result.or_else(|| {
if *report_pending { Some(channel) } else { None }
})
})
} }
} }
pub fn mark_report_sent(&mut self, channel: usize) {
self.report_pending[channel] = false;
}
pub fn feed(&mut self, buf: &[u8]) -> (usize, SessionOutput) { pub fn feed(&mut self, buf: &[u8]) -> (usize, SessionOutput) {
let mut buf_bytes = 0; let mut buf_bytes = 0;
for (i, b) in buf.iter().enumerate() { for (i, b) in buf.iter().enumerate() {
@ -136,8 +123,8 @@ impl Session {
Some(line) => { Some(line) => {
let command = Command::parse(&line); let command = Command::parse(&line);
match command { match command {
Ok(Command::Report(mode)) => { Ok(Command::Reporting(reporting)) => {
self.report_mode = mode; self.reporting = reporting;
} }
_ => {} _ => {}
} }