2019-02-06 17:19:28 +08:00
|
|
|
#![feature(const_fn)]
|
2019-09-12 22:12:03 +08:00
|
|
|
#![feature(alloc_error_handler)]
|
2017-05-04 17:35:26 +08:00
|
|
|
#![no_std]
|
2018-08-29 03:57:17 +08:00
|
|
|
#![no_main]
|
2017-05-04 17:35:26 +08:00
|
|
|
|
2019-09-12 22:12:03 +08:00
|
|
|
extern crate alloc;
|
|
|
|
use cortex_m_rt::{entry, heap_start};
|
2019-08-08 08:23:17 +08:00
|
|
|
use core::fmt::{self, Write};
|
2018-03-26 19:37:14 +08:00
|
|
|
use smoltcp::time::Instant;
|
2019-08-21 17:31:51 +08:00
|
|
|
use smoltcp::wire::{IpCidr, IpAddress, EthernetAddress};
|
2018-01-26 21:03:04 +08:00
|
|
|
use smoltcp::iface::{NeighborCache, EthernetInterfaceBuilder};
|
|
|
|
use smoltcp::socket::{SocketSet, TcpSocket, TcpSocketBuffer};
|
2019-09-02 05:56:27 +08:00
|
|
|
use cortex_m_semihosting::hio;
|
2019-09-12 22:12:03 +08:00
|
|
|
use alloc_cortex_m::CortexMHeap;
|
2017-05-04 17:35:26 +08:00
|
|
|
|
2017-05-11 14:55:00 +08:00
|
|
|
#[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)*));
|
|
|
|
}
|
|
|
|
|
2018-08-29 03:57:17 +08:00
|
|
|
#[no_mangle] // https://github.com/rust-lang/rust/issues/{38281,51647}
|
|
|
|
#[panic_handler]
|
|
|
|
pub fn panic_fmt(info: &core::panic::PanicInfo) -> ! {
|
|
|
|
println!("{}", info);
|
2019-09-14 22:52:35 +08:00
|
|
|
let mut stdout = hio::hstdout().unwrap();
|
|
|
|
let _ = writeln!(stdout, "{}", info);
|
2017-08-06 19:52:11 +08:00
|
|
|
loop {}
|
|
|
|
}
|
|
|
|
|
2019-09-12 22:12:03 +08:00
|
|
|
#[global_allocator]
|
|
|
|
static ALLOCATOR: CortexMHeap = CortexMHeap::empty();
|
|
|
|
const HEAP_SIZE: usize = 8192;
|
|
|
|
|
|
|
|
#[alloc_error_handler]
|
|
|
|
fn alloc_error_handler(layout: alloc::alloc::Layout) -> ! {
|
|
|
|
panic!("Allocation error for: {:?}", layout)
|
|
|
|
}
|
|
|
|
|
2017-05-09 15:57:54 +08:00
|
|
|
mod board;
|
2019-09-08 07:54:51 +08:00
|
|
|
use self::board::{gpio::Gpio, systick::get_time};
|
2017-08-02 00:33:33 +08:00
|
|
|
mod ethmac;
|
2019-09-11 05:37:51 +08:00
|
|
|
mod command_parser;
|
2019-09-11 06:23:15 +08:00
|
|
|
use command_parser::{Command, ShowCommand};
|
2019-09-11 05:37:51 +08:00
|
|
|
mod session;
|
|
|
|
use self::session::{Session, SessionOutput};
|
2019-08-08 08:08:14 +08:00
|
|
|
mod ad7172;
|
2017-05-06 17:17:41 +08:00
|
|
|
|
2017-05-09 13:16:00 +08:00
|
|
|
pub struct UART0;
|
|
|
|
|
|
|
|
impl fmt::Write for UART0 {
|
|
|
|
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
|
2018-08-29 03:57:17 +08:00
|
|
|
let uart_0 = unsafe { &*tm4c129x::UART0::ptr() };
|
2017-05-09 13:16:00 +08:00
|
|
|
for c in s.bytes() {
|
2018-08-29 03:57:17 +08:00
|
|
|
while uart_0.fr.read().txff().bit() {}
|
|
|
|
uart_0.dr.write(|w| w.data().bits(c))
|
2017-05-09 13:16:00 +08:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-05 15:51:54 +08:00
|
|
|
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);
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2019-09-14 07:36:12 +08:00
|
|
|
/// In nanoseconds
|
|
|
|
const REPORT_INTERVAL: u64 = 100_000;
|
|
|
|
|
2019-02-06 17:19:28 +08:00
|
|
|
#[entry]
|
2018-08-29 03:57:17 +08:00
|
|
|
fn main() -> ! {
|
2019-09-02 05:56:27 +08:00
|
|
|
let mut stdout = hio::hstdout().unwrap();
|
2019-09-02 06:01:18 +08:00
|
|
|
writeln!(stdout, "ionpak boot").unwrap();
|
2017-05-09 15:57:54 +08:00
|
|
|
board::init();
|
2019-09-02 06:01:18 +08:00
|
|
|
writeln!(stdout, "board initialized").unwrap();
|
2019-09-12 22:12:03 +08:00
|
|
|
unsafe { ALLOCATOR.init(heap_start() as usize, HEAP_SIZE) };
|
2017-05-04 19:42:22 +08:00
|
|
|
|
2017-05-11 14:55:00 +08:00
|
|
|
println!(r#"
|
|
|
|
_ _
|
|
|
|
(_) | |
|
|
|
|
_ ___ _ __ _ __ __ _| |
|
|
|
|
| |/ _ \| '_ \| '_ \ / _` | |/ /
|
|
|
|
| | (_) | | | | |_) | (_| | <
|
|
|
|
|_|\___/|_| |_| .__/ \__,_|_|\_\
|
|
|
|
| |
|
|
|
|
|_|
|
2017-08-05 15:51:54 +08:00
|
|
|
"#);
|
2019-08-08 07:57:30 +08:00
|
|
|
// CSn
|
2019-08-08 06:54:37 +08:00
|
|
|
let pb4 = board::gpio::PB4.into_output();
|
|
|
|
// SCLK
|
|
|
|
let pb5 = board::gpio::PB5.into_output();
|
|
|
|
// MOSI
|
|
|
|
let pe4 = board::gpio::PE4.into_output();
|
|
|
|
// MISO
|
|
|
|
let pe5 = board::gpio::PE5.into_input();
|
2019-09-02 05:56:45 +08:00
|
|
|
// max 2 MHz = 0.5 us
|
2019-09-08 06:47:41 +08:00
|
|
|
let mut delay_fn = || for _ in 0..10 { cortex_m::asm::nop(); };
|
2019-08-08 06:54:37 +08:00
|
|
|
let spi = board::softspi::SyncSoftSpi::new(
|
2019-08-08 08:08:14 +08:00
|
|
|
board::softspi::SoftSpi::new(pb5, pe4, pe5),
|
|
|
|
&mut delay_fn
|
2019-08-08 06:54:37 +08:00
|
|
|
);
|
2019-08-08 08:23:17 +08:00
|
|
|
let mut adc = ad7172::Adc::new(spi, pb4).unwrap();
|
2019-09-02 05:56:45 +08:00
|
|
|
loop {
|
|
|
|
let r = adc.identify();
|
|
|
|
match r {
|
2019-09-08 05:29:26 +08:00
|
|
|
Err(e) =>
|
|
|
|
writeln!(stdout, "Cannot identify ADC: {:?}", e).unwrap(),
|
|
|
|
Ok(id) if id & 0xFFF0 == 0x00D0 => {
|
2019-09-02 06:01:18 +08:00
|
|
|
writeln!(stdout, "ADC id: {:04X}", id).unwrap();
|
2019-09-02 05:56:45 +08:00
|
|
|
break;
|
|
|
|
}
|
2019-09-08 05:29:26 +08:00
|
|
|
Ok(id) =>
|
|
|
|
writeln!(stdout, "Corrupt ADC id: {:04X}", id).unwrap(),
|
|
|
|
};
|
|
|
|
}
|
2019-09-08 06:47:14 +08:00
|
|
|
writeln!(stdout, "AD7172: setting checksum mode").unwrap();
|
|
|
|
adc.set_checksum_mode(ad7172::ChecksumMode::Crc).unwrap();
|
2019-09-08 05:29:26 +08:00
|
|
|
loop {
|
|
|
|
let r = adc.identify();
|
|
|
|
match r {
|
|
|
|
Err(e) =>
|
|
|
|
writeln!(stdout, "Cannot identify ADC: {:?}", e).unwrap(),
|
|
|
|
Ok(id) if id & 0xFFF0 == 0x00D0 => {
|
|
|
|
writeln!(stdout, "ADC id: {:04X}", id).unwrap();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Ok(id) =>
|
2019-09-02 05:56:45 +08:00
|
|
|
writeln!(stdout, "Corrupt ADC id: {:04X}", id).unwrap(),
|
|
|
|
};
|
|
|
|
}
|
2019-09-14 07:36:12 +08:00
|
|
|
// 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();
|
2019-09-11 05:37:51 +08:00
|
|
|
|
2017-08-07 11:18:19 +08:00
|
|
|
let mut hardware_addr = EthernetAddress(board::get_mac_address());
|
|
|
|
if hardware_addr.is_multicast() {
|
|
|
|
println!("programmed MAC address is invalid, using default");
|
|
|
|
hardware_addr = EthernetAddress([0x10, 0xE2, 0xD5, 0x00, 0x03, 0x00]);
|
|
|
|
}
|
2019-08-30 04:40:14 +08:00
|
|
|
let mut ip_addrs = [IpCidr::new(IpAddress::v4(192, 168, 1, 26), 24)];
|
2018-01-26 21:03:04 +08:00
|
|
|
println!("MAC {} IP {}", hardware_addr, ip_addrs[0]);
|
|
|
|
let mut neighbor_cache_storage = [None; 8];
|
|
|
|
let neighbor_cache = NeighborCache::new(&mut neighbor_cache_storage[..]);
|
2018-03-26 20:35:28 +08:00
|
|
|
let mut device = ethmac::Device::new();
|
|
|
|
unsafe { device.init(hardware_addr) };
|
|
|
|
let mut iface = EthernetInterfaceBuilder::new(&mut device)
|
2018-01-26 21:03:04 +08:00
|
|
|
.ethernet_addr(hardware_addr)
|
|
|
|
.neighbor_cache(neighbor_cache)
|
|
|
|
.ip_addrs(&mut ip_addrs[..])
|
|
|
|
.finalize();
|
2017-08-05 15:51:54 +08:00
|
|
|
|
|
|
|
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);
|
2019-09-11 05:37:51 +08:00
|
|
|
let mut sessions_handles = [
|
|
|
|
(Session::new(), tcp_handle0),
|
|
|
|
(Session::new(), tcp_handle1),
|
|
|
|
(Session::new(), tcp_handle2),
|
|
|
|
(Session::new(), tcp_handle3),
|
|
|
|
(Session::new(), tcp_handle4),
|
|
|
|
(Session::new(), tcp_handle5),
|
|
|
|
(Session::new(), tcp_handle6),
|
|
|
|
(Session::new(), tcp_handle7),
|
2019-08-08 08:23:17 +08:00
|
|
|
];
|
|
|
|
|
2019-09-14 07:36:12 +08:00
|
|
|
let mut last_report = get_time();
|
2019-09-14 08:33:56 +08:00
|
|
|
let mut next_report = get_time();
|
2019-09-14 07:36:12 +08:00
|
|
|
// cumulative (sum, count)
|
|
|
|
let mut sample = [(0u64, 0usize); 2];
|
2019-09-14 08:33:56 +08:00
|
|
|
let mut report = [None; 2];
|
2017-05-06 12:33:38 +08:00
|
|
|
loop {
|
2019-09-14 07:36:12 +08:00
|
|
|
// 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;
|
2019-08-08 08:23:17 +08:00
|
|
|
});
|
2019-09-14 07:36:12 +08:00
|
|
|
let now = get_time();
|
2019-09-14 08:33:56 +08:00
|
|
|
if now >= next_report {
|
|
|
|
if now < next_report + REPORT_INTERVAL {
|
2019-09-14 08:18:33 +08:00
|
|
|
// Try to keep interval constant
|
2019-09-14 08:33:56 +08:00
|
|
|
next_report += REPORT_INTERVAL;
|
2019-09-14 08:18:33 +08:00
|
|
|
} else {
|
|
|
|
// Bad jitter, catch up
|
2019-09-14 08:33:56 +08:00
|
|
|
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));
|
|
|
|
}
|
2019-09-14 08:18:33 +08:00
|
|
|
}
|
2019-09-14 07:36:12 +08:00
|
|
|
for (session, _) in sessions_handles.iter_mut() {
|
|
|
|
session.set_report_pending();
|
|
|
|
}
|
2019-09-14 08:33:56 +08:00
|
|
|
last_report = get_time();
|
2019-09-14 07:36:12 +08:00
|
|
|
}
|
|
|
|
|
2019-09-11 05:37:51 +08:00
|
|
|
for (session, tcp_handle) in sessions_handles.iter_mut() {
|
|
|
|
let socket = &mut *sockets.get::<TcpSocket>(*tcp_handle);
|
2017-08-05 15:51:54 +08:00
|
|
|
if !socket.is_open() {
|
2019-09-11 05:37:51 +08:00
|
|
|
if session.is_dirty() {
|
|
|
|
// Reset a previously uses session/socket
|
|
|
|
*session = Session::new();
|
|
|
|
}
|
2019-08-08 08:23:17 +08:00
|
|
|
socket.listen(23).unwrap()
|
2017-08-05 15:51:54 +08:00
|
|
|
}
|
|
|
|
|
2019-09-11 05:37:51 +08:00
|
|
|
if socket.may_recv() && socket.may_send() {
|
2019-09-14 06:46:48 +08:00
|
|
|
let output = socket.recv(|buf| session.feed(buf));
|
2019-09-11 05:37:51 +08:00
|
|
|
|
2019-09-14 06:46:48 +08:00
|
|
|
match output {
|
2019-09-11 05:37:51 +08:00
|
|
|
Ok(SessionOutput::Nothing) => {}
|
2019-09-14 06:46:48 +08:00
|
|
|
Ok(SessionOutput::Command(command)) => match command {
|
|
|
|
Command::Quit =>
|
|
|
|
socket.close(),
|
|
|
|
Command::Report(mode) => {
|
|
|
|
let _ = writeln!(socket, "Report mode: {:?}", mode);
|
|
|
|
}
|
|
|
|
Command::Show(ShowCommand::ReportMode) => {
|
|
|
|
let _ = writeln!(socket, "Report mode: {:?}", session.report_mode());
|
|
|
|
}
|
2019-09-14 09:09:07 +08:00
|
|
|
Command::Pwm { pwm_match, pwm_reload } => {
|
|
|
|
board::set_timer_pwm(pwm_match, pwm_reload);
|
|
|
|
let _ = writeln!(socket, "PWM duty cycle: {}/{}", pwm_match, pwm_reload);
|
2019-09-14 06:46:48 +08:00
|
|
|
}
|
2019-09-11 05:37:51 +08:00
|
|
|
}
|
|
|
|
Ok(SessionOutput::Error(e)) => {
|
|
|
|
let _ = writeln!(socket, "Command error: {:?}", e);
|
|
|
|
}
|
|
|
|
Err(_) => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if socket.may_send() && session.is_report_pending() {
|
2019-09-14 08:33:56 +08:00
|
|
|
let _ = write!(socket, "t={}", last_report);
|
|
|
|
for (channel, report_data) in report.iter().enumerate() {
|
|
|
|
report_data.map(|report_data| {
|
|
|
|
let _ = write!(socket, " sens{}={:06X}", channel, report_data);
|
|
|
|
});
|
2019-09-08 05:29:26 +08:00
|
|
|
}
|
2019-09-14 08:33:56 +08:00
|
|
|
let _ = writeln!(socket, "");
|
2019-09-11 05:37:51 +08:00
|
|
|
session.mark_report_sent();
|
2017-08-05 15:51:54 +08:00
|
|
|
}
|
2019-08-08 08:23:17 +08:00
|
|
|
}
|
2019-09-08 08:34:59 +08:00
|
|
|
match iface.poll(&mut sockets, Instant::from_millis((get_time() / 1000) as i64)) {
|
2017-09-05 17:26:23 +08:00
|
|
|
Ok(_) => (),
|
2017-08-05 15:51:54 +08:00
|
|
|
Err(e) => println!("poll error: {}", e)
|
|
|
|
}
|
2017-05-06 12:33:38 +08:00
|
|
|
}
|
2017-05-04 17:35:26 +08:00
|
|
|
}
|