ionpak-thermostat/firmware/src/main.rs

342 lines
11 KiB
Rust

#![feature(used, const_fn, core_float, asm)]
#![no_std]
extern crate cortex_m;
extern crate cortex_m_rt;
extern crate tm4c129x;
extern crate smoltcp;
use core::cell::{Cell, RefCell};
use core::fmt;
use cortex_m::exception::Handlers as ExceptionHandlers;
use cortex_m::interrupt::Mutex;
use tm4c129x::interrupt::Interrupt;
use tm4c129x::interrupt::Handlers as InterruptHandlers;
use smoltcp::Error;
use smoltcp::wire::{EthernetAddress, IpAddress};
use smoltcp::iface::{ArpCache, SliceArpCache, EthernetInterface};
use smoltcp::socket::{AsSocket, SocketSet};
use smoltcp::socket::{TcpSocket, TcpSocketBuffer};
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ({
use core::fmt::Write;
write!($crate::UART0, $($arg)*).unwrap()
})
}
#[macro_export]
macro_rules! println {
($fmt:expr) => (print!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => (print!(concat!($fmt, "\n"), $($arg)*));
}
#[macro_use]
mod board;
mod ethmac;
mod pid;
mod loop_anode;
mod loop_cathode;
mod electrometer;
mod http;
mod pages;
static TIME: Mutex<Cell<u64>> = Mutex::new(Cell::new(0));
fn get_time() -> u64 {
cortex_m::interrupt::free(|cs| {
TIME.borrow(cs).get()
})
}
static LOOP_ANODE: Mutex<RefCell<loop_anode::Controller>> = Mutex::new(RefCell::new(
loop_anode::Controller::new()));
static LOOP_CATHODE: Mutex<RefCell<loop_cathode::Controller>> = Mutex::new(RefCell::new(
loop_cathode::Controller::new()));
static ELECTROMETER: Mutex<RefCell<electrometer::Electrometer>> = Mutex::new(RefCell::new(
electrometer::Electrometer::new()));
pub struct UART0;
impl fmt::Write for UART0 {
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
for c in s.bytes() {
unsafe {
let uart_0 = tm4c129x::UART0.get();
while (*uart_0).fr.read().txff().bit() {}
(*uart_0).dr.write(|w| w.data().bits(c))
}
}
Ok(())
}
}
const TCP_RX_BUFFER_SIZE: usize = 256;
const TCP_TX_BUFFER_SIZE: usize = 8192;
macro_rules! create_socket_storage {
($rx_storage:ident, $tx_storage:ident) => (
let mut $rx_storage = [0; TCP_RX_BUFFER_SIZE];
let mut $tx_storage = [0; TCP_TX_BUFFER_SIZE];
)
}
macro_rules! create_socket {
($set:ident, $rx_storage:ident, $tx_storage:ident, $target:ident) => (
let tcp_rx_buffer = TcpSocketBuffer::new(&mut $rx_storage[..]);
let tcp_tx_buffer = TcpSocketBuffer::new(&mut $tx_storage[..]);
let tcp_socket = TcpSocket::new(tcp_rx_buffer, tcp_tx_buffer);
let $target = $set.add(tcp_socket);
)
}
fn main() {
// Enable the FPU
unsafe {
asm!("
PUSH {R0, R1}
LDR.W R0, =0xE000ED88
LDR R1, [R0]
ORR R1, R1, #(0xF << 20)
STR R1, [R0]
DSB
ISB
POP {R0, R1}
");
}
// Beware of the compiler inserting FPU instructions
// in the prologue of functions before the FPU is enabled!
main_with_fpu();
}
#[inline(never)]
fn main_with_fpu() {
board::init();
cortex_m::interrupt::free(|cs| {
let nvic = tm4c129x::NVIC.borrow(cs);
nvic.enable(Interrupt::ADC0SS0);
let mut loop_anode = LOOP_ANODE.borrow(cs).borrow_mut();
let mut loop_cathode = LOOP_CATHODE.borrow(cs).borrow_mut();
// ZJ-10
let anode = 165.0;
let cathode_bias = 50.0;
let emission = 0.5e-3;
// ZJ-27
/*let anode = 225.0;
let cathode_bias = 25.0;
let emission = 1.0e-3;*/
// ZJ-12
/*let anode = 200.0;
let cathode_bias = 50.0;
let emission = 4.0e-3;*/
// G8130
/*let anode = 180.0;
let cathode_bias = 30.0;
let emission = 4.0e-3;*/
loop_anode.set_target(anode);
loop_cathode.set_emission_target(emission);
loop_cathode.set_bias_target(cathode_bias);
});
println!(r#"
_ _
(_) | |
_ ___ _ __ _ __ __ _| |
| |/ _ \| '_ \| '_ \ / _` | |/ /
| | (_) | | | | |_) | (_| | <
|_|\___/|_| |_| .__/ \__,_|_|\_\
| |
|_|
"#);
let hardware_addr = EthernetAddress(board::get_mac_address());
let mut protocol_addrs = [IpAddress::v4(192, 168, 69, 1)];
println!("MAC {} IP {}", hardware_addr, protocol_addrs[0]);
let mut arp_cache_entries: [_; 8] = Default::default();
let mut arp_cache = SliceArpCache::new(&mut arp_cache_entries[..]);
ethmac::init(hardware_addr.0);
let mut device = ethmac::EthernetDevice;
let mut iface = EthernetInterface::new(
&mut device, &mut arp_cache as &mut ArpCache,
hardware_addr, &mut protocol_addrs[..]);
create_socket_storage!(tcp_rx_storage0, tcp_tx_storage0);
create_socket_storage!(tcp_rx_storage1, tcp_tx_storage1);
create_socket_storage!(tcp_rx_storage2, tcp_tx_storage2);
create_socket_storage!(tcp_rx_storage3, tcp_tx_storage3);
create_socket_storage!(tcp_rx_storage4, tcp_tx_storage4);
create_socket_storage!(tcp_rx_storage5, tcp_tx_storage5);
create_socket_storage!(tcp_rx_storage6, tcp_tx_storage6);
create_socket_storage!(tcp_rx_storage7, tcp_tx_storage7);
let mut socket_set_entries: [_; 8] = Default::default();
let mut sockets = SocketSet::new(&mut socket_set_entries[..]);
create_socket!(sockets, tcp_rx_storage0, tcp_tx_storage0, tcp_handle0);
create_socket!(sockets, tcp_rx_storage1, tcp_tx_storage1, tcp_handle1);
create_socket!(sockets, tcp_rx_storage2, tcp_tx_storage2, tcp_handle2);
create_socket!(sockets, tcp_rx_storage3, tcp_tx_storage3, tcp_handle3);
create_socket!(sockets, tcp_rx_storage4, tcp_tx_storage4, tcp_handle4);
create_socket!(sockets, tcp_rx_storage5, tcp_tx_storage5, tcp_handle5);
create_socket!(sockets, tcp_rx_storage6, tcp_tx_storage6, tcp_handle6);
create_socket!(sockets, tcp_rx_storage7, tcp_tx_storage7, tcp_handle7);
let mut sessions = [
(http::Request::new(), tcp_handle0),
(http::Request::new(), tcp_handle1),
(http::Request::new(), tcp_handle2),
(http::Request::new(), tcp_handle3),
(http::Request::new(), tcp_handle4),
(http::Request::new(), tcp_handle5),
(http::Request::new(), tcp_handle6),
(http::Request::new(), tcp_handle7),
];
let mut next_blink = 0;
let mut next_info = 0;
let mut led_state = true;
let mut latch_reset_time = None;
loop {
let time = get_time();
for &mut(ref mut request, ref tcp_handle) in sessions.iter_mut() {
let socket: &mut TcpSocket = sockets.get_mut(*tcp_handle).as_socket();
if !socket.is_open() {
socket.listen(80).unwrap()
}
if socket.may_recv() {
let request_status = {
let data = socket.recv(TCP_RX_BUFFER_SIZE).unwrap();
request.input(data)
};
match request_status {
Ok(true) => {
if socket.can_send() {
pages::serve(socket, &request);
}
request.reset();
socket.close();
}
Ok(false) => (),
Err(err) => {
println!("failed HTTP request: {}", err);
request.reset();
socket.close();
}
}
} else if socket.may_send() {
request.reset();
socket.close();
}
}
let timestamp_ms = 0; // TODO
match iface.poll(&mut sockets, timestamp_ms) {
Ok(()) | Err(Error::Exhausted) => (),
Err(e) => println!("poll error: {}", e)
}
if time > next_blink {
led_state = !led_state;
next_blink = time + 1000;
board::set_led(1, led_state);
}
if time >= next_info {
let (anode, cathode, electrometer) = cortex_m::interrupt::free(|cs| {
(LOOP_ANODE.borrow(cs).borrow().get_status(),
LOOP_CATHODE.borrow(cs).borrow().get_status(),
ELECTROMETER.borrow(cs).borrow().get_status())
});
println!("");
anode.debug_print();
cathode.debug_print();
electrometer.debug_print();
if cathode.fbi.is_some() && electrometer.ic.is_some() {
let fbi = cathode.fbi.unwrap();
let ic = electrometer.ic.unwrap();
let pressure = ic/fbi/18.75154;
println!("{:.1e} mbar", pressure);
}
next_info = next_info + 3000;
}
board::process_errors();
if board::error_latched() {
match latch_reset_time {
None => {
println!("Protection latched");
latch_reset_time = Some(time + 10000);
}
Some(t) => if time > t {
latch_reset_time = None;
cortex_m::interrupt::free(|cs| {
// reset PID loops as they have accumulated large errors
// while the protection was active, which would cause
// unnecessary overshoots.
LOOP_ANODE.borrow(cs).borrow_mut().reset();
LOOP_CATHODE.borrow(cs).borrow_mut().reset();
board::reset_error();
});
println!("Protection reset");
}
}
}
}
}
use tm4c129x::interrupt::ADC0SS0;
extern fn adc0_ss0(_ctxt: ADC0SS0) {
cortex_m::interrupt::free(|cs| {
let adc0 = tm4c129x::ADC0.borrow(cs);
if adc0.ostat.read().ov0().bit() {
panic!("ADC FIFO overflowed")
}
adc0.isc.write(|w| w.in0().bit(true));
let ic_sample = adc0.ssfifo0.read().data().bits();
let fbi_sample = adc0.ssfifo0.read().data().bits();
let fv_sample = adc0.ssfifo0.read().data().bits();
let fd_sample = adc0.ssfifo0.read().data().bits();
let av_sample = adc0.ssfifo0.read().data().bits();
let fbv_sample = adc0.ssfifo0.read().data().bits();
let mut loop_anode = LOOP_ANODE.borrow(cs).borrow_mut();
let mut loop_cathode = LOOP_CATHODE.borrow(cs).borrow_mut();
let mut electrometer = ELECTROMETER.borrow(cs).borrow_mut();
loop_anode.adc_input(av_sample);
loop_cathode.adc_input(fbi_sample, fd_sample, fv_sample, fbv_sample);
electrometer.adc_input(ic_sample);
let time = TIME.borrow(cs);
time.set(time.get() + 1);
});
}
#[used]
#[link_section = ".rodata.exceptions"]
pub static EXCEPTIONS: ExceptionHandlers = ExceptionHandlers {
..cortex_m::exception::DEFAULT_HANDLERS
};
#[used]
#[link_section = ".rodata.interrupts"]
pub static INTERRUPTS: InterruptHandlers = InterruptHandlers {
ADC0SS0: adc0_ss0,
..tm4c129x::interrupt::DEFAULT_HANDLERS
};