diff --git a/pico/app/src/main.rs b/pico/app/src/main.rs index 42fa34e..f257e25 100644 --- a/pico/app/src/main.rs +++ b/pico/app/src/main.rs @@ -326,6 +326,9 @@ async fn main(spawner: Spawner) { urc::Urc::EnterPinReadResponse(v) => { info!("URC EnterPinReadResponse code={}", v.code); } + urc::Urc::TextToSpeechURC(v) => { + info!("URC TextToSpeechURC status={}", v.status); + } }, pubsub::WaitResult::Lagged(b) => { info!("Urc Lagged messages: {}", b); diff --git a/pico/pico-lib/src/call.rs b/pico/pico-lib/src/call.rs index c2a4d20..a95b603 100644 --- a/pico/pico-lib/src/call.rs +++ b/pico/pico-lib/src/call.rs @@ -9,6 +9,7 @@ use defmt::Format; use defmt::info; use crate::at::NoResponse; +use crate::hexstr::UCS2HexString; use crate::utils::send_command_logged; // 6.2.19 AT+CHFA Swap the Audio Channels @@ -155,6 +156,64 @@ pub enum MicrophoneBias { On = 1, } +// 17.2.1 AT+CTTS TTS Operation +#[derive(Clone, Debug, Format, AtatCmd)] +#[at_cmd("+CTTS", NoResponse)] +pub struct AtTextToSpeechOperationWrite { + pub mode: TextToSpeechOperationMode, + pub text: Option>, +} + +#[derive(Debug, Default, Format, Clone, PartialEq, AtatEnum)] +pub enum TextToSpeechOperationMode { + #[default] + StopPlaying = 0, // NoResponse + StartPlayUCS2 = 1, + StartPlayASCII = 2, + StartPlayASCIIAndGBK = 3, +} + +// +CTTS: +#[derive(Debug, Clone, AtatResp, PartialEq, Default)] +pub struct TextToSpeechURC { + pub status: TextToSpeechStatus, +} + +#[derive(Debug, Default, Format, Clone, PartialEq, AtatEnum)] +pub enum TextToSpeechStatus { + #[default] + Idle = 0, + Play = 1, +} + +// 17.2.2 AT+CTTSPARAM Set Parameters of the TTS Playing +// AT+CTTSPARAM=,,,,[] +#[derive(Clone, Debug, Format, AtatCmd)] +#[at_cmd("+CTTS", NoResponse)] +pub struct AtTextToSpeechParamWrite { + pub volume: u8, // 0-100, default 50 + pub mode: TextToSpeechMode, + pub pitch: u8, // 1-100, default 50 + pub speed: u8, // 1-100, default 50 + pub channel: Option, +} + +#[derive(Debug, Default, Format, Clone, PartialEq, AtatEnum)] +pub enum TextToSpeechMode { + #[default] + AutoReadDigitNumberRule = 0, + AutoReadDigitTelegramRule = 1, + ReadDigitTelegramRule = 2, + ReadDigitNumberRule = 3, +} + +#[derive(Debug, Default, Format, Clone, PartialEq, AtatEnum)] +pub enum TextToSpeechChannel { + #[default] + Main = 0, + Aux = 1, +} + pub async fn init( client: &mut T, _pico: &mut U, @@ -266,6 +325,48 @@ pub async fn hangup_incoming_call( + client: &mut T, + pico: &mut U, + message: &String<512>, + duration_millis: u64, +) { + send_command_logged( + client, + &AtTextToSpeechParamWrite { + volume: 80, + mode: TextToSpeechMode::AutoReadDigitNumberRule, + pitch: 50, + speed: 50, + channel: Some(TextToSpeechChannel::Main), + }, + "AtTextToSpeechParamWrite".to_string(), + ) + .await + .ok(); + + send_command_logged( + client, + &AtTextToSpeechOperationWrite { + mode: TextToSpeechOperationMode::StartPlayUCS2, + text: Some(UCS2HexString { + text: message.clone(), + quoted: true, + }), + }, + "AtTextToSpeechOperationWrite".to_string(), + ) + .await + .ok(); + + { + info!("Sleeping {} ms", duration_millis); + pico.sleep(duration_millis).await; + } + + // TODO: could wait for +CTTS: 0 +} + #[cfg(test)] mod tests { use crate::cmd_serialization_tests; @@ -323,6 +424,20 @@ mod tests { }, "AT+CMICBIAS=1\r", ), + test_at_text_to_speech_operation_stop: ( + AtTextToSpeechOperationWrite { + mode: TextToSpeechOperationMode::StopPlaying, + text: None, + }, + "AT+CTTS=0\r", + ), + test_at_text_to_speech_operation_play: ( + AtTextToSpeechOperationWrite { + mode: TextToSpeechOperationMode::StartPlayUCS2, + text: Some(UCS2HexString { text: String::try_from("Hello World!").unwrap(), quoted: true }), + }, + "AT+CTTS=1,\"00480065006C006C006F00200057006F0072006C00640021\"\r", + ), } #[test] diff --git a/pico/pico-lib/src/urc.rs b/pico/pico-lib/src/urc.rs index 3dc46f9..6ecd6d1 100644 --- a/pico/pico-lib/src/urc.rs +++ b/pico/pico-lib/src/urc.rs @@ -3,6 +3,7 @@ use atat::atat_derive::AtatUrc; use atat::heapless_bytes::Bytes; use crate::call::ClipUrc; +use crate::call::TextToSpeechURC; use crate::network::EnterPinReadResponse; use crate::sms::NewMessageIndicationUrc; @@ -56,4 +57,6 @@ pub enum Urc { ClipUrc(ClipUrc), #[at_urc("+CMTI")] NewMessageIndicationUrc(NewMessageIndicationUrc), + #[at_urc("+CTTS")] + TextToSpeechURC(TextToSpeechURC), }