forked from M-Labs/ionpak-thermostat
main: revert resampling, report per-channel
This commit is contained in:
parent
a7ee2107ea
commit
4c00548646
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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 now = get_time();
|
||||||
let data = adc.read_data().unwrap();
|
let data = adc.read_data().unwrap();
|
||||||
sample[usize::from(channel)].0 += u64::from(data);
|
report[usize::from(channel)] = Some((now, data));
|
||||||
sample[usize::from(channel)].1 += 1;
|
|
||||||
});
|
for (session, _) in sessions_handles.iter_mut() {
|
||||||
let now = get_time();
|
session.set_report_pending(channel.into());
|
||||||
if now >= next_report {
|
|
||||||
if now < next_report + REPORT_INTERVAL {
|
|
||||||
// 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() {
|
|
||||||
session.set_report_pending();
|
|
||||||
}
|
|
||||||
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::ReportMode) => {
|
Command::Show(ShowCommand::Reporting) => {
|
||||||
let _ = writeln!(socket, "Report mode: {}", session.report_mode());
|
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::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)) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user