1#![cfg_attr(
2 feature = "doc-images",
3 doc = ::embed_doc_image::embed_image!(
4 "linkage_blaze_gallery",
5 "docs/assets/linkage_blaze_gallery.png"
6 )
7)]
8#![cfg_attr(
22 feature = "doc-images",
23 doc = "\n[![Linkage Blaze gallery showing CYD applications][linkage_blaze_gallery]][interactive Linkage Blaze gallery]\n"
24)]
25mod buffer;
69mod display;
70mod one_spi;
71mod text;
72#[path = "cyd/touch.rs"]
73mod touch_driver;
74
75use core::{convert::Infallible, fmt};
76
77use embedded_graphics::{
78 Pixel,
79 mono_font::MonoFont,
80 pixelcolor::{IntoStorage, Rgb565, Rgb888},
81 prelude::{Dimensions, DrawTarget, OriginDimensions, Point, Size},
82 primitives::Rectangle,
83};
84use embedded_hal::spi::SpiDevice;
85use static_cell::StaticCell;
86
87use buffer::DynPixelBuffer;
88use buffer::{PixelBuffer, RegionView};
89use device_envoy_core::button::Button;
90use device_envoy_core::cyd::backend;
91use device_envoy_core::cyd::{
92 SCREEN_PIXELS,
93 backend::{CalibrationConfig, RawTouchEvent, TouchUncalibrated},
94 display::CydFrame,
95 touch::TouchEvent,
96};
97use device_envoy_core::pixel_target::PixelTarget;
98pub use display::DEFAULT_DISPLAY_SPI_HZ;
99pub use device_envoy_core::cyd::{
102 Cyd, CydDisplay, CydTouch,
103 display::{Orientation, tiling},
104 touch,
105};
106pub use one_spi::CydEspOneSpi;
107pub use text::DEFAULT_FONT;
108use touch_driver::TOUCH_SPI_HZ;
109
110use crate::flash_block::FlashBlockEsp;
111use display::CydDisplayEsp as CydDisplayEspDevice;
112use touch_driver::CydTouchEsp as CydTouchEspDevice;
113
114pub struct CydDisplayEsp<D: SpiDevice<u8> = display::CydDisplaySpiDevice> {
125 display: CydDisplayEspDevice<D>,
126 orientation: Orientation,
127 pixel_buffer: &'static mut dyn DynPixelBuffer,
130 background_color: Rgb888,
135 foreground_color: Rgb888,
136 background565: Rgb565,
137 foreground565: Rgb565,
138 font: &'static MonoFont<'static>,
139}
140
141pub(crate) struct CydTouchUncalibratedEsp<D = touch_driver::CydTouchSpiDevice> {
146 touch: CydTouchEspDevice<D>,
147}
148
149pub struct CydTouchEsp<D = touch_driver::CydTouchSpiDevice> {
155 raw: CydTouchUncalibratedEsp<D>,
156 calibration_config: CalibrationConfig,
157 orientation: Orientation,
158}
159
160pub struct CydEsp {
167 pub display: CydDisplayEsp,
169 pub touch: CydTouchEsp,
171}
172
173pub(crate) struct CydEspUncalibrated {
175 pub display: CydDisplayEsp,
177 pub touch: CydTouchUncalibratedEsp,
179}
180
181pub struct CydStaticEsp<const PIXEL_COUNT: usize> {
196 pixel_buffer: StaticCell<PixelBuffer<PIXEL_COUNT>>,
197}
198
199impl<const PIXEL_COUNT: usize> CydStaticEsp<PIXEL_COUNT> {
200 pub(crate) const fn new() -> Self {
203 assert!(
204 PIXEL_COUNT <= SCREEN_PIXELS,
205 "PIXEL_COUNT must not exceed SCREEN_PIXELS"
206 );
207 Self {
208 pixel_buffer: StaticCell::new(),
209 }
210 }
211}
212
213pub struct CydFrameEsp<'a, D: SpiDevice<u8> = display::CydDisplaySpiDevice> {
220 display: &'a mut CydDisplayEspDevice<D>,
221 view: RegionView<'a>,
222 rectangle: Rectangle,
225 pub(crate) background565: Rgb565,
228 pub(crate) foreground565: Rgb565,
229 pub(crate) font: &'static MonoFont<'static>,
230}
231
232impl<'a, D: SpiDevice<u8>> CydFrameEsp<'a, D> {
233 pub fn fill(&mut self, color: Rgb565) -> &mut Self {
239 self.view.fill(color);
240 self
241 }
242
243 #[must_use]
245 pub fn width(&self) -> usize {
246 self.view.width()
247 }
248
249 #[must_use]
251 pub fn height(&self) -> usize {
252 self.view.height()
253 }
254
255 pub fn raw_pixels_mut(&mut self) -> &mut [u16] {
257 self.view.raw_pixels_mut()
258 }
259
260 pub fn flush(&mut self) -> Result<(), Error> {
268 Ok(self.display.flush_buffer(
269 self.view.size().width as usize,
270 self.view.size().height as usize,
271 self.view.raw_pixels(),
272 self.rectangle.top_left,
273 )?)
274 }
275
276 fn local_x(&self, x: i32) -> Option<usize> {
277 usize::try_from(x.checked_sub(self.rectangle.top_left.x)?).ok()
278 }
279
280 fn local_y(&self, y: i32) -> Option<usize> {
281 usize::try_from(y.checked_sub(self.rectangle.top_left.y)?).ok()
282 }
283}
284
285impl<D: SpiDevice<u8>> DrawTarget for CydFrameEsp<'_, D> {
286 type Color = Rgb565;
287 type Error = Infallible;
288
289 fn clear(&mut self, color: Self::Color) -> Result<(), Self::Error> {
290 self.fill(color);
291 Ok(())
292 }
293
294 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
295 where
296 I: IntoIterator<Item = Pixel<Self::Color>>,
297 {
298 for Pixel(point, color) in pixels {
299 let Some(local_x) = self.local_x(point.x) else {
300 continue;
301 };
302 let Some(local_y) = self.local_y(point.y) else {
303 continue;
304 };
305 if local_x < self.view.width() && local_y < self.view.height() {
306 let index = local_y * self.view.width() + local_x;
307 self.raw_pixels_mut()[index] = color.into_storage();
308 }
309 }
310 Ok(())
311 }
312}
313
314impl<D: SpiDevice<u8>> Dimensions for CydFrameEsp<'_, D> {
315 fn bounding_box(&self) -> Rectangle {
316 self.rectangle
317 }
318}
319
320impl<D: SpiDevice<u8>> PixelTarget for CydFrameEsp<'_, D> {
321 fn width(&self) -> usize {
322 usize::try_from(self.rectangle.top_left.x)
323 .expect("frame top-left x must be non-negative")
324 .checked_add(self.width())
325 .expect("frame width must fit in usize")
326 }
327
328 fn height(&self) -> usize {
329 usize::try_from(self.rectangle.top_left.y)
330 .expect("frame top-left y must be non-negative")
331 .checked_add(self.height())
332 .expect("frame height must fit in usize")
333 }
334
335 fn put_pixel(&mut self, x: usize, y: usize, color: Rgb888) {
336 let Some(local_x) = self.local_x(x as i32) else {
337 return;
338 };
339 let Some(local_y) = self.local_y(y as i32) else {
340 return;
341 };
342 if local_x >= self.view.width() || local_y >= self.view.height() {
343 return;
344 }
345 let stride = self.view.width();
346 self.raw_pixels_mut()[local_y * stride + local_x] = Rgb565::from(color).into_storage();
347 }
348
349 fn put_pixel_565(&mut self, x: usize, y: usize, rgb565: u16) {
352 let Some(local_x) = self.local_x(x as i32) else {
353 return;
354 };
355 let Some(local_y) = self.local_y(y as i32) else {
356 return;
357 };
358 if local_x >= self.view.width() || local_y >= self.view.height() {
359 return;
360 }
361 let stride = self.view.width();
362 self.raw_pixels_mut()[local_y * stride + local_x] = rgb565;
363 }
364}
365
366#[derive(Debug)]
391pub enum Error {
392 ConfigureDisplaySpi(esp_hal::spi::master::ConfigError),
395 InitDisplay,
398 ConfigureTouchSpi(esp_hal::spi::master::ConfigError),
401 FlushFrameBuffer,
404 SetOrientation,
407}
408
409impl<D: SpiDevice<u8>> CydDisplayEsp<D> {
410 fn set_orientation(&mut self, orientation: Orientation) -> Result<(), Error> {
411 self.display.set_orientation(orientation)?;
412 self.orientation = orientation;
413 Ok(())
414 }
415
416 fn from_display_device(
417 mut display: CydDisplayEspDevice<D>,
418 orientation: Orientation,
419 background_color: Rgb888,
420 foreground_color: Rgb888,
421 font: &'static MonoFont<'static>,
422 pixel_buffer: &'static mut dyn DynPixelBuffer,
423 ) -> Result<Self, Error> {
424 let background565 = rgb565(background_color);
425 display.fill(background565)?;
426
427 Ok(Self {
428 display,
429 orientation,
430 pixel_buffer,
431 background_color,
432 foreground_color,
433 background565,
434 foreground565: rgb565(foreground_color),
435 font,
436 })
437 }
438
439 pub(crate) fn new_from_device(
444 spi_device: D,
445 dc_pin: impl esp_hal::gpio::OutputPin + 'static,
446 rst_pin: impl esp_hal::gpio::OutputPin + 'static,
447 backlight_pin: impl esp_hal::gpio::OutputPin + 'static,
448 orientation: Orientation,
449 background_color: Rgb888,
450 foreground_color: Rgb888,
451 font: &'static MonoFont<'static>,
452 pixel_buffer: &'static mut dyn DynPixelBuffer,
453 ) -> Result<Self, Error> {
454 let display = CydDisplayEspDevice::new_from_device(
455 spi_device,
456 dc_pin,
457 rst_pin,
458 backlight_pin,
459 orientation,
460 )?;
461 Self::from_display_device(
462 display,
463 orientation,
464 background_color,
465 foreground_color,
466 font,
467 pixel_buffer,
468 )
469 }
470}
471
472impl CydDisplayEsp<display::CydDisplaySpiDevice> {
473 pub fn new<const PIXEL_COUNT: usize>(
496 statics: &'static CydStaticEsp<PIXEL_COUNT>,
497 display_spi: impl esp_hal::spi::master::Instance + 'static,
498 display_sck_pin: impl esp_hal::gpio::interconnect::PeripheralOutput<'static>,
499 display_mosi_pin: impl esp_hal::gpio::interconnect::PeripheralOutput<'static>,
500 display_miso_pin: impl esp_hal::gpio::interconnect::PeripheralInput<'static>,
501 display_cs_pin: impl esp_hal::gpio::OutputPin + 'static,
502 display_dc_pin: impl esp_hal::gpio::OutputPin + 'static,
503 display_rst_pin: impl esp_hal::gpio::OutputPin + 'static,
504 display_backlight_pin: impl esp_hal::gpio::OutputPin + 'static,
505 display_spi_hz: u32,
506 orientation: Orientation,
507 background_color: Rgb888,
508 foreground_color: Rgb888,
509 font: &'static MonoFont<'static>,
510 ) -> Result<Self, Error> {
511 let pixel_buffer = PixelBuffer::init_static(&statics.pixel_buffer);
512 let display = CydDisplayEspDevice::new(
513 display_spi,
514 display_sck_pin,
515 display_mosi_pin,
516 display_miso_pin,
517 display_cs_pin,
518 display_dc_pin,
519 display_rst_pin,
520 display_backlight_pin,
521 display_spi_hz,
522 orientation,
523 )?;
524 Self::from_display_device(
525 display,
526 orientation,
527 background_color,
528 foreground_color,
529 font,
530 pixel_buffer,
531 )
532 }
533}
534
535impl<D: SpiDevice<u8>> CydTouchUncalibratedEsp<D> {
536 pub(crate) fn from_device(
541 touch_spi_device: D,
542 touch_irq_pin: impl esp_hal::gpio::InputPin + 'static,
543 ) -> Self {
544 Self {
545 touch: CydTouchEspDevice::from_device(touch_spi_device, touch_irq_pin),
546 }
547 }
548}
549
550impl CydTouchUncalibratedEsp<touch_driver::CydTouchSpiDevice> {
551 pub(crate) fn new(
553 touch_spi: impl esp_hal::spi::master::Instance + 'static,
554 touch_sck_pin: impl esp_hal::gpio::interconnect::PeripheralOutput<'static>,
555 touch_mosi_pin: impl esp_hal::gpio::interconnect::PeripheralOutput<'static>,
556 touch_miso_pin: impl esp_hal::gpio::interconnect::PeripheralInput<'static>,
557 touch_cs_pin: impl esp_hal::gpio::OutputPin + 'static,
558 touch_irq_pin: impl esp_hal::gpio::InputPin + 'static,
559 ) -> Result<Self, Error> {
560 Ok(Self {
561 touch: CydTouchEspDevice::new(
562 touch_spi,
563 touch_sck_pin,
564 touch_mosi_pin,
565 touch_miso_pin,
566 touch_cs_pin,
567 touch_irq_pin,
568 )?,
569 })
570 }
571}
572
573impl CydEsp {
574 pub const SCREEN_PIXELS: usize = SCREEN_PIXELS;
578
579 #[must_use]
597 pub const fn new_static<const PIXEL_COUNT: usize>() -> CydStaticEsp<PIXEL_COUNT> {
598 CydStaticEsp::new()
599 }
600
601 pub async fn new<const PIXEL_COUNT: usize, R: Button>(
669 statics: &'static CydStaticEsp<PIXEL_COUNT>,
670 display_spi: impl esp_hal::spi::master::Instance + 'static,
671 display_sck_pin: impl esp_hal::gpio::interconnect::PeripheralOutput<'static>,
672 display_mosi_pin: impl esp_hal::gpio::interconnect::PeripheralOutput<'static>,
673 display_miso_pin: impl esp_hal::gpio::interconnect::PeripheralInput<'static>,
674 display_cs_pin: impl esp_hal::gpio::OutputPin + 'static,
675 display_dc_pin: impl esp_hal::gpio::OutputPin + 'static,
676 display_rst_pin: impl esp_hal::gpio::OutputPin + 'static,
677 display_backlight_pin: impl esp_hal::gpio::OutputPin + 'static,
678 display_spi_hz: u32,
679 orientation: Orientation,
680 background_color: Rgb888,
681 foreground_color: Rgb888,
682 font: &'static MonoFont<'static>,
683 touch_spi: impl esp_hal::spi::master::Instance + 'static,
684 touch_sck_pin: impl esp_hal::gpio::interconnect::PeripheralOutput<'static>,
685 touch_mosi_pin: impl esp_hal::gpio::interconnect::PeripheralOutput<'static>,
686 touch_miso_pin: impl esp_hal::gpio::interconnect::PeripheralInput<'static>,
687 touch_cs_pin: impl esp_hal::gpio::OutputPin + 'static,
688 touch_irq_pin: impl esp_hal::gpio::InputPin + 'static,
689 calibration_flash_block: &mut FlashBlockEsp,
690 recalibration_button: &mut R,
691 ) -> crate::Result<Self> {
692 let CydEspUncalibrated { mut display, touch } = CydEspUncalibrated::new(
693 statics,
694 display_spi,
695 display_sck_pin,
696 display_mosi_pin,
697 display_miso_pin,
698 display_cs_pin,
699 display_dc_pin,
700 display_rst_pin,
701 display_backlight_pin,
702 display_spi_hz,
703 orientation,
704 background_color,
705 foreground_color,
706 font,
707 touch_spi,
708 touch_sck_pin,
709 touch_mosi_pin,
710 touch_miso_pin,
711 touch_cs_pin,
712 touch_irq_pin,
713 )?;
714 let touch = backend::ensure_calibration(
715 &mut display,
716 touch,
717 calibration_flash_block,
718 recalibration_button,
719 None,
720 orientation,
721 )
722 .await
723 .map_err(|error| match error {
724 backend::Error::Device(cyd_error) => crate::Error::from(cyd_error),
725 backend::Error::Flash(flash_error) => flash_error,
726 })?;
727 display.set_orientation(orientation)?;
728 Ok(Self { display, touch })
729 }
730}
731
732impl Cyd for CydEsp {
733 type Error = Error;
734 type Display = CydDisplayEsp;
735 type Touch = CydTouchEsp;
736
737 fn parts(&mut self) -> (&mut Self::Display, &mut Self::Touch) {
738 (&mut self.display, &mut self.touch)
739 }
740
741 fn orientation(&self) -> Orientation {
742 self.display.orientation
743 }
744}
745
746impl CydEspUncalibrated {
747 pub(crate) fn new<const PIXEL_COUNT: usize>(
748 statics: &'static CydStaticEsp<PIXEL_COUNT>,
749 display_spi: impl esp_hal::spi::master::Instance + 'static,
750 display_sck_pin: impl esp_hal::gpio::interconnect::PeripheralOutput<'static>,
751 display_mosi_pin: impl esp_hal::gpio::interconnect::PeripheralOutput<'static>,
752 display_miso_pin: impl esp_hal::gpio::interconnect::PeripheralInput<'static>,
753 display_cs_pin: impl esp_hal::gpio::OutputPin + 'static,
754 display_dc_pin: impl esp_hal::gpio::OutputPin + 'static,
755 display_rst_pin: impl esp_hal::gpio::OutputPin + 'static,
756 display_backlight_pin: impl esp_hal::gpio::OutputPin + 'static,
757 display_spi_hz: u32,
758 _orientation: Orientation,
759 background_color: Rgb888,
760 foreground_color: Rgb888,
761 font: &'static MonoFont<'static>,
762 touch_spi: impl esp_hal::spi::master::Instance + 'static,
763 touch_sck_pin: impl esp_hal::gpio::interconnect::PeripheralOutput<'static>,
764 touch_mosi_pin: impl esp_hal::gpio::interconnect::PeripheralOutput<'static>,
765 touch_miso_pin: impl esp_hal::gpio::interconnect::PeripheralInput<'static>,
766 touch_cs_pin: impl esp_hal::gpio::OutputPin + 'static,
767 touch_irq_pin: impl esp_hal::gpio::InputPin + 'static,
768 ) -> Result<Self, Error> {
769 Ok(Self {
770 display: CydDisplayEsp::new(
771 statics,
772 display_spi,
773 display_sck_pin,
774 display_mosi_pin,
775 display_miso_pin,
776 display_cs_pin,
777 display_dc_pin,
778 display_rst_pin,
779 display_backlight_pin,
780 display_spi_hz,
781 Orientation::Landscape,
782 background_color,
783 foreground_color,
784 font,
785 )?,
786 touch: CydTouchUncalibratedEsp::new(
787 touch_spi,
788 touch_sck_pin,
789 touch_mosi_pin,
790 touch_miso_pin,
791 touch_cs_pin,
792 touch_irq_pin,
793 )?,
794 })
795 }
796}
797
798fn rgb565(color: Rgb888) -> Rgb565 {
799 Rgb565::from(color)
800}
801
802impl<D: SpiDevice<u8>> fmt::Debug for CydDisplayEsp<D> {
803 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
804 formatter
805 .debug_struct("CydDisplayEsp")
806 .field("orientation", &self.orientation)
807 .finish_non_exhaustive()
808 }
809}
810
811impl<D> fmt::Debug for CydTouchUncalibratedEsp<D> {
812 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
813 formatter
814 .debug_struct("CydTouchUncalibratedEsp")
815 .finish_non_exhaustive()
816 }
817}
818
819impl<D> fmt::Debug for CydTouchEsp<D> {
820 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
821 formatter
822 .debug_struct("CydTouchEsp")
823 .field("calibration_config", &self.calibration_config)
824 .field("orientation", &self.orientation)
825 .finish_non_exhaustive()
826 }
827}
828
829impl fmt::Debug for CydEsp {
830 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
831 formatter
832 .debug_struct("CydEsp")
833 .field("orientation", &self.display.orientation)
834 .finish_non_exhaustive()
835 }
836}
837
838impl fmt::Debug for CydEspUncalibrated {
839 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
840 formatter
841 .debug_struct("CydEspUncalibrated")
842 .field("orientation", &self.display.orientation)
843 .finish_non_exhaustive()
844 }
845}
846
847impl<D: SpiDevice<u8>> backend::DisplayBackend for CydDisplayEsp<D> {
848 type Error = Error;
849 type Frame<'a>
850 = CydFrameEsp<'a, D>
851 where
852 Self: 'a;
853
854 fn create_frame_mut(&mut self, rectangle: Rectangle) -> Self::Frame<'_> {
855 self.display.make_frame(
856 self.pixel_buffer,
857 rectangle,
858 self.background565,
859 self.foreground565,
860 self.font,
861 )
862 }
863}
864
865impl<D: SpiDevice<u8>> CydDisplay for CydDisplayEsp<D> {
866 #[inline]
867 fn screen_size(&self) -> Size {
868 self.display.size()
869 }
870
871 fn background_color(&self) -> Rgb888 {
872 self.background_color
873 }
874
875 fn foreground_color(&self) -> Rgb888 {
876 self.foreground_color
877 }
878
879 fn background_565(&self) -> Rgb565 {
880 self.background565
881 }
882
883 fn foreground_565(&self) -> Rgb565 {
884 self.foreground565
885 }
886
887 #[inline]
888 fn fill_rectangle(&mut self, rectangle: Rectangle, color: Rgb565) -> Result<(), Error> {
889 Ok(self.display.fill_rectangle(rectangle, color)?)
890 }
891
892 #[inline]
893 fn fill_contiguous<I>(&mut self, rectangle: Rectangle, pixels: I) -> Result<(), Error>
894 where
895 I: IntoIterator<Item = Rgb565>,
896 {
897 Ok(self.display.fill_contiguous(rectangle, pixels)?)
898 }
899}
900
901impl<D: SpiDevice<u8>> TouchUncalibrated for CydTouchUncalibratedEsp<D> {
902 type Error = Error;
903 type Calibrated = CydTouchEsp<D>;
904
905 fn read_raw_touch_event(&mut self) -> Result<Option<RawTouchEvent>, Self::Error> {
906 Ok(self.touch.read_raw_touch_event())
907 }
908
909 fn calibrate(
910 self,
911 calibration_config: CalibrationConfig,
912 orientation: Orientation,
913 ) -> Self::Calibrated {
914 CydTouchEsp {
915 raw: self,
916 calibration_config,
917 orientation,
918 }
919 }
920}
921
922impl<D: SpiDevice<u8>> CydTouch for CydTouchEsp<D> {
923 type Error = Error;
924
925 fn try_read(&mut self) -> Result<Option<TouchEvent>, Error> {
926 Ok(self
927 .raw
928 .touch
929 .read_raw_touch_event()
930 .map(|raw_touch_event| match raw_touch_event {
931 RawTouchEvent::Down { raw_x, raw_y } => {
932 let (x, y) = self.calibration_config.map_raw_to_screen(raw_x, raw_y);
933 TouchEvent::Down {
934 point: self
935 .orientation
936 .map_landscape_point(Point::new(x as i32, y as i32)),
937 }
938 }
939 RawTouchEvent::Move { raw_x, raw_y } => {
940 let (x, y) = self.calibration_config.map_raw_to_screen(raw_x, raw_y);
941 TouchEvent::Move {
942 point: self
943 .orientation
944 .map_landscape_point(Point::new(x as i32, y as i32)),
945 }
946 }
947 RawTouchEvent::Up => TouchEvent::Up,
948 }))
949 }
950}
951
952impl<D: SpiDevice<u8>> CydFrame for CydFrameEsp<'_, D> {
953 type Error = Error;
954
955 fn rectangle(&self) -> Rectangle {
956 self.rectangle
957 }
958
959 fn fill(&mut self, color: Rgb565) -> &mut Self {
960 CydFrameEsp::fill(self, color)
961 }
962
963 fn clear(&mut self) -> &mut Self {
964 self.fill(self.background565)
965 }
966
967 fn write_text(&mut self, text: &str) -> &mut Self {
968 CydFrameEsp::write_text(self, text)
969 }
970
971 fn copy_from_565(&mut self, src: &[u16]) -> device_envoy_core::Result<()> {
972 let dst = self.raw_pixels_mut();
973 if dst.len() != src.len() {
974 return Err(device_envoy_core::Error::CopySize {
975 src_len: src.len(),
976 frame_len: dst.len(),
977 });
978 }
979 dst.copy_from_slice(src);
980 Ok(())
981 }
982
983 async fn flush(&mut self) -> Result<(), Error> {
987 CydFrameEsp::flush(self)
988 }
989}