main: setup thermostat v1 channels, report avgs at 10hz

This commit is contained in:
Astro 2019-09-14 01:36:12 +02:00
parent c50e1c7766
commit f8dd7d1912
2 changed files with 72 additions and 54 deletions

View File

@ -2,7 +2,7 @@ use embedded_hal::digital::v2::OutputPin;
use embedded_hal::blocking::spi::Transfer;
use super::checksum::{ChecksumMode, Checksum};
use super::AdcError;
use super::regs::*;
use super::{regs, regs::RegisterData, Input, RefSource};
/// AD7172-2 implementation
///
@ -27,32 +27,44 @@ impl<SPI: Transfer<u8>, NSS: OutputPin> Adc<SPI, NSS> {
/// `0x00DX` for AD7271-2
pub fn identify(&mut self) -> Result<u16, AdcError<SPI::Error>> {
self.read_reg(&Id)
self.read_reg(&regs::Id)
.map(|id| id.id())
}
pub fn set_checksum_mode(&mut self, mode: ChecksumMode) -> Result<(), AdcError<SPI::Error>> {
let mut ifmode = self.read_reg(&IfMode)?;
// Cannot use update_reg() here because checksum_mode is
// updated between read_reg() and write_reg().
let mut ifmode = self.read_reg(&regs::IfMode)?;
ifmode.set_crc(mode);
self.checksum_mode = mode;
self.write_reg(&IfMode, &mut ifmode)?;
self.write_reg(&regs::IfMode, &mut ifmode)?;
Ok(())
}
// pub fn setup(&mut self) -> Result<(), SPI::Error> {
// let mut buf = [0, 0, 0];
// adc.write_reg(Register::AdcMode, &mut buf)?;
// let mut buf = [0, 1, 0];
// adc.write_reg(Register::IfMode, &mut buf)?;
// let mut buf = [0, 0, 0];
// adc.write_reg(Register::GpioCon, &mut buf)?;
// Ok(())
// }
pub fn setup_channel(
&mut self, index: u8, in_pos: Input, in_neg: Input
) -> Result<(), AdcError<SPI::Error>> {
self.update_reg(&regs::SetupCon { index }, |data| {
data.set_bi_unipolar(false);
data.set_refbuf_pos(true);
data.set_refbuf_neg(true);
data.set_ainbuf_pos(true);
data.set_ainbuf_neg(true);
// TODO: which RefSource?
data.set_ref_sel(RefSource::Internal);
})?;
self.update_reg(&regs::Channel { index }, |data| {
data.set_setup(index);
data.set_enabled(true);
data.set_a_in_pos(in_pos);
data.set_a_in_neg(in_neg);
})?;
Ok(())
}
/// Returns the channel the data is from
pub fn data_ready(&mut self) -> Result<Option<u8>, AdcError<SPI::Error>> {
self.read_reg(&Status)
self.read_reg(&regs::Status)
.map(|status| {
if status.ready() {
Some(status.channel())
@ -64,11 +76,11 @@ impl<SPI: Transfer<u8>, NSS: OutputPin> Adc<SPI, NSS> {
/// Get data
pub fn read_data(&mut self) -> Result<u32, AdcError<SPI::Error>> {
self.read_reg(&Data)
self.read_reg(&regs::Data)
.map(|data| data.data())
}
pub fn read_reg<R: Register>(&mut self, reg: &R) -> Result<R::Data, AdcError<SPI::Error>> {
fn read_reg<R: regs::Register>(&mut self, reg: &R) -> Result<R::Data, AdcError<SPI::Error>> {
let mut reg_data = R::Data::empty();
let address = 0x40 | reg.address();
let mut checksum = Checksum::new(self.checksum_mode);
@ -85,7 +97,7 @@ impl<SPI: Transfer<u8>, NSS: OutputPin> Adc<SPI, NSS> {
Ok(reg_data)
}
pub fn write_reg<R: Register>(&mut self, reg: &R, reg_data: &mut R::Data) -> Result<(), AdcError<SPI::Error>> {
fn write_reg<R: regs::Register>(&mut self, reg: &R, reg_data: &mut R::Data) -> Result<(), AdcError<SPI::Error>> {
let address = reg.address();
let mut checksum = Checksum::new(match self.checksum_mode {
ChecksumMode::Off => ChecksumMode::Off,
@ -102,9 +114,9 @@ impl<SPI: Transfer<u8>, NSS: OutputPin> Adc<SPI, NSS> {
Ok(())
}
pub fn update_reg<R, F, A>(&mut self, reg: &R, f: F) -> Result<A, AdcError<SPI::Error>>
fn update_reg<R, F, A>(&mut self, reg: &R, f: F) -> Result<A, AdcError<SPI::Error>>
where
R: Register,
R: regs::Register,
F: FnOnce(&mut R::Data) -> A,
{
let mut reg_data = self.read_reg(reg)?;

View File

@ -85,6 +85,9 @@ macro_rules! create_socket {
)
}
/// In nanoseconds
const REPORT_INTERVAL: u64 = 100_000;
#[entry]
fn main() -> ! {
let mut stdout = hio::hstdout().unwrap();
@ -146,6 +149,10 @@ fn main() -> ! {
writeln!(stdout, "Corrupt ADC id: {:04X}", id).unwrap(),
};
}
// SENS0_{P,N}
adc.setup_channel(0, ad7172::Input::Ain0, ad7172::Input::Ain1).unwrap();
// SENS1_{P,N}
adc.setup_channel(1, ad7172::Input::Ain2, ad7172::Input::Ain3).unwrap();
let mut hardware_addr = EthernetAddress(board::get_mac_address());
if hardware_addr.is_multicast() {
@ -195,31 +202,34 @@ fn main() -> ! {
(Session::new(), tcp_handle7),
];
let mut read_times = [0, 0];
let mut data = None;
// if a socket has sent the latest data
let mut last_report = get_time();
// cumulative (sum, count)
let mut sample = [(0u64, 0usize); 2];
let mut report = None;
loop {
let _ = adc.data_ready()
.and_then(|channel|
channel.map(|channel|
adc.read_data().map(|new_data| {
let now = get_time();
read_times[0] = read_times[1];
read_times[1] = now;
data = Some((now, Ok((channel, new_data))));
for (session, _) in sessions_handles.iter_mut() {
session.set_report_pending();
}
})
).unwrap_or(Ok(()))
)
.map_err(|e| {
let now = get_time();
data = Some((now, Err(e)));
for (session, _) in sessions_handles.iter_mut() {
session.set_report_pending();
}
// ADC input
adc.data_ready()
.unwrap_or_else(|e| {
writeln!(stdout, "ADC error: {:?}", e);
None
}).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();
if now >= last_report + REPORT_INTERVAL {
last_report = now;
// TODO: calculate med instead of avg?
report = Some((now, [
sample[0].0 / (sample[0].1 as u64),
sample[1].0 / (sample[1].1 as u64),
]));
for (session, _) in sessions_handles.iter_mut() {
session.set_report_pending();
}
}
for (session, tcp_handle) in sessions_handles.iter_mut() {
let socket = &mut *sockets.get::<TcpSocket>(*tcp_handle);
if !socket.is_open() {
@ -256,18 +266,14 @@ fn main() -> ! {
}
}
if socket.may_send() && session.is_report_pending() {
match &data {
Some((time, Ok((channel, input)))) => {
let interval = read_times[1] - read_times[0];
let _ = writeln!(socket, "t={}-{} channel={} input={}\r", time, interval, channel, input);
match &report {
Some((time, samples)) => {
let _ = writeln!(socket, "t={} sens0={} sens1={}\r",
time, samples[0], samples[1]
);
}
Some((time, Err(ad7172::AdcError::ChecksumMismatch(Some(expected), Some(input))))) => {
let _ = writeln!(socket, "t={} checksum_expected={:02X} checksum_input={:02X}\r", time, expected, input);
}
Some((time, Err(e))) => {
let _ = writeln!(socket, "t={} adc_error={:?}\r", time, e);
}
None => {}
None =>
panic!("report_pending while is there is none yet"),
}
session.mark_report_sent();
}