door/outside/src/music.rs

183 lines
5.6 KiB
Rust

use common::Name;
use embassy_rp::clocks::RoscRng;
use embassy_rp::uart;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel;
use embassy_time::Timer;
use embedded_io_async::Read;
use embedded_io_async::Write;
use rand::RngCore;
use serde::Deserialize;
use serde::Serialize;
use crate::server::NAMES;
use crate::wiggle::WAGS;
use crate::Irqs;
use embassy_rp::uart::BufferedUart;
use embassy_rp::peripherals::PIN_21;
use embassy_rp::peripherals::PIN_20;
use embassy_rp::peripherals::UART1;
use log::*;
pub static COMMANDS: Channel<CriticalSectionRawMutex, MusicCommand, 3> = Channel::new();
pub trait Tracks {
fn tracks(&self) -> u8;
fn prefix(&self) -> &'static str;
}
impl Tracks for Name {
fn tracks(&self) -> u8 {
match self {
Name::Andy => 7,
Name::Evan => 7,
Name::Felix => 12,
Name::Phil => 6,
Name::Tess => 4,
Name::Amaia => 5,
Name::Prueky => 1,
Name::David => 2,
Name::Nathaniel => 1,
Name::Thia => 7,
Name::Michael => 0,
Name::Zoey => 1,
Name::Coke => todo!(),
Name::Unknown => 0,
}
}
fn prefix(&self) -> &'static str {
match self {
Name::Andy => "andy",
Name::Evan => "evan",
Name::Felix => "felix",
Name::Phil => "phil",
Name::Tess => "tess",
Name::Amaia => "amaia",
Name::Prueky => "prueky",
Name::David => "david",
Name::Nathaniel => "nathaniel1",
Name::Thia => "thia",
Name::Michael => "michael",
Name::Zoey => "zoey",
Name::Coke => "button",
Name::Unknown => "",
}
}
}
static ACCEPTED_SUFFIXABLE: [bool; 6] = [false, false, false, false, false, true];
static DENIED_SUFFIXABLE: [bool; 6] = [false, false, false, false, false, true];
pub enum MusicCommand {
/// play a random clip for name, accepted if true
Introduce(Name, bool),
/// 0-30
SetVolume(u8),
Play(&'static str),
}
#[embassy_executor::task]
pub async fn music_manager(uart: UART1, irqs: Irqs, txp: PIN_20, rxp: PIN_21) -> ! {
let mut config = uart::Config::default();
config.baudrate = 115200;
let mut rx = [0; 2048];
let mut tx = [0; 2048];
let mut uart = BufferedUart::new(uart, irqs, txp, rxp, &mut tx, &mut rx, config);
let mut rng = RoscRng;
loop {
let command = COMMANDS.receive().await;
match command {
MusicCommand::Introduce(name, accepted) => {
let call: bool;
if accepted {
let index = rng.next_u32() % ACCEPTED_SUFFIXABLE.len() as u32;
play_song("a", Some((index+1) as u8), &mut uart).await;
call = ACCEPTED_SUFFIXABLE[index as usize];
} else {
let index = rng.next_u32() % DENIED_SUFFIXABLE.len() as u32;
play_song("d", Some((index+1) as u8), &mut uart).await;
call = DENIED_SUFFIXABLE[index as usize];
}
if call {
match name.tracks() {
0 => {},
1 => {
play_song(&name.prefix(), None, &mut uart).await;
},
tracks => {
let index = rng.next_u32() % tracks as u32;
play_song(&name.prefix(), Some((index+1) as u8), &mut uart).await;
}
}
}
},
MusicCommand::Play(song) => {
play_song(song, None, &mut uart).await
},
MusicCommand::SetVolume(vol) => {
uart.write_all(b"AT+VOL=").await.unwrap();
uart.write_all(itoa::Buffer::new().format(vol).as_bytes()).await.unwrap();
uart.write_all(b"\r\n").await.unwrap();
let mut buffer = [0;512];
info!("set volume to {vol}, returned: {}",read_line(&mut buffer, &mut uart).await.trim());
},
}
}
}
async fn play_song<'a>(prefix: &str, index: Option<u8>, uart: &mut BufferedUart<'a, UART1>) {
info!("playing: {}{}.mp3",prefix,index.unwrap_or(0));
uart.write_all(b"AT+PLAYFILE=/").await.unwrap();
uart.write_all(prefix.as_bytes()).await.unwrap();
if let Some(index) = index {
uart.write_all(itoa::Buffer::new().format(index).as_bytes()).await.unwrap();
}
uart.write_all(b".mp3\r\n").await.unwrap();
let mut buffer = [0;512];
info!("returned: {}",read_line(&mut buffer, uart).await.trim());
uart.write_all(b"AT+QUERY=4\r\n").await.unwrap();
let mut buffer = [0;512];
let output = read_line(&mut buffer, uart).await;
if let Ok(length) = output.trim().parse::<u64>() {
WAGS.store((length as u8) * 2 + 1, core::sync::atomic::Ordering::SeqCst);
Timer::after_secs(length).await;
}
}
async fn read_line<'a, 'b>(buffer: &'b mut [u8], uart: &mut BufferedUart<'a, UART1>) -> &'b str {
let mut pos = 0;
loop {
if let Ok(len) = uart.read(&mut buffer[pos..]).await {
let to_print = unsafe { core::str::from_utf8_unchecked(&buffer[..(pos + len)]) };
if to_print.contains("\r\n") {
//info!("{}", to_print);
pos += len;
break;
}
pos += len;
} else {
break;
}
}
return unsafe { core::str::from_utf8_unchecked(&buffer[..(pos)]) };
}