forked from M-Labs/ionpak-thermostat
main: setup thermostat v1 channels, report avgs at 10hz
This commit is contained in:
parent
c50e1c7766
commit
f8dd7d1912
@ -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(®s::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(®s::IfMode)?;
|
||||
ifmode.set_crc(mode);
|
||||
self.checksum_mode = mode;
|
||||
self.write_reg(&IfMode, &mut ifmode)?;
|
||||
self.write_reg(®s::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(®s::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(®s::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(®s::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(®s::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)?;
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user