use core::{
cell::UnsafeCell,
error::Error,
fmt::{self, Debug, Display},
marker::PhantomData,
};
use gdbstub::conn::{Connection, ConnectionExt};
use vex_sdk::vexTasksRun;
use crate::sdk::serial::{self, Channel};
#[cfg(target_arch = "arm")]
pub mod mux;
#[derive(Debug)]
pub struct TransportError(pub &'static str);
impl Display for TransportError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Error for TransportError {}
impl From<&'static str> for TransportError {
fn from(value: &'static str) -> Self {
Self(value)
}
}
pub unsafe trait Transport:
ConnectionExt + Connection<Error = TransportError> + Send + 'static
{
fn try_read(&mut self) -> Result<Option<u8>, Self::Error> {
if self.peek()?.is_some() {
self.read().map(Some)
} else {
Ok(None)
}
}
}
#[derive(Debug)]
#[non_exhaustive]
pub struct StdioTransport {
_unsync: PhantomData<UnsafeCell<()>>,
}
unsafe impl Transport for StdioTransport {
fn try_read(&mut self) -> Result<Option<u8>, Self::Error> {
Ok(serial::read_byte(Channel::USER))
}
}
impl StdioTransport {
pub const fn new() -> Self {
Self {
_unsync: PhantomData,
}
}
}
impl Default for StdioTransport {
fn default() -> Self {
Self::new()
}
}
impl Connection for StdioTransport {
type Error = TransportError;
fn write(&mut self, byte: u8) -> Result<(), Self::Error> {
#[cfg(target_arch = "arm")]
mux::write_all(mux::ChannelId::Debug, &[byte]);
Ok(())
}
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
#[cfg(target_arch = "arm")]
mux::write_all(mux::ChannelId::Debug, buf);
Ok(())
}
fn flush(&mut self) -> Result<(), Self::Error> {
#[cfg(target_arch = "arm")]
mux::flush_serial();
Ok(())
}
fn on_session_start(&mut self) -> Result<(), Self::Error> {
#[cfg(target_arch = "arm")]
mux::enable_auto_muxing();
Ok(())
}
}
impl ConnectionExt for StdioTransport {
fn peek(&mut self) -> Result<Option<u8>, Self::Error> {
Ok(serial::peek_byte(Channel::USER))
}
fn read(&mut self) -> Result<u8, Self::Error> {
loop {
if let Some(byte) = serial::read_byte(Channel::USER) {
return Ok(byte);
}
unsafe {
vexTasksRun();
}
}
}
}