move to modular servicer design

This commit is contained in:
sigil-03 2025-08-16 17:03:29 -06:00
parent 77188a3eaa
commit 51af5c3343
9 changed files with 371 additions and 154 deletions

View file

@ -0,0 +1,165 @@
use adpcm_pwm_dac::dac;
use ch32_hal::timer::GeneralInstance16bit;
use ch32_hal::timer::simple_pwm::SimplePwm;
use ch32_hal::timer::Channel;
use ch32_hal::delay::Delay;
use crate::insert_coin::services::{DacService, LedService, Service, ServiceData};
pub struct SimplePwmCore<'d, T: GeneralInstance16bit> {
pwm: core::cell::RefCell<SimplePwm<'d, T>>,
}
impl<'d, T: GeneralInstance16bit> SimplePwmCore<'d, T> {
pub fn new(pwm: SimplePwm<'d, T>) -> Self {
Self {
pwm: core::cell::RefCell::new(pwm),
}
}
// pub fn get_handle(&'d self, ch: Channel) -> SimplePwmHandle<'d, '_, T> {
// SimplePwmHandle {
// core: &self,
// channel: ch,
// }
// }
pub fn write_amplitude(&self, ch: Channel, amplitude: u8) {
if !self.pwm.borrow().is_enabled(ch) {
self.pwm.borrow_mut().enable(ch);
}
let max_duty = self.pwm.borrow().get_max_duty();
let dc = amplitude as u32 * max_duty / 100;
self.pwm.borrow_mut().set_duty(ch, dc);
}
pub fn disable(&self, ch: Channel) {
self.pwm.borrow_mut().disable(ch);
}
}
pub struct CoreConfig {
tick_rate_hz: usize,
}
impl CoreConfig {
pub fn new(tick_rate_hz: usize) -> Self {
Self {
tick_rate_hz,
}
}
}
#[derive(Default)]
struct Core {
tick: usize,
}
pub struct InsertCoin<'a, T: GeneralInstance16bit> {
core: Core,
config: CoreConfig,
pwm_core: SimplePwmCore<'a, T>,
led0: LedService,
led1: LedService,
// led2: LedService,
dac: DacService<'a>,
}
impl<'a, T: GeneralInstance16bit> InsertCoin<'a, T> {
pub fn new(config: CoreConfig, pwm_core: SimplePwmCore<'a, T>) -> Self {
// LED0 servicer setup
let led0_blink_rate_hz = 9;
let led0_tick_per_service = (config.tick_rate_hz/(led0_blink_rate_hz * 2));
let led0_service_data = ServiceData::new(led0_tick_per_service);
let led0 = LedService::new(ch32_hal::timer::Channel::Ch3, led0_service_data);
// LED1 servicer setup
let led1_blink_rate_hz = 3;
let led1_tick_per_service = (config.tick_rate_hz/(led1_blink_rate_hz * 2));
let led1_service_data = ServiceData::new(led1_tick_per_service);
let led1 = LedService::new(ch32_hal::timer::Channel::Ch1, led1_service_data);
// DAC servicer setup
let dac_sample_rate_hz = 16000;
let dac_tick_per_service = (config.tick_rate_hz/(dac_sample_rate_hz));
let dac_service_data = ServiceData::new(dac_tick_per_service);
let dac = DacService::new(ch32_hal::timer::Channel::Ch4, dac_service_data);
let data = include_bytes!("../../../../dpcm-encoder-decoder/sweep_dpcm_u4.raw");
dac.load_data(data);
Self {
config,
core: Default::default(),
pwm_core,
led0,
led1,
// led2,
dac,
// led1: Led {
// channel: hal::timer::Channel::Ch1,
// amplitude: 0,
// need_service: false,
// },
}
}
/// consumes self and runs
pub fn run(mut self) -> ! {
let mut delay = Delay;
let tick_interval_us = 1000000/self.config.tick_rate_hz;
let mut led0_index = 0;
let led0_dcs = [0u8, 25u8, 50u8, 75u8, 100u8, 75u8, 50u8, 25u8];
let mut led1_index = 0;
let led1_dcs = [0u8, 25u8, 50u8, 75u8, 100u8];
loop {
self.led0.tick();
self.led1.tick();
self.dac.tick();
if(self.led0.need_service()) {
self.led0.set_amplitude(led0_dcs[led0_index]);
self.pwm_core.write_amplitude(self.led0.channel, self.led0.amplitude);
led0_index += 1;
if led0_index > led0_dcs.len() - 1 {
led0_index = 0;
}
self.led0.service();
}
if(self.led1.need_service()) {
self.led1.set_amplitude(led1_dcs[led1_index]);
self.pwm_core.write_amplitude(self.led1.channel, self.led1.amplitude);
led1_index += 1;
if led1_index > led1_dcs.len() - 1 {
led1_index = 0;
}
self.led1.service();
}
if(self.dac.need_service()) {
self.dac.service();
// TODO: adpcm-pwm-dac:e4c811653781e69e40b63fd27a8c1e20
self.pwm_core.write_amplitude(self.dac.channel, self.dac.get_amplitude() as u8);
}
delay.delay_us(tick_interval_us as u32);
}
}
}

View file

@ -0,0 +1,5 @@
mod insert_coin;
mod services;
use services::LedService;
pub use insert_coin::{InsertCoin, CoreConfig, SimplePwmCore};

View file

@ -0,0 +1,51 @@
use crate::insert_coin::services::{ServiceData, Service};
use adpcm_pwm_dac::{dac::{DpcmDac, DpcmDecoder}, interface::DacInterface};
use ch32_hal::timer::Channel;
pub struct DacService<'a> {
service_data: core::cell::RefCell<ServiceData>,
dpcm_decoder: core::cell::RefCell<DpcmDecoder<'a>>,
amplitude: core::cell::RefCell<usize>,
pub channel: Channel,
}
impl<'a> DacService<'a> {
pub fn new(channel: Channel, service_data: ServiceData) -> Self {
Self {
service_data: core::cell::RefCell::new(service_data),
dpcm_decoder: core::cell::RefCell::new(DpcmDecoder::new()),
amplitude: core::cell::RefCell::new(0),
channel,
}
}
pub fn load_data(&self, data: &'a [u8]) {
self.dpcm_decoder.borrow_mut().load_data(data);
}
pub fn set_amplitude(&self, amplitude: usize) {
self.amplitude.replace(amplitude);
}
pub fn get_amplitude(&self) -> usize {
*self.amplitude.borrow()
}
}
impl<'a> Service for DacService<'a> {
fn tick(&self) {
let mut tc = self.service_data.borrow_mut();
tc.ticks_remaining = tc.ticks_remaining.saturating_sub(1);
}
fn need_service(&self) -> bool {
self.service_data.borrow().ticks_remaining == 0
}
fn service(&self) {
let mut tc = self.service_data.borrow_mut();
tc.ticks_remaining = tc.ticks_per_service;
self.set_amplitude(self.dpcm_decoder.borrow_mut().output_next());
}
}

View file

@ -0,0 +1,42 @@
use ch32_hal::timer::Channel;
use crate::insert_coin::services::{ServiceData, Service};
pub struct LedService {
service_data: core::cell::RefCell<ServiceData>,
pub channel: Channel,
pub amplitude: u8,
}
impl LedService {
pub fn new(channel: Channel, service_data: ServiceData) -> Self {
Self {
service_data: core::cell::RefCell::new(service_data),
channel,
amplitude: 0,
}
}
pub fn set_amplitude(&mut self, amplitude: u8) {
self.amplitude = amplitude;
}
}
impl Service for LedService {
fn tick(&self) {
let mut tc = self.service_data.borrow_mut();
tc.ticks_remaining = tc.ticks_remaining.saturating_sub(1);
}
fn need_service(&self) -> bool {
self.service_data.borrow().ticks_remaining == 0
}
fn service(&self) {
let mut tc = self.service_data.borrow_mut();
tc.ticks_remaining = tc.ticks_per_service;
}
}

View file

@ -0,0 +1,8 @@
mod services;
pub use services::{Service, ServiceData};
mod led;
pub use led::LedService;
mod dac;
pub use dac::DacService;

View file

@ -0,0 +1,25 @@
pub struct ServiceData {
pub ticks_per_service: usize,
pub ticks_remaining: usize,
}
impl ServiceData {
pub fn new(ticks_per_service: usize) -> Self {
Self {
ticks_per_service,
ticks_remaining: 0,
}
}
}
pub trait Service {
/// indicate to the service that a tick has occurred
fn tick(&self);
/// return true if service needs the service() routine run
fn need_service(&self) -> bool;
/// service routine - handle what needs to be done (non blocking) when
/// the service needs to be serviced here
fn service(&self);
}