4
0

legacy_stdio.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. //! 这个模块的两个宏应该公开
  2. //! 如果制造实例的时候,给定了stdout,那么就会打印到这个stdout里面
  3. use embedded_hal::serial::{Read, Write};
  4. use nb::block;
  5. /// Legacy standard input/output
  6. pub trait LegacyStdio: Send {
  7. /// Get a character from legacy stdin
  8. fn getchar(&mut self) -> u8;
  9. /// Put a character into legacy stdout
  10. fn putchar(&mut self, ch: u8);
  11. }
  12. /// Use serial in `embedded-hal` as legacy standard input/output
  13. struct EmbeddedHalSerial<T> {
  14. inner: T,
  15. }
  16. impl<T> EmbeddedHalSerial<T> {
  17. /// Create a wrapper with a value
  18. fn new(inner: T) -> Self {
  19. Self { inner }
  20. }
  21. }
  22. impl<T: Send> LegacyStdio for EmbeddedHalSerial<T>
  23. where
  24. T: Read<u8> + Write<u8>,
  25. {
  26. fn getchar(&mut self) -> u8 {
  27. // 直接调用embedded-hal里面的函数
  28. // 关于unwrap:因为这个是legacy函数,这里没有详细的处理流程,就panic掉
  29. block!(self.inner.try_read()).ok().unwrap()
  30. }
  31. fn putchar(&mut self, ch: u8) {
  32. // 直接调用函数写一个字节
  33. block!(self.inner.try_write(ch)).ok();
  34. // 写一次flush一次,因为是legacy,就不考虑效率了
  35. block!(self.inner.try_flush()).ok();
  36. }
  37. }
  38. struct Fused<T, R>(T, R);
  39. // 和上面的原理差不多,就是分开了
  40. impl<T, R> LegacyStdio for Fused<T, R>
  41. where
  42. T: Write<u8> + Send + 'static,
  43. R: Read<u8> + Send + 'static,
  44. {
  45. fn getchar(&mut self) -> u8 {
  46. block!(self.1.try_read()).ok().unwrap()
  47. }
  48. fn putchar(&mut self, ch: u8) {
  49. block!(self.0.try_write(ch)).ok();
  50. block!(self.0.try_flush()).ok();
  51. }
  52. }
  53. use alloc::boxed::Box;
  54. use spin::Mutex;
  55. lazy_static::lazy_static! {
  56. static ref LEGACY_STDIO: Mutex<Option<Box<dyn LegacyStdio>>> =
  57. Mutex::new(None);
  58. }
  59. #[doc(hidden)] // use through a macro
  60. pub fn init_legacy_stdio_embedded_hal<T: Read<u8> + Write<u8> + Send + 'static>(serial: T) {
  61. let serial = EmbeddedHalSerial::new(serial);
  62. *LEGACY_STDIO.lock() = Some(Box::new(serial));
  63. }
  64. #[doc(hidden)] // use through a macro
  65. pub fn init_legacy_stdio_embedded_hal_fuse<T, R>(tx: T, rx: R)
  66. where
  67. T: Write<u8> + Send + 'static,
  68. R: Read<u8> + Send + 'static,
  69. {
  70. let serial = Fused(tx, rx);
  71. *LEGACY_STDIO.lock() = Some(Box::new(serial));
  72. }
  73. pub fn legacy_stdio_putchar(ch: u8) {
  74. if let Some(stdio) = LEGACY_STDIO.lock().as_mut() {
  75. stdio.putchar(ch)
  76. }
  77. }
  78. pub fn legacy_stdio_getchar() -> u8 {
  79. if let Some(stdio) = LEGACY_STDIO.lock().as_mut() {
  80. stdio.getchar()
  81. } else {
  82. 0 // default: always return 0
  83. }
  84. }
  85. use core::fmt;
  86. struct Stdout;
  87. impl fmt::Write for Stdout {
  88. fn write_str(&mut self, s: &str) -> fmt::Result {
  89. if let Some(stdio) = LEGACY_STDIO.lock().as_mut() {
  90. for byte in s.as_bytes() {
  91. stdio.putchar(*byte)
  92. }
  93. }
  94. Ok(())
  95. }
  96. }
  97. #[doc(hidden)]
  98. pub fn _print(args: fmt::Arguments) {
  99. use fmt::Write;
  100. Stdout.write_fmt(args).unwrap();
  101. }
  102. /// Prints to the legacy debug console.
  103. ///
  104. /// This is only supported when there exists legacy extension;
  105. /// otherwise platform caller should use an early kernel input/output device
  106. /// declared in platform specific hardware.
  107. #[macro_export(local_inner_macros)]
  108. macro_rules! print {
  109. ($($arg:tt)*) => ({
  110. $crate::legacy_stdio::_print(core::format_args!($($arg)*));
  111. });
  112. }
  113. /// Prints to the legacy debug console, with a newline.
  114. ///
  115. /// This is only supported when there exists legacy extension;
  116. /// otherwise platform caller should use an early kernel input/output device
  117. /// declared in platform specific hardware.
  118. #[macro_export(local_inner_macros)]
  119. macro_rules! println {
  120. ($fmt: literal $(, $($arg: tt)+)?) => {
  121. $crate::legacy_stdio::_print(core::format_args!(core::concat!($fmt, "\n") $(, $($arg)+)?));
  122. }
  123. }