use protobuf::Message;
use crate::{
AndroidAutoConfiguration, AndroidAutoFrame, AndroidAutoMainTrait, ChannelHandlerTrait,
ChannelId, StreamMux, Wifi, common::AndroidAutoCommonMessage,
};
#[derive(Debug)]
enum NavigationMessage {
Status(ChannelId, Wifi::NavigationStatus),
TurnIndication(ChannelId, Wifi::NavigationTurnEvent),
DistanceIndication(ChannelId, Wifi::NavigationDistanceEvent),
}
impl From<NavigationMessage> for AndroidAutoFrame {
fn from(value: NavigationMessage) -> Self {
match value {
NavigationMessage::Status(_, _) => unimplemented!(),
NavigationMessage::DistanceIndication(_, _) => unimplemented!(),
NavigationMessage::TurnIndication(_, _) => unimplemented!(),
}
}
}
impl TryFrom<&AndroidAutoFrame> for NavigationMessage {
type Error = String;
fn try_from(value: &AndroidAutoFrame) -> Result<Self, Self::Error> {
use protobuf::Enum;
let mut ty = [0u8; 2];
ty.copy_from_slice(&value.data[0..2]);
let ty = u16::from_be_bytes(ty);
if let Some(sys) = Wifi::navigation_channel_message::Enum::from_i32(ty as i32) {
match sys {
Wifi::navigation_channel_message::Enum::STATUS => {
let m = Wifi::NavigationStatus::parse_from_bytes(&value.data[2..]);
match m {
Ok(m) => Ok(Self::Status(value.header.channel_id, m)),
Err(e) => Err(format!("Invalid frame: {}", e)),
}
}
Wifi::navigation_channel_message::Enum::NONE => unimplemented!(),
Wifi::navigation_channel_message::Enum::TURN_EVENT => {
let m = Wifi::NavigationTurnEvent::parse_from_bytes(&value.data[2..]);
match m {
Ok(m) => Ok(Self::TurnIndication(value.header.channel_id, m)),
Err(e) => Err(format!("Invalid frame: {}", e)),
}
}
Wifi::navigation_channel_message::Enum::DISTANCE_EVENT => {
let m = Wifi::NavigationDistanceEvent::parse_from_bytes(&value.data[2..]);
match m {
Ok(m) => Ok(Self::DistanceIndication(value.header.channel_id, m)),
Err(e) => Err(format!("Invalid frame: {}", e)),
}
}
}
} else {
Err(format!("Not converted message: {:x?}", value.data))
}
}
}
pub struct NavigationChannelHandler {}
impl ChannelHandlerTrait for NavigationChannelHandler {
fn build_channel<T: AndroidAutoMainTrait + ?Sized>(
&self,
_config: &AndroidAutoConfiguration,
chanid: ChannelId,
_main: &T,
) -> Option<Wifi::ChannelDescriptor> {
let mut chan = Wifi::ChannelDescriptor::new();
let mut navchan = Wifi::NavigationChannel::new();
navchan.set_minimum_interval_ms(1000);
navchan.set_type(Wifi::navigation_turn_type::Enum::IMAGE);
let mut io = Wifi::NavigationImageOptions::new();
io.set_colour_depth_bits(16);
io.set_dunno(255);
io.set_height(256);
io.set_width(256);
navchan.image_options.0.replace(Box::new(io));
chan.set_channel_id(chanid as u32);
chan.navigation_channel.0.replace(Box::new(navchan));
if !chan.is_initialized() {
panic!("Channel not initialized?");
}
Some(chan)
}
async fn receive_data<T: AndroidAutoMainTrait + ?Sized>(
&self,
msg: AndroidAutoFrame,
stream: &crate::WriteHalf,
_config: &AndroidAutoConfiguration,
main: &T,
) -> Result<(), super::FrameIoError> {
let channel = msg.header.channel_id;
let msg1: Result<NavigationMessage, String> = (&msg).try_into();
if let Ok(msg) = msg1 {
match msg {
NavigationMessage::Status(_, status) => {
if let Some(n) = main.supports_navigation() {
n.nagivation_status(status).await;
}
}
NavigationMessage::TurnIndication(_, turn) => {
if let Some(n) = main.supports_navigation() {
n.turn_indication(turn).await;
}
}
NavigationMessage::DistanceIndication(_, distance) => {
if let Some(n) = main.supports_navigation() {
n.distance_indication(distance).await;
}
}
}
}
let msg2: Result<AndroidAutoCommonMessage, String> = (&msg).try_into();
if let Ok(msg2) = msg2 {
match msg2 {
AndroidAutoCommonMessage::ChannelOpenResponse(_, _) => unimplemented!(),
AndroidAutoCommonMessage::ChannelOpenRequest(_m) => {
let mut m2 = Wifi::ChannelOpenResponse::new();
m2.set_status(Wifi::status::Enum::OK);
stream
.write_frame(
AndroidAutoCommonMessage::ChannelOpenResponse(channel, m2).into(),
)
.await?;
}
}
return Ok(());
}
todo!("{:x?}", msg);
}
}