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 embedded_hal::blocking::spi::Transfer;
use super::checksum::{ChecksumMode, Checksum}; use super::checksum::{ChecksumMode, Checksum};
use super::AdcError; use super::AdcError;
use super::regs::*; use super::{regs, regs::RegisterData, Input, RefSource};
/// AD7172-2 implementation /// AD7172-2 implementation
/// ///
@ -27,32 +27,44 @@ impl<SPI: Transfer<u8>, NSS: OutputPin> Adc<SPI, NSS> {
/// `0x00DX` for AD7271-2 /// `0x00DX` for AD7271-2
pub fn identify(&mut self) -> Result<u16, AdcError<SPI::Error>> { pub fn identify(&mut self) -> Result<u16, AdcError<SPI::Error>> {
self.read_reg(&Id) self.read_reg(&regs::Id)
.map(|id| id.id()) .map(|id| id.id())
} }
pub fn set_checksum_mode(&mut self, mode: ChecksumMode) -> Result<(), AdcError<SPI::Error>> { 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); ifmode.set_crc(mode);
self.checksum_mode = mode; self.checksum_mode = mode;
self.write_reg(&IfMode, &mut ifmode)?; self.write_reg(&regs::IfMode, &mut ifmode)?;
Ok(()) Ok(())
} }
// pub fn setup(&mut self) -> Result<(), SPI::Error> { pub fn setup_channel(
// let mut buf = [0, 0, 0]; &mut self, index: u8, in_pos: Input, in_neg: Input
// adc.write_reg(Register::AdcMode, &mut buf)?; ) -> Result<(), AdcError<SPI::Error>> {
// let mut buf = [0, 1, 0]; self.update_reg(&regs::SetupCon { index }, |data| {
// adc.write_reg(Register::IfMode, &mut buf)?; data.set_bi_unipolar(false);
// let mut buf = [0, 0, 0]; data.set_refbuf_pos(true);
// adc.write_reg(Register::GpioCon, &mut buf)?; data.set_refbuf_neg(true);
data.set_ainbuf_pos(true);
// Ok(()) 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 /// Returns the channel the data is from
pub fn data_ready(&mut self) -> Result<Option<u8>, AdcError<SPI::Error>> { pub fn data_ready(&mut self) -> Result<Option<u8>, AdcError<SPI::Error>> {
self.read_reg(&Status) self.read_reg(&regs::Status)
.map(|status| { .map(|status| {
if status.ready() { if status.ready() {
Some(status.channel()) Some(status.channel())
@ -64,11 +76,11 @@ impl<SPI: Transfer<u8>, NSS: OutputPin> Adc<SPI, NSS> {
/// Get data /// Get data
pub fn read_data(&mut self) -> Result<u32, AdcError<SPI::Error>> { pub fn read_data(&mut self) -> Result<u32, AdcError<SPI::Error>> {
self.read_reg(&Data) self.read_reg(&regs::Data)
.map(|data| data.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 mut reg_data = R::Data::empty();
let address = 0x40 | reg.address(); let address = 0x40 | reg.address();
let mut checksum = Checksum::new(self.checksum_mode); let mut checksum = Checksum::new(self.checksum_mode);
@ -85,7 +97,7 @@ impl<SPI: Transfer<u8>, NSS: OutputPin> Adc<SPI, NSS> {
Ok(reg_data) 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 address = reg.address();
let mut checksum = Checksum::new(match self.checksum_mode { let mut checksum = Checksum::new(match self.checksum_mode {
ChecksumMode::Off => ChecksumMode::Off, ChecksumMode::Off => ChecksumMode::Off,
@ -102,9 +114,9 @@ impl<SPI: Transfer<u8>, NSS: OutputPin> Adc<SPI, NSS> {
Ok(()) 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 where
R: Register, R: regs::Register,
F: FnOnce(&mut R::Data) -> A, F: FnOnce(&mut R::Data) -> A,
{ {
let mut reg_data = self.read_reg(reg)?; 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] #[entry]
fn main() -> ! { fn main() -> ! {
let mut stdout = hio::hstdout().unwrap(); let mut stdout = hio::hstdout().unwrap();
@ -146,6 +149,10 @@ fn main() -> ! {
writeln!(stdout, "Corrupt ADC id: {:04X}", id).unwrap(), 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()); let mut hardware_addr = EthernetAddress(board::get_mac_address());
if hardware_addr.is_multicast() { if hardware_addr.is_multicast() {
@ -195,31 +202,34 @@ fn main() -> ! {
(Session::new(), tcp_handle7), (Session::new(), tcp_handle7),
]; ];
let mut read_times = [0, 0]; let mut last_report = get_time();
let mut data = None; // cumulative (sum, count)
// if a socket has sent the latest data let mut sample = [(0u64, 0usize); 2];
let mut report = None;
loop { loop {
let _ = adc.data_ready() // ADC input
.and_then(|channel| adc.data_ready()
channel.map(|channel| .unwrap_or_else(|e| {
adc.read_data().map(|new_data| { writeln!(stdout, "ADC error: {:?}", e);
let now = get_time(); None
read_times[0] = read_times[1]; }).map(|channel| {
read_times[1] = now; let data = adc.read_data().unwrap();
data = Some((now, Ok((channel, new_data)))); sample[usize::from(channel)].0 += u64::from(data);
for (session, _) in sessions_handles.iter_mut() { sample[usize::from(channel)].1 += 1;
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();
}
}); });
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() { 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);
if !socket.is_open() { if !socket.is_open() {
@ -256,18 +266,14 @@ fn main() -> ! {
} }
} }
if socket.may_send() && session.is_report_pending() { if socket.may_send() && session.is_report_pending() {
match &data { match &report {
Some((time, Ok((channel, input)))) => { Some((time, samples)) => {
let interval = read_times[1] - read_times[0]; let _ = writeln!(socket, "t={} sens0={} sens1={}\r",
let _ = writeln!(socket, "t={}-{} channel={} input={}\r", time, interval, channel, input); time, samples[0], samples[1]
);
} }
Some((time, Err(ad7172::AdcError::ChecksumMismatch(Some(expected), Some(input))))) => { None =>
let _ = writeln!(socket, "t={} checksum_expected={:02X} checksum_input={:02X}\r", time, expected, input); panic!("report_pending while is there is none yet"),
}
Some((time, Err(e))) => {
let _ = writeln!(socket, "t={} adc_error={:?}\r", time, e);
}
None => {}
} }
session.mark_report_sent(); session.mark_report_sent();
} }