artiq/artiq/firmware/libboard_artiq/grabber.rs

112 lines
2.8 KiB
Rust

use board_misoc::csr;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum State {
Down,
WaitResolution,
Up
}
static mut GRABBER_STATE: &'static mut [State] = &mut [State::Down; csr::GRABBER_LEN];
fn get_pll_reset(g: usize) -> bool {
unsafe { (csr::GRABBER[g].pll_reset_read)() != 0 }
}
fn set_pll_reset(g: usize, reset: bool) {
let val = if reset { 1 } else { 0 };
unsafe { (csr::GRABBER[g].pll_reset_write)(val) }
}
fn pll_locked(g: usize) -> bool {
unsafe { (csr::GRABBER[g].pll_locked_read)() != 0 }
}
fn clock_pattern_ok(g: usize) -> bool {
unsafe { (csr::GRABBER[g].clk_sampled_read)() == 0b1100011 }
}
fn clock_pattern_ok_filter(g: usize) -> bool {
for _ in 0..128 {
if !clock_pattern_ok(g) {
return false;
}
}
true
}
fn phase_shift(g: usize, direction: u8) {
unsafe {
(csr::GRABBER[g].phase_shift_write)(direction);
while (csr::GRABBER[g].phase_shift_done_read)() == 0 {}
}
}
fn clock_align(g: usize) -> bool {
while clock_pattern_ok_filter(g) {
phase_shift(g, 1);
}
phase_shift(g, 1);
let mut count = 0;
while !clock_pattern_ok_filter(g) {
phase_shift(g, 1);
count += 1;
if count > 1024 {
return false;
}
}
let mut window = 1;
phase_shift(g, 1);
while clock_pattern_ok_filter(g) {
phase_shift(g, 1);
window += 1;
}
for _ in 0..window/2 {
phase_shift(g, 0);
}
true
}
fn get_last_pixels(g: usize) -> (u16, u16) {
unsafe { ((csr::GRABBER[g].last_x_read)(),
(csr::GRABBER[g].last_y_read)()) }
}
pub fn tick() {
for g in 0..csr::GRABBER.len() {
if unsafe { GRABBER_STATE[g] != State::Down } {
if !clock_pattern_ok(g) || !pll_locked(g) {
set_pll_reset(g, true);
unsafe { GRABBER_STATE[g] = State::Down; }
info!("grabber{} is down", g);
}
if unsafe { GRABBER_STATE[g] == State::WaitResolution } {
let (last_x, last_y) = get_last_pixels(g);
info!("grabber{} detected frame size: {}x{}",
g, last_x + 1, last_y + 1);
unsafe { GRABBER_STATE[g] = State::Up; }
}
} else {
if get_pll_reset(g) {
set_pll_reset(g, false);
} else {
if pll_locked(g) {
info!("grabber{} PLL is locked", g);
if clock_align(g) {
info!("grabber{} is up", g);
unsafe { GRABBER_STATE[g] = State::WaitResolution; }
} else {
set_pll_reset(g, true);
}
} else {
set_pll_reset(g, true);
}
}
}
}
}