Initial commit
This commit is contained in:
commit
f8b331b659
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
target
|
90
common/Cargo.lock
generated
Normal file
90
common/Cargo.lock
generated
Normal file
@ -0,0 +1,90 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"embedded-hal",
|
||||
"shared-bus",
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
|
||||
dependencies = [
|
||||
"nb 0.1.3",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
|
||||
dependencies = [
|
||||
"nb 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc59d1bcc64fc5d021d67521f818db868368028108d37f0e98d74e33f68297b5"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "shared-bus"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f8438a40b91c8b9531c664e9680c55b92bd78cd6809a8b45b4512b1e5765f2"
|
||||
dependencies = [
|
||||
"embedded-hal",
|
||||
"nb 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "git+https://github.com/mvdnes/spin-rs#5be251f5b52b653c2c40fcdc1089d38114125efa"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
11
common/Cargo.toml
Normal file
11
common/Cargo.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[package]
|
||||
name = "common"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
embedded-hal = "0.2.7"
|
||||
shared-bus = { version = "0.2.5" }
|
||||
spin = {git = "https://github.com/mvdnes/spin-rs", features = ['portable_atomic']}
|
48
common/src/lcd.rs
Normal file
48
common/src/lcd.rs
Normal file
@ -0,0 +1,48 @@
|
||||
use core::fmt::{Error, Write};
|
||||
use embedded_hal::blocking::{i2c::Write as I2CWrite, delay::DelayUs};
|
||||
use spin::Mutex;
|
||||
|
||||
|
||||
pub static DEFAULT_ADDR: u8 = 0x72;
|
||||
|
||||
|
||||
pub struct SerLCD<'a, T, D> {
|
||||
i2c: T,
|
||||
addr: u8,
|
||||
delay: &'a Mutex<D>
|
||||
}
|
||||
|
||||
impl<'a, T, D, E> SerLCD<'a, T, D>
|
||||
where
|
||||
T: I2CWrite<Error = E>,
|
||||
D: DelayUs<u32>,
|
||||
{
|
||||
pub fn new(i2c: T, delay: &'a Mutex<D>) -> Self {
|
||||
Self { i2c, addr: DEFAULT_ADDR, delay }
|
||||
}
|
||||
|
||||
pub fn new_with_addr(i2c: T, addr: u8, delay: &'a Mutex<D>) -> Self {
|
||||
Self { i2c, addr, delay }
|
||||
}
|
||||
|
||||
pub fn clear(&mut self) -> Result<(), E> {
|
||||
self.delay.lock().delay_us(500u32);
|
||||
self.i2c.write(self.addr, b"|-")
|
||||
}
|
||||
|
||||
pub fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), E> {
|
||||
self.delay.lock().delay_us(500u32);
|
||||
self.i2c.write(self.addr, bytes)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, D, E> Write for SerLCD<'_, T, D>
|
||||
where
|
||||
T: I2CWrite<Error = E>,
|
||||
D: DelayUs<u32>,
|
||||
{
|
||||
fn write_str(&mut self, s: &str) -> core::fmt::Result {
|
||||
self.delay.lock().delay_us(500u32);
|
||||
self.i2c.write(self.addr, s.as_bytes()).map_err(|_| Error)
|
||||
}
|
||||
}
|
182
common/src/lib.rs
Normal file
182
common/src/lib.rs
Normal file
@ -0,0 +1,182 @@
|
||||
#![no_std]
|
||||
|
||||
mod lcd;
|
||||
mod seesaw;
|
||||
pub mod timer;
|
||||
|
||||
use shared_bus::{BusManager, BusMutex};
|
||||
use timer::Timer;
|
||||
|
||||
use core::fmt::{Debug, Write};
|
||||
use embedded_hal::{
|
||||
blocking::{i2c::{Read as I2CRead, Write as I2CWrite}, delay::{DelayMs, DelayUs}},
|
||||
digital::v2::{InputPin, OutputPin},
|
||||
};
|
||||
use lcd::SerLCD;
|
||||
use seesaw::Seesaw;
|
||||
use spin::Mutex;
|
||||
|
||||
|
||||
const ENCODER_ADDREESS: u8 = 0x36;
|
||||
const ENCODER_SW_PIN: u8 = 24;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
enum Mode {
|
||||
Timer,
|
||||
Focus,
|
||||
TimePaperDev,
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
fn next(self) -> Self {
|
||||
match self {
|
||||
Self::Timer => Self::Focus,
|
||||
Self::Focus => Self::TimePaperDev,
|
||||
Self::TimePaperDev => Self::Timer,
|
||||
}
|
||||
}
|
||||
fn prev(self) -> Self {
|
||||
match self {
|
||||
Self::Timer => Self::TimePaperDev,
|
||||
Self::Focus => Self::Timer,
|
||||
Self::TimePaperDev => Self::Focus,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main<
|
||||
U: Write,
|
||||
IM: BusMutex<Bus = IB>,
|
||||
IB: I2CRead<Error = IE> + I2CWrite<Error = IE>,
|
||||
IE: Debug,
|
||||
T: Timer,
|
||||
D: DelayMs<u32> + DelayUs<u32>,
|
||||
P: InputPin<Error = PE>,
|
||||
PE: Debug,
|
||||
R: OutputPin<Error = RE>,
|
||||
RE: Debug,
|
||||
>(mut uart: U, i2c: BusManager<IM>, timer: T, delay: D, pedal: P, mut relay: R) -> ! {
|
||||
let delay = Mutex::new(delay);
|
||||
write!(&mut uart, "Timer reset").unwrap();
|
||||
let mut lcd = SerLCD::new(i2c.acquire_i2c(), &delay);
|
||||
lcd.write_bytes(&[b'|', b'+', 32, 0, 0]).unwrap();
|
||||
let mut encoder = Seesaw::new(i2c.acquire_i2c(), ENCODER_ADDREESS, &delay);
|
||||
while lcd.clear().is_err() {} // Wait for the LCD to be ready
|
||||
encoder
|
||||
.pin_mode(ENCODER_SW_PIN, seesaw::PinMode::Input)
|
||||
.unwrap();
|
||||
let mut time = 0;
|
||||
let mut mode = Mode::Timer;
|
||||
'main: loop {
|
||||
lcd.clear().unwrap();
|
||||
// The button is active-low, so invert the read value to make it active-high.
|
||||
let encoder_button = !encoder.digital_read(ENCODER_SW_PIN).unwrap();
|
||||
let delta = -encoder.get_encoder_delta().unwrap();
|
||||
if encoder_button {
|
||||
relay.set_low().unwrap();
|
||||
write!(&mut lcd, "Mode: {:?}", mode).unwrap();
|
||||
#[allow(clippy::comparison_chain)]
|
||||
if delta > 0 {
|
||||
mode = mode.next();
|
||||
} else if delta < 0 {
|
||||
mode = mode.prev();
|
||||
}
|
||||
} else {
|
||||
match mode {
|
||||
Mode::Focus => {
|
||||
relay.set_high().unwrap();
|
||||
write!(&mut lcd, "Focus").unwrap();
|
||||
}
|
||||
Mode::Timer => {
|
||||
if pedal.is_high().unwrap() {
|
||||
relay.set_high().unwrap();
|
||||
countdown(time as u64, &mut lcd, "Exposing", &mut encoder, &pedal, &delay, &timer);
|
||||
relay.set_low().unwrap();
|
||||
mode = Mode::TimePaperDev;
|
||||
} else {
|
||||
time += delta;
|
||||
if time < 0 {
|
||||
time = 0;
|
||||
}
|
||||
write!(&mut lcd, "Time: {:0>2}:{:0>2}", time / 60, time % 60).unwrap();
|
||||
}
|
||||
}
|
||||
Mode::TimePaperDev => {
|
||||
delay.lock().delay_ms(2u32);
|
||||
write!(&mut lcd, "|-Ready dev").unwrap();
|
||||
while pedal.is_low().unwrap() {
|
||||
if !encoder.digital_read(ENCODER_SW_PIN).unwrap() {
|
||||
continue 'main;
|
||||
}
|
||||
}
|
||||
countdown(60 + 30, &mut lcd, "Dev", &mut encoder, &pedal, &delay, &timer);
|
||||
write!(&mut lcd, "|-Ready stop").unwrap();
|
||||
while pedal.is_low().unwrap() {
|
||||
if !encoder.digital_read(ENCODER_SW_PIN).unwrap() {
|
||||
continue 'main;
|
||||
}
|
||||
}
|
||||
countdown(30, &mut lcd, "Stop", &mut encoder, &pedal, &delay, &timer);
|
||||
write!(&mut lcd, "|-Ready fix").unwrap();
|
||||
while pedal.is_low().unwrap() {
|
||||
if !encoder.digital_read(ENCODER_SW_PIN).unwrap() {
|
||||
continue 'main;
|
||||
}
|
||||
}
|
||||
countdown(30, &mut lcd, "Fix", &mut encoder, &pedal, &delay, &timer);
|
||||
mode = Mode::Timer;
|
||||
}
|
||||
}
|
||||
};
|
||||
delay.lock().delay_ms(100u32);
|
||||
}
|
||||
}
|
||||
|
||||
fn countdown<
|
||||
'a,
|
||||
I: I2CRead<Error = SE> + I2CWrite<Error = SE>,
|
||||
SE: Debug,
|
||||
P: InputPin<Error = PE>,
|
||||
PE: Debug,
|
||||
D: DelayMs<u32> + DelayUs<u32>,
|
||||
TM: Timer
|
||||
>(
|
||||
seconds: u64,
|
||||
lcd: &mut SerLCD<'a, I, D>,
|
||||
name: &str,
|
||||
encoder: &mut Seesaw<'a, I, D>,
|
||||
pedal: &P,
|
||||
delay: &Mutex<D>,
|
||||
timer: &TM,
|
||||
) {
|
||||
let start_time = timer.get_counter();
|
||||
let finish_time = start_time + (seconds as u64) * 1_000_000;
|
||||
write!(lcd, "|-{name}: {:0>2}:{:0>2}", seconds / 60, seconds % 60).unwrap();
|
||||
let mut next_print_time = start_time + 1_000_000;
|
||||
while timer.get_counter() < finish_time {
|
||||
let current_time = timer.get_counter();
|
||||
if next_print_time < timer.get_counter() {
|
||||
let current_seconds = ((finish_time - current_time) / 1_000_000)
|
||||
+ if ((finish_time - current_time) % 1_000_000) > 0 {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
write!(
|
||||
lcd,
|
||||
"|-{name}: {:0>2}:{:0>2}",
|
||||
current_seconds / 60,
|
||||
current_seconds % 60,
|
||||
)
|
||||
.unwrap();
|
||||
next_print_time += 1_000_000;
|
||||
}
|
||||
if !encoder.digital_read(ENCODER_SW_PIN).unwrap() && pedal.is_high().unwrap() {
|
||||
write!(lcd, "|-Canceled, release buttons").unwrap();
|
||||
while !encoder.digital_read(ENCODER_SW_PIN).unwrap() || pedal.is_high().unwrap() {}
|
||||
delay.lock().delay_ms(10);
|
||||
return;
|
||||
}
|
||||
delay.lock().delay_ms(10);
|
||||
}
|
||||
}
|
110
common/src/seesaw.rs
Normal file
110
common/src/seesaw.rs
Normal file
@ -0,0 +1,110 @@
|
||||
use embedded_hal::blocking::{i2c::{Read, Write}, delay::DelayUs};
|
||||
|
||||
mod registers;
|
||||
|
||||
use registers::*;
|
||||
use spin::Mutex;
|
||||
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum PinMode {
|
||||
#[allow(unused)]
|
||||
Output,
|
||||
Input,
|
||||
#[allow(unused)]
|
||||
InputPullup,
|
||||
#[allow(unused)]
|
||||
InputPulldown,
|
||||
}
|
||||
|
||||
pub struct Seesaw<'a, T, D> {
|
||||
i2c: T,
|
||||
addr: u8,
|
||||
delay: &'a Mutex<D>,
|
||||
}
|
||||
|
||||
impl<'a, T, D, E> Seesaw<'a, T, D>
|
||||
where
|
||||
T: Write<Error = E> + Read<Error = E>,
|
||||
D: DelayUs<u32>,
|
||||
{
|
||||
pub fn new(i2c: T, addr: u8, delay: &'a Mutex<D>) -> Self {
|
||||
Self { i2c, addr, delay }
|
||||
}
|
||||
|
||||
pub fn pin_mode(&mut self, pin: u8, mode: PinMode) -> Result<(), E> {
|
||||
if pin >= 32 {
|
||||
self.pin_mode_bulk(0, 1 << (pin as u32 - 32), mode)
|
||||
} else {
|
||||
self.pin_mode_bulk(1 << (pin as u32), 0, mode)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn digital_read(&mut self, pin: u8) -> Result<bool, E> {
|
||||
if pin >= 32 {
|
||||
Ok(self.digital_read_bulk_b(1 << (pin as u32 - 32))? != 0)
|
||||
} else {
|
||||
Ok(self.digital_read_bulk(1 << pin as u32)? != 0)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn digital_read_bulk(&mut self, pins: u32) -> Result<u32, E> {
|
||||
let mut buf = [0; 4];
|
||||
self.read(GpioRegisters::Read, &mut buf)?;
|
||||
Ok(u32::from_be_bytes(buf) & pins)
|
||||
}
|
||||
|
||||
pub fn digital_read_bulk_b(&mut self, pins: u32) -> Result<u32, E> {
|
||||
let mut buf = [0; 8];
|
||||
self.read(GpioRegisters::Read, &mut buf)?;
|
||||
Ok(u32::from_be_bytes(buf[4..8].try_into().unwrap()) & pins)
|
||||
}
|
||||
|
||||
pub fn pin_mode_bulk(&mut self, pinsa: u32, pinsb: u32, mode: PinMode) -> Result<(), E> {
|
||||
let mut cmd = [0; 8];
|
||||
cmd[0..4].copy_from_slice(&pinsa.to_be_bytes());
|
||||
cmd[4..8].copy_from_slice(&pinsb.to_be_bytes());
|
||||
match mode {
|
||||
PinMode::Output => self.write(GpioRegisters::Dirset, &cmd),
|
||||
PinMode::Input => self.write(GpioRegisters::Dirclr, &cmd),
|
||||
PinMode::InputPullup => {
|
||||
self.write(GpioRegisters::Dirclr, &cmd)?;
|
||||
self.write(GpioRegisters::Pullenset, &cmd)?;
|
||||
self.write(GpioRegisters::Set, &cmd)
|
||||
}
|
||||
PinMode::InputPulldown => {
|
||||
self.write(GpioRegisters::Dirclr, &cmd)?;
|
||||
self.write(GpioRegisters::Pullenset, &cmd)?;
|
||||
self.write(GpioRegisters::Clr, &cmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_encoder_delta(&mut self) -> Result<i32, E> {
|
||||
let mut buf = [0; 4];
|
||||
self.read(EncoderRegisters::Delta, &mut buf)?;
|
||||
Ok(i32::from_be_bytes(buf))
|
||||
}
|
||||
|
||||
pub fn read<R: Into<SeesawRegisters>>(&mut self, reg: R, data: &mut [u8]) -> Result<(), E> {
|
||||
let (modu, reg) = reg.into().into();
|
||||
|
||||
self.delay.lock().delay_us(500u32);
|
||||
self.i2c.write(self.addr, &[modu, reg])?;
|
||||
|
||||
self.delay.lock().delay_us(500u32);
|
||||
self.i2c.read(self.addr, data)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write<R: Into<SeesawRegisters>>(&mut self, reg: R, data: &[u8]) -> Result<(), E> {
|
||||
let (modu, reg) = reg.into().into();
|
||||
|
||||
self.delay.lock().delay_us(500u32);
|
||||
self.i2c.write(self.addr, &[modu, reg])?;
|
||||
|
||||
self.delay.lock().delay_us(500u32);
|
||||
self.i2c.write(self.addr, data)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
51
common/src/seesaw/registers.rs
Normal file
51
common/src/seesaw/registers.rs
Normal file
@ -0,0 +1,51 @@
|
||||
#[repr(u8)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum GpioRegisters {
|
||||
Dirset = 0x02,
|
||||
Dirclr = 0x03,
|
||||
Read = 0x04,
|
||||
Set = 0x05,
|
||||
Clr = 0x06,
|
||||
Toggle = 0x07,
|
||||
Intenset = 0x08,
|
||||
Intenclr = 0x09,
|
||||
Intflag = 0x0A,
|
||||
Pullenset = 0x0B,
|
||||
Pullenclr = 0x0C,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum EncoderRegisters {
|
||||
Status = 0x0,
|
||||
Intenset = 0x10,
|
||||
Intenclr = 0x20,
|
||||
Position = 0x30,
|
||||
Delta = 0x40,
|
||||
}
|
||||
|
||||
pub enum SeesawRegisters {
|
||||
Gpio(GpioRegisters),
|
||||
Encoder(EncoderRegisters),
|
||||
}
|
||||
|
||||
impl From<EncoderRegisters> for SeesawRegisters {
|
||||
fn from(v: EncoderRegisters) -> Self {
|
||||
Self::Encoder(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GpioRegisters> for SeesawRegisters {
|
||||
fn from(v: GpioRegisters) -> Self {
|
||||
Self::Gpio(v)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SeesawRegisters> for (u8, u8) {
|
||||
fn from(r: SeesawRegisters) -> Self {
|
||||
match r {
|
||||
SeesawRegisters::Gpio(r) => (0x01, r as u8),
|
||||
SeesawRegisters::Encoder(r) => (0x11, r as u8),
|
||||
}
|
||||
}
|
||||
}
|
3
common/src/timer.rs
Normal file
3
common/src/timer.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub trait Timer {
|
||||
fn get_counter(&self) -> u64;
|
||||
}
|
405
dev/Cargo.lock
generated
Normal file
405
dev/Cargo.lock
generated
Normal file
@ -0,0 +1,405 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "cassowary"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"embedded-hal",
|
||||
"shared-bus",
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.25.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossterm_winapi",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.26.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"crossterm_winapi",
|
||||
"libc",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"signal-hook",
|
||||
"signal-hook-mio",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossterm_winapi"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dev"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"common",
|
||||
"crossterm 0.26.1",
|
||||
"embedded-hal",
|
||||
"itertools",
|
||||
"parking_lot",
|
||||
"shared-bus",
|
||||
"tui",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
|
||||
dependencies = [
|
||||
"nb 0.1.3",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.144"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
|
||||
dependencies = [
|
||||
"nb 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.9.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc59d1bcc64fc5d021d67521f818db868368028108d37f0e98d74e33f68297b5"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "shared-bus"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f8438a40b91c8b9531c664e9680c55b92bd78cd6809a8b45b4512b1e5765f2"
|
||||
dependencies = [
|
||||
"embedded-hal",
|
||||
"nb 0.1.3",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-mio"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"mio",
|
||||
"signal-hook",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "git+https://github.com/mvdnes/spin-rs#5be251f5b52b653c2c40fcdc1089d38114125efa"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tui"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cassowary",
|
||||
"crossterm 0.25.0",
|
||||
"unicode-segmentation",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.45.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.42.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
16
dev/Cargo.toml
Normal file
16
dev/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "dev"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.71"
|
||||
common = { version = "0.1.0", path = "../common" }
|
||||
crossterm = "0.26.1"
|
||||
embedded-hal = "0.2.7"
|
||||
itertools = "0.10.5"
|
||||
parking_lot = "0.12.1"
|
||||
shared-bus = { version = "0.2.5", features = [ "std" ] }
|
||||
tui = "0.19.0"
|
33
dev/src/arc_wrp.rs
Normal file
33
dev/src/arc_wrp.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
pub struct ArcWrp<T>(Arc<T>);
|
||||
|
||||
impl<T> ArcWrp<T> {
|
||||
pub fn new(data: T) -> Self {
|
||||
Self(Arc::new(data))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for ArcWrp<T> {
|
||||
type Target = Arc<T>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for ArcWrp<T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
// Must use instead of derive or arc_wrp.clone() calls clone on the inner Arc
|
||||
impl<T> Clone for ArcWrp<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
24
dev/src/delay.rs
Normal file
24
dev/src/delay.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use std::time::Duration;
|
||||
|
||||
use embedded_hal::blocking::delay::{DelayMs, DelayUs};
|
||||
|
||||
pub struct Delay;
|
||||
|
||||
impl Delay {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl DelayMs<u32> for Delay {
|
||||
fn delay_ms(&mut self, ms: u32) {
|
||||
std::thread::sleep(Duration::from_millis(ms as u64));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl DelayUs<u32> for Delay {
|
||||
fn delay_us(&mut self, us: u32) {
|
||||
std::thread::sleep(Duration::from_micros(us as u64));
|
||||
}
|
||||
}
|
78
dev/src/encoder.rs
Normal file
78
dev/src/encoder.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
struct EncoderMutState {
|
||||
read_buf: Vec<u8>,
|
||||
command: Option<(u8, u8)>,
|
||||
}
|
||||
|
||||
pub struct Encoder {
|
||||
mut_state: Mutex<EncoderMutState>,
|
||||
delta: AtomicI32,
|
||||
button: AtomicBool,
|
||||
}
|
||||
|
||||
impl Encoder {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
mut_state: Mutex::new(EncoderMutState {
|
||||
read_buf: Vec::new(),
|
||||
command: None,
|
||||
}),
|
||||
delta: AtomicI32::new(0),
|
||||
button: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self, bytes: &[u8]) {
|
||||
let mut mut_state = self.mut_state.lock();
|
||||
if let Some(_command) = mut_state.command {
|
||||
mut_state.command = None;
|
||||
} else {
|
||||
mut_state.read_buf.clear();
|
||||
mut_state.command = Some((bytes[0], bytes[1]));
|
||||
match (bytes[0], bytes[1]) {
|
||||
// GPIO read
|
||||
(0x01, 0x04) => {
|
||||
let button_resp = self.button.load(Ordering::Relaxed);
|
||||
if button_resp {
|
||||
mut_state
|
||||
.read_buf
|
||||
.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]);
|
||||
} else {
|
||||
mut_state
|
||||
.read_buf
|
||||
.extend_from_slice(&[1, 0, 0, 0, 0, 0, 0, 0]);
|
||||
}
|
||||
mut_state.command = None
|
||||
}
|
||||
// Encoder delta
|
||||
(0x11, 0x40) => {
|
||||
mut_state
|
||||
.read_buf
|
||||
.extend_from_slice(&(self.delta.swap(0, Ordering::Relaxed)).to_be_bytes());
|
||||
mut_state.command = None;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self, buffer: &mut [u8]) {
|
||||
let mut mut_state = self.mut_state.lock();
|
||||
let mut buf_remaining = buffer.len();
|
||||
while mut_state.read_buf.len() > 0 && buf_remaining > 0 {
|
||||
buffer[buffer.len() - buf_remaining] = mut_state.read_buf.remove(0);
|
||||
buf_remaining -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delta(&self) -> &AtomicI32 {
|
||||
&self.delta
|
||||
}
|
||||
|
||||
pub fn button(&self) -> &AtomicBool {
|
||||
&self.button
|
||||
}
|
||||
}
|
57
dev/src/i2c.rs
Normal file
57
dev/src/i2c.rs
Normal file
@ -0,0 +1,57 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::{encoder::Encoder, lcd::Lcd};
|
||||
|
||||
use embedded_hal::blocking::i2c::{Read as I2CRead, Write as I2CWrite};
|
||||
|
||||
pub struct I2C {
|
||||
lcd: Lcd,
|
||||
encoder: Arc<Encoder>,
|
||||
}
|
||||
|
||||
impl I2C {
|
||||
pub fn new(lcd: Lcd, encoder: Arc<Encoder>) -> Self {
|
||||
Self { lcd, encoder }
|
||||
}
|
||||
}
|
||||
|
||||
impl I2CRead for I2C {
|
||||
type Error = ();
|
||||
|
||||
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
|
||||
#[allow(clippy::single_match)]
|
||||
match address {
|
||||
// Ignore LCD read
|
||||
0x72 => (),
|
||||
0x36 => {
|
||||
self.encoder.read(buffer);
|
||||
}
|
||||
_ => panic!(
|
||||
"I2C read from unknown device at address {:#x} of {} bytes",
|
||||
address,
|
||||
buffer.len()
|
||||
),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl I2CWrite for I2C {
|
||||
type Error = ();
|
||||
|
||||
fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
|
||||
match address {
|
||||
0x72 => {
|
||||
self.lcd.write(bytes);
|
||||
}
|
||||
0x36 => {
|
||||
self.encoder.write(bytes);
|
||||
}
|
||||
_ => panic!(
|
||||
"I2C write to unknown device at address {:#x} with data {:?}",
|
||||
address, bytes
|
||||
),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
58
dev/src/lcd.rs
Normal file
58
dev/src/lcd.rs
Normal file
@ -0,0 +1,58 @@
|
||||
use std::sync::{mpsc::Sender, Arc};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use crate::Message;
|
||||
|
||||
struct LcdCommon {
|
||||
cursor: Mutex<u8>,
|
||||
text: Mutex<[u8; 0x68]>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Lcd {
|
||||
channel: Sender<Message>,
|
||||
common: Arc<LcdCommon>,
|
||||
}
|
||||
|
||||
impl Lcd {
|
||||
pub fn new(channel: Sender<Message>) -> Self {
|
||||
Self {
|
||||
channel,
|
||||
common: Arc::new(LcdCommon {
|
||||
cursor: Mutex::new(0),
|
||||
text: Mutex::new([b' '; 0x68]),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write(&self, bytes: &[u8]) {
|
||||
let mut cursor = self.common.cursor.lock();
|
||||
let mut i = 0;
|
||||
while i < bytes.len() {
|
||||
if bytes[i] == b'|' {
|
||||
match bytes[i + 1] {
|
||||
b'|' => todo!(),
|
||||
b'-' => {
|
||||
*self.common.text.lock() = [b' '; 0x68];
|
||||
*cursor = 0;
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
if bytes[i] & 0x80 == 0x80 {
|
||||
*cursor = bytes[i] & 0x7F;
|
||||
}
|
||||
i += 1;
|
||||
} else {
|
||||
self.common.text.lock()[*cursor as usize] = bytes[i];
|
||||
*cursor += 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
self.channel.send(Message::Update).unwrap();
|
||||
}
|
||||
|
||||
pub fn text(&self) -> &Mutex<[u8; 0x68]> {
|
||||
&self.common.text
|
||||
}
|
||||
}
|
168
dev/src/main.rs
Normal file
168
dev/src/main.rs
Normal file
@ -0,0 +1,168 @@
|
||||
mod arc_wrp;
|
||||
mod delay;
|
||||
mod encoder;
|
||||
mod i2c;
|
||||
mod lcd;
|
||||
mod pedal;
|
||||
mod relay;
|
||||
mod timer;
|
||||
mod uart;
|
||||
|
||||
use std::{
|
||||
io,
|
||||
sync::{atomic::Ordering, mpsc::channel, Arc},
|
||||
};
|
||||
|
||||
use arc_wrp::ArcWrp;
|
||||
use crossterm::{
|
||||
event::{Event, KeyCode},
|
||||
terminal::{disable_raw_mode, enable_raw_mode},
|
||||
};
|
||||
use delay::Delay;
|
||||
use encoder::Encoder;
|
||||
use i2c::I2C;
|
||||
use lcd::Lcd;
|
||||
use pedal::Pedal;
|
||||
use relay::Relay;
|
||||
use shared_bus::BusManagerStd;
|
||||
use timer::Timer;
|
||||
use tui::{
|
||||
backend::CrosstermBackend,
|
||||
layout::Rect,
|
||||
widgets::{Block, Borders, Paragraph},
|
||||
Terminal,
|
||||
};
|
||||
use uart::Uart;
|
||||
|
||||
pub enum Message {
|
||||
Update,
|
||||
Quit,
|
||||
}
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
enable_raw_mode()?;
|
||||
let stdout = io::stdout();
|
||||
let backend = CrosstermBackend::new(stdout);
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
let (tx, rx) = channel();
|
||||
let uart = ArcWrp::new(Uart::new());
|
||||
let lcd = Lcd::new(tx.clone());
|
||||
let encoder = Arc::new(Encoder::new());
|
||||
let i2c = BusManagerStd::new(I2C::new(lcd.clone(), encoder.clone()));
|
||||
let timer = ArcWrp::new(Timer::new());
|
||||
let delay = Delay::new();
|
||||
let pedal = ArcWrp::new(Pedal::new());
|
||||
let relay = Relay::new(tx.clone());
|
||||
{
|
||||
let timer = timer.clone();
|
||||
let uart = uart.clone();
|
||||
let pedal = pedal.clone();
|
||||
let relay = relay.clone();
|
||||
std::thread::spawn(move || common::main(uart, i2c, timer, delay, pedal, relay));
|
||||
}
|
||||
{
|
||||
let tx = tx.clone();
|
||||
let pedal = pedal.clone();
|
||||
let encoder = encoder.clone();
|
||||
let timer = timer.clone();
|
||||
std::thread::spawn(move || loop {
|
||||
let event = crossterm::event::read().unwrap();
|
||||
if let Event::Key(event) = event {
|
||||
match event.code {
|
||||
KeyCode::Char('q') => {
|
||||
tx.send(Message::Quit).unwrap();
|
||||
continue;
|
||||
}
|
||||
KeyCode::Right => {
|
||||
encoder.delta().fetch_sub(1, Ordering::Relaxed);
|
||||
}
|
||||
KeyCode::Left => {
|
||||
encoder.delta().fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
KeyCode::Char('e') => {
|
||||
let old = encoder.button().load(Ordering::Relaxed);
|
||||
encoder.button().store(!old, Ordering::Relaxed);
|
||||
}
|
||||
KeyCode::Char('p') => {
|
||||
pedal.state().store(true, Ordering::Relaxed);
|
||||
}
|
||||
KeyCode::Char('n') => {
|
||||
if timer.time_mult().load(Ordering::Relaxed) > 1 {
|
||||
timer.time_mult().fetch_sub(1, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
KeyCode::Char('m') => {
|
||||
timer.time_mult().fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
tx.send(Message::Update).unwrap();
|
||||
});
|
||||
}
|
||||
terminal.clear()?;
|
||||
let term_size = terminal.size()?;
|
||||
let uart_height = term_size.height;
|
||||
let uart_width = term_size.width - 22;
|
||||
let mut lcd_render = String::new();
|
||||
loop {
|
||||
terminal.draw(|f| {
|
||||
if let Some(lcd_text) = lcd.text().try_lock() {
|
||||
lcd_render.clear();
|
||||
for c in &lcd_text[0x0..0x14] {
|
||||
lcd_render.push(*c as char);
|
||||
}
|
||||
for c in &lcd_text[0x40..0x54] {
|
||||
lcd_render.push(*c as char);
|
||||
}
|
||||
for c in &lcd_text[0x14..0x28] {
|
||||
lcd_render.push(*c as char);
|
||||
}
|
||||
for c in &lcd_text[0x54..0x68] {
|
||||
lcd_render.push(*c as char);
|
||||
}
|
||||
}
|
||||
f.render_widget(
|
||||
Paragraph::new(&*lcd_render)
|
||||
.block(Block::default().title("LCD").borders(Borders::ALL)),
|
||||
Rect::new(0, 0, 20, 6),
|
||||
);
|
||||
let relay_text = if relay.state().load(Ordering::Relaxed) {
|
||||
"Enlarger on"
|
||||
} else {
|
||||
"Enlarger off"
|
||||
};
|
||||
f.render_widget(Paragraph::new(relay_text), Rect::new(0, 7, 12, 1));
|
||||
f.render_widget(
|
||||
Paragraph::new(format!(
|
||||
"Time mult: x{}",
|
||||
timer.time_mult().load(Ordering::Relaxed)
|
||||
)),
|
||||
Rect::new(0, 9, 22, 1),
|
||||
);
|
||||
let enc_button_text = if encoder.button().load(Ordering::Relaxed) {
|
||||
"Encoder pressed"
|
||||
} else {
|
||||
"Encoder released"
|
||||
};
|
||||
f.render_widget(Paragraph::new(enc_button_text), Rect::new(0, 11, 16, 1));
|
||||
f.render_widget(Paragraph::new(format!("Encoder delta: {}", encoder.delta().load(Ordering::Relaxed))), Rect::new(0, 13, 22, 1));
|
||||
f.render_widget(
|
||||
Paragraph::new(&**uart.out().lock())
|
||||
.block(Block::default().title("UART").borders(Borders::ALL)),
|
||||
Rect::new(22, 0, uart_width, uart_height),
|
||||
);
|
||||
})?;
|
||||
match rx.recv() {
|
||||
Ok(m) => match m {
|
||||
Message::Update => (),
|
||||
Message::Quit => break,
|
||||
},
|
||||
Err(_) => panic!(),
|
||||
}
|
||||
}
|
||||
terminal.clear()?;
|
||||
terminal.set_cursor(0, 0)?;
|
||||
disable_raw_mode()?;
|
||||
Ok(())
|
||||
}
|
33
dev/src/pedal.rs
Normal file
33
dev/src/pedal.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use embedded_hal::digital::v2::InputPin;
|
||||
|
||||
use crate::arc_wrp::ArcWrp;
|
||||
|
||||
pub struct Pedal {
|
||||
state: AtomicBool,
|
||||
}
|
||||
|
||||
impl Pedal {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
state: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn state(&self) -> &AtomicBool {
|
||||
&self.state
|
||||
}
|
||||
}
|
||||
|
||||
impl InputPin for ArcWrp<Pedal> {
|
||||
type Error = ();
|
||||
|
||||
fn is_high(&self) -> Result<bool, Self::Error> {
|
||||
Ok(self.state.swap(false, Ordering::Relaxed))
|
||||
}
|
||||
|
||||
fn is_low(&self) -> Result<bool, Self::Error> {
|
||||
self.is_high().map(|x| !x)
|
||||
}
|
||||
}
|
44
dev/src/relay.rs
Normal file
44
dev/src/relay.rs
Normal file
@ -0,0 +1,44 @@
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
mpsc::Sender,
|
||||
Arc,
|
||||
};
|
||||
|
||||
use embedded_hal::digital::v2::OutputPin;
|
||||
|
||||
use crate::Message;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Relay {
|
||||
channel: Sender<Message>,
|
||||
state: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl Relay {
|
||||
pub fn new(channel: Sender<Message>) -> Self {
|
||||
Self {
|
||||
channel,
|
||||
state: Arc::new(AtomicBool::new(false)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn state(&self) -> &AtomicBool {
|
||||
self.state.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl OutputPin for Relay {
|
||||
type Error = ();
|
||||
|
||||
fn set_low(&mut self) -> Result<(), Self::Error> {
|
||||
self.state.store(false, Ordering::Relaxed);
|
||||
self.channel.send(Message::Update).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_high(&mut self) -> Result<(), Self::Error> {
|
||||
self.state.store(true, Ordering::Relaxed);
|
||||
self.channel.send(Message::Update).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
}
|
31
dev/src/timer.rs
Normal file
31
dev/src/timer.rs
Normal file
@ -0,0 +1,31 @@
|
||||
use std::{
|
||||
sync::atomic::{AtomicU32, Ordering},
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
use crate::arc_wrp::ArcWrp;
|
||||
|
||||
pub struct Timer {
|
||||
start_time: Instant,
|
||||
time_mult: AtomicU32,
|
||||
}
|
||||
|
||||
impl Timer {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
start_time: Instant::now(),
|
||||
time_mult: AtomicU32::new(1),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn time_mult(&self) -> &AtomicU32 {
|
||||
&self.time_mult
|
||||
}
|
||||
}
|
||||
|
||||
impl common::timer::Timer for ArcWrp<Timer> {
|
||||
fn get_counter(&self) -> u64 {
|
||||
Instant::now().duration_since(self.start_time).as_micros() as u64
|
||||
* self.time_mult.load(Ordering::Relaxed) as u64
|
||||
}
|
||||
}
|
28
dev/src/uart.rs
Normal file
28
dev/src/uart.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use std::fmt::Write;
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use crate::arc_wrp::ArcWrp;
|
||||
|
||||
pub struct Uart {
|
||||
out: Mutex<String>,
|
||||
}
|
||||
|
||||
impl Uart {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
out: Mutex::new(String::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn out(&self) -> &Mutex<String> {
|
||||
&self.out
|
||||
}
|
||||
}
|
||||
|
||||
impl Write for ArcWrp<Uart> {
|
||||
fn write_str(&mut self, s: &str) -> std::fmt::Result {
|
||||
*self.out.lock() += s;
|
||||
Ok(())
|
||||
}
|
||||
}
|
15
embedded/.cargo/config
Normal file
15
embedded/.cargo/config
Normal file
@ -0,0 +1,15 @@
|
||||
[build]
|
||||
target = "thumbv6m-none-eabi" # Adafruit QT Py - SAMD21
|
||||
|
||||
[target.thumbv6m-none-eabi]
|
||||
runner = 'elf2uf2-rs -d'
|
||||
|
||||
rustflags = [
|
||||
|
||||
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
|
||||
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
|
||||
"-C", "link-arg=--nmagic",
|
||||
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"--cfg", "portable_atomic_unsafe_assume_single_core",
|
||||
]
|
412
embedded/Cargo.lock
generated
Normal file
412
embedded/Cargo.lock
generated
Normal file
@ -0,0 +1,412 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adafruit-qt-py-rp2040"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e36e061b89c1354cab7a96173730928d67e9970ad509cd295af724abb30920b6"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"rp2040-boot2",
|
||||
"rp2040-hal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "bare-metal"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
|
||||
dependencies = [
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitfield"
|
||||
version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
|
||||
|
||||
[[package]]
|
||||
name = "common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"embedded-hal",
|
||||
"shared-bus",
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m"
|
||||
version = "0.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
|
||||
dependencies = [
|
||||
"bare-metal",
|
||||
"bitfield",
|
||||
"embedded-hal",
|
||||
"volatile-register",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m-rt"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1"
|
||||
dependencies = [
|
||||
"cortex-m-rt-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cortex-m-rt-macros"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc-any"
|
||||
version = "2.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "774646b687f63643eb0f4bf13dc263cb581c8c9e57973b6ddf78bda3994d88df"
|
||||
dependencies = [
|
||||
"debug-helper",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52"
|
||||
|
||||
[[package]]
|
||||
name = "debug-helper"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f578e8e2c440e7297e008bb5486a3a8a194775224bbc23729b0dbdfaeebf162e"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
|
||||
|
||||
[[package]]
|
||||
name = "embedded-dma"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446"
|
||||
dependencies = [
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "embedded-hal"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
|
||||
dependencies = [
|
||||
"nb 0.1.3",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fugit"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ab17bb279def6720d058cb6c052249938e7f99260ab534879281a95367a87e5"
|
||||
dependencies = [
|
||||
"gcd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gcd"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
|
||||
dependencies = [
|
||||
"nb 1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nb"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
|
||||
dependencies = [
|
||||
"num_enum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
|
||||
|
||||
[[package]]
|
||||
name = "pio"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76e09694b50f89f302ed531c1f2a7569f0be5867aee4ab4f8f729bbeec0078e3"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"num_enum",
|
||||
"paste",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc59d1bcc64fc5d021d67521f818db868368028108d37f0e98d74e33f68297b5"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
|
||||
[[package]]
|
||||
name = "rp2040-boot2"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c773ec49b836077aa144b58dc7654a243e1eecdb6cf0d25361ae7c7600fabd8"
|
||||
dependencies = [
|
||||
"crc-any",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rp2040-hal"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1369bb84862d7f69391a96606b2f29a00bfce7f29a749e23d5f01fc3f607ada0"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"critical-section",
|
||||
"embedded-dma",
|
||||
"embedded-hal",
|
||||
"fugit",
|
||||
"itertools",
|
||||
"nb 1.1.0",
|
||||
"paste",
|
||||
"pio",
|
||||
"rand_core",
|
||||
"rp2040-hal-macros",
|
||||
"rp2040-pac",
|
||||
"usb-device",
|
||||
"vcell",
|
||||
"void",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rp2040-hal-macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86479063e497efe1ae81995ef9071f54fd1c7427e04d6c5b84cde545ff672a5e"
|
||||
dependencies = [
|
||||
"cortex-m-rt",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rp2040-pac"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9192cafbb40d717c9e0ddf767aaf9c69fee1b4e48d22ed853b57b11f6d9f3d7e"
|
||||
dependencies = [
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"vcell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
dependencies = [
|
||||
"semver-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
|
||||
[[package]]
|
||||
name = "shared-bus"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05f8438a40b91c8b9531c664e9680c55b92bd78cd6809a8b45b4512b1e5765f2"
|
||||
dependencies = [
|
||||
"embedded-hal",
|
||||
"nb 0.1.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "git+https://github.com/mvdnes/spin-rs#5be251f5b52b653c2c40fcdc1089d38114125efa"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "timer"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"adafruit-qt-py-rp2040",
|
||||
"common",
|
||||
"cortex-m",
|
||||
"cortex-m-rt",
|
||||
"embedded-hal",
|
||||
"fugit",
|
||||
"shared-bus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
|
||||
|
||||
[[package]]
|
||||
name = "usb-device"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f6cc3adc849b5292b4075fc0d5fdcf2f24866e88e336dd27a8943090a520508"
|
||||
|
||||
[[package]]
|
||||
name = "vcell"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
|
||||
[[package]]
|
||||
name = "volatile-register"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6"
|
||||
dependencies = [
|
||||
"vcell",
|
||||
]
|
15
embedded/Cargo.toml
Normal file
15
embedded/Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
||||
[package]
|
||||
name = "timer"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
adafruit-qt-py-rp2040 = "0.6.0"
|
||||
common = { version = "0.1.0", path = "../common" }
|
||||
cortex-m = "0.7.7"
|
||||
cortex-m-rt = "0.7.3"
|
||||
embedded-hal = "0.2.7"
|
||||
fugit = "0.3.6"
|
||||
shared-bus = { version = "0.2.5" }
|
16
embedded/build.rs
Normal file
16
embedded/build.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
fn main() {
|
||||
if env::var_os("CARGO_FEATURE_RT").is_some() {
|
||||
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
File::create(out.join("memory.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("memory.x"))
|
||||
.unwrap();
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
println!("cargo:rerun-if-changed=memory.x");
|
||||
}
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
}
|
36
embedded/memory.x
Normal file
36
embedded/memory.x
Normal file
@ -0,0 +1,36 @@
|
||||
MEMORY {
|
||||
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
|
||||
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
|
||||
/*
|
||||
* RAM consists of 4 banks, SRAM0-SRAM3, with a striped mapping.
|
||||
* This is usually good for performance, as it distributes load on
|
||||
* those banks evenly.
|
||||
*/
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 256K
|
||||
/*
|
||||
* RAM banks 4 and 5 use a direct mapping. They can be used to have
|
||||
* memory areas dedicated for some specific job, improving predictability
|
||||
* of access times.
|
||||
* Example: Separate stacks for core0 and core1.
|
||||
*/
|
||||
SRAM4 : ORIGIN = 0x20040000, LENGTH = 4k
|
||||
SRAM5 : ORIGIN = 0x20041000, LENGTH = 4k
|
||||
|
||||
/* SRAM banks 0-3 can also be accessed directly. However, those ranges
|
||||
alias with the RAM mapping, above. So don't use them at the same time!
|
||||
SRAM0 : ORIGIN = 0x21000000, LENGTH = 64k
|
||||
SRAM1 : ORIGIN = 0x21010000, LENGTH = 64k
|
||||
SRAM2 : ORIGIN = 0x21020000, LENGTH = 64k
|
||||
SRAM3 : ORIGIN = 0x21030000, LENGTH = 64k
|
||||
*/
|
||||
}
|
||||
|
||||
EXTERN(BOOT2_FIRMWARE)
|
||||
|
||||
SECTIONS {
|
||||
/* ### Boot loader */
|
||||
.boot2 ORIGIN(BOOT2) :
|
||||
{
|
||||
KEEP(*(.boot2));
|
||||
} > BOOT2
|
||||
} INSERT BEFORE .text;
|
73
embedded/src/main.rs
Normal file
73
embedded/src/main.rs
Normal file
@ -0,0 +1,73 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
mod panic_handler;
|
||||
mod timer;
|
||||
|
||||
use adafruit_qt_py_rp2040::{
|
||||
hal::{
|
||||
clocks,
|
||||
sio,
|
||||
uart::{UartPeripheral, UartConfig, DataBits, StopBits},
|
||||
Clock, Timer, Watchdog, I2C,
|
||||
},
|
||||
pac, entry,
|
||||
};
|
||||
use cortex_m::delay::Delay as CortexDelay;
|
||||
use fugit::RateExtU32;
|
||||
use shared_bus::BusManagerSimple;
|
||||
use timer::TimerWrp;
|
||||
|
||||
use common::{self, main};
|
||||
|
||||
const XTAL_FREQ_HZ: u32 = 12_000_000;
|
||||
|
||||
#[entry]
|
||||
fn startup() -> ! {
|
||||
let core_peripherals = pac::CorePeripherals::take().unwrap();
|
||||
let mut peripherals = pac::Peripherals::take().unwrap();
|
||||
let mut watchdog = Watchdog::new(peripherals.WATCHDOG);
|
||||
let clocks = clocks::init_clocks_and_plls(
|
||||
XTAL_FREQ_HZ,
|
||||
peripherals.XOSC,
|
||||
peripherals.CLOCKS,
|
||||
peripherals.PLL_SYS,
|
||||
peripherals.PLL_USB,
|
||||
&mut peripherals.RESETS,
|
||||
&mut watchdog,
|
||||
)
|
||||
.unwrap_or_else(|_| panic!("Failed to init clocks"));
|
||||
let sio = sio::Sio::new(peripherals.SIO);
|
||||
let pins = adafruit_qt_py_rp2040::Pins::new(
|
||||
peripherals.IO_BANK0,
|
||||
peripherals.PADS_BANK0,
|
||||
sio.gpio_bank0,
|
||||
&mut peripherals.RESETS,
|
||||
);
|
||||
let uart = UartPeripheral::new(
|
||||
peripherals.UART1,
|
||||
(
|
||||
pins.tx.into_mode(),
|
||||
pins.rx.into_mode(),
|
||||
),
|
||||
&mut peripherals.RESETS,
|
||||
)
|
||||
.enable(UartConfig::new(9600u32.Hz(), DataBits::Eight, None, StopBits::One), clocks.peripheral_clock.freq())
|
||||
.unwrap();
|
||||
let i2c = BusManagerSimple::new(I2C::i2c1(
|
||||
peripherals.I2C1,
|
||||
pins.sda1.into_mode(),
|
||||
pins.scl1.into_mode(),
|
||||
100u32.kHz(),
|
||||
&mut peripherals.RESETS,
|
||||
&clocks.system_clock,
|
||||
));
|
||||
let timer = TimerWrp(Timer::new(peripherals.TIMER, &mut peripherals.RESETS));
|
||||
let delay = CortexDelay::new(
|
||||
core_peripherals.SYST,
|
||||
clocks.system_clock.freq().to_Hz(),
|
||||
);
|
||||
let pedal = pins.a0.into_pull_down_input();
|
||||
let relay = pins.a1.into_push_pull_output();
|
||||
main(uart, i2c, timer, delay, pedal, relay);
|
||||
}
|
9
embedded/src/panic_handler.rs
Normal file
9
embedded/src/panic_handler.rs
Normal file
@ -0,0 +1,9 @@
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(_info: &PanicInfo<'_>) -> ! {
|
||||
// println!("{}", info);
|
||||
loop {
|
||||
cortex_m::asm::wfi()
|
||||
}
|
||||
}
|
14
embedded/src/timer.rs
Normal file
14
embedded/src/timer.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use adafruit_qt_py_rp2040::hal::Timer as QtTimer;
|
||||
use common::timer::Timer;
|
||||
use fugit::Instant;
|
||||
|
||||
pub struct TimerWrp(pub QtTimer);
|
||||
|
||||
impl Timer for TimerWrp {
|
||||
fn get_counter(&self) -> u64 {
|
||||
// Confirm that the ratio of ticks is as expected by explicitly specifying the type
|
||||
let instant: Instant<u64, 1, 1_000_000> = QtTimer::get_counter(&self.0);
|
||||
instant.ticks()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user