use crate::core::error::Result;
use crate::core::state::{Sink, Source};
use super::units::LengthCounter;
const SEQUENCE: [u8; 32] = [
15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
];
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Triangle {
pub length: LengthCounter,
linear: u8,
linear_reload_value: u8,
linear_reload: bool,
control: bool,
period: u16,
timer: u16,
step: u8,
halt_ultrasonic: bool,
}
impl Triangle {
pub const fn new(halt_ultrasonic: bool) -> Triangle {
Triangle {
length: LengthCounter::new(),
linear: 0,
linear_reload_value: 0,
linear_reload: false,
control: false,
period: 0,
timer: 0,
step: 0,
halt_ultrasonic,
}
}
#[inline]
pub const fn linear(&self) -> u8 {
self.linear
}
#[inline]
pub const fn period(&self) -> u16 {
self.period
}
pub fn write_linear(&mut self, value: u8) {
self.control = value & 0x80 != 0;
self.length.set_halt(self.control);
self.linear_reload_value = value & 0x7F;
}
pub fn write_period_low(&mut self, value: u8) {
self.period = (self.period & 0x0700) | u16::from(value);
}
pub fn write_period_high(&mut self, value: u8) {
self.period = (self.period & 0x00FF) | (u16::from(value & 0x07) << 8);
self.length.load(value);
self.linear_reload = true;
}
pub fn clock_linear(&mut self) {
if self.linear_reload {
self.linear = self.linear_reload_value;
} else if self.linear > 0 {
self.linear -= 1;
}
if !self.control {
self.linear_reload = false;
}
}
pub fn tick_timer(&mut self) {
if self.timer == 0 {
self.timer = self.period;
if self.length.active() && self.linear > 0 && !self.ultrasonic() {
self.step = (self.step + 1) & 31;
}
} else {
self.timer -= 1;
}
}
#[inline]
const fn ultrasonic(&self) -> bool {
self.halt_ultrasonic && self.period < 2
}
pub fn output(&self) -> u8 {
SEQUENCE[usize::from(self.step)]
}
pub fn reset_phase(&mut self) {
self.step = 0;
}
pub fn save(&self, w: &mut dyn Sink) -> Result<()> {
self.length.save(w)?;
w.write_u8(self.linear)?;
w.write_u8(self.linear_reload_value)?;
w.write_bool(self.linear_reload)?;
w.write_bool(self.control)?;
w.write_u16(self.period)?;
w.write_u16(self.timer)?;
w.write_u8(self.step)
}
pub fn load<'a>(&mut self, r: &mut dyn Source<'a>) -> Result<()> {
self.length.load_state(r)?;
self.linear = r.read_u8()?;
self.linear_reload_value = r.read_u8()? & 0x7F;
self.linear_reload = r.read_bool()?;
self.control = r.read_bool()?;
self.period = r.read_u16()? & 0x07FF;
self.timer = r.read_u16()?;
self.step = r.read_u8()? & 31;
Ok(())
}
}