1use pico_de_gallo_lib::{
47 AdcChannel, AdcConfigurationInfo, AdcError, GpioDirection, GpioEdge, GpioError, GpioPull,
48 GpioState, I2cError, OneWireError, PicoDeGallo, PicoDeGalloError, PwmError, SpiError,
49 UartError,
50};
51use std::sync::Arc;
52use tokio::runtime::{Handle, Runtime};
53use tokio::sync::Mutex;
54use tokio::task::block_in_place;
55
56pub use pico_de_gallo_lib::{
57 GpioEvent, I2cFrequency, SpiConfigurationInfo, SpiPhase, SpiPolarity, UartConfigurationInfo,
58};
59
60pub struct Hal {
66 gallo: Arc<Mutex<PicoDeGallo>>,
67 _runtime: Option<Runtime>,
68 handle: Handle,
69}
70
71impl Default for Hal {
72 fn default() -> Self {
73 Self::new()
74 }
75}
76
77impl Hal {
78 pub fn new() -> Self {
80 Self::new_inner(None)
81 }
82
83 pub fn new_with_serial_number(serial_number: &str) -> Self {
86 Self::new_inner(Some(serial_number))
87 }
88
89 fn new_inner(serial_number: Option<&str>) -> Self {
90 let (runtime, handle) = match Handle::try_current() {
91 Ok(handle) => (None, handle),
92 Err(_) => {
93 let runtime = Runtime::new().unwrap();
94 let handle = runtime.handle().clone();
95 (Some(runtime), handle)
96 }
97 };
98
99 let gallo = if runtime.is_none() {
100 if let Some(serial_number) = serial_number {
101 PicoDeGallo::new_with_serial_number(serial_number)
102 } else {
103 PicoDeGallo::new()
104 }
105 } else {
106 handle.block_on(async {
107 if let Some(serial_number) = serial_number {
108 PicoDeGallo::new_with_serial_number(serial_number)
109 } else {
110 PicoDeGallo::new()
111 }
112 })
113 };
114
115 Self {
116 gallo: Arc::new(Mutex::new(gallo)),
117 _runtime: runtime,
118 handle,
119 }
120 }
121
122 pub fn i2c_set_config(&mut self, frequency: I2cFrequency) -> Result<(), I2cHalError> {
124 if Self::in_async_context() {
125 block_in_place(|| self.i2c_set_config_inner(frequency))
126 } else {
127 self.i2c_set_config_inner(frequency)
128 }
129 }
130
131 fn i2c_set_config_inner(&mut self, frequency: I2cFrequency) -> Result<(), I2cHalError> {
132 let handle = self.handle.clone();
133 let gallo = handle.block_on(self.gallo.lock());
134 handle
135 .block_on(gallo.i2c_set_config(frequency))
136 .map_err(I2cHalError::from)
137 }
138
139 pub fn i2c_scan(&self, include_reserved: bool) -> Result<Vec<u8>, I2cHalError> {
145 if Self::in_async_context() {
146 block_in_place(|| self.i2c_scan_inner(include_reserved))
147 } else {
148 self.i2c_scan_inner(include_reserved)
149 }
150 }
151
152 fn i2c_scan_inner(&self, include_reserved: bool) -> Result<Vec<u8>, I2cHalError> {
153 let handle = self.handle.clone();
154 let gallo = handle.block_on(self.gallo.lock());
155 handle
156 .block_on(gallo.i2c_scan(include_reserved))
157 .map_err(I2cHalError::from)
158 }
159
160 pub fn spi_set_config(
162 &mut self,
163 spi_frequency: u32,
164 spi_phase: SpiPhase,
165 spi_polarity: SpiPolarity,
166 ) -> Result<(), SpiHalError> {
167 if Self::in_async_context() {
168 block_in_place(|| self.spi_set_config_inner(spi_frequency, spi_phase, spi_polarity))
169 } else {
170 self.spi_set_config_inner(spi_frequency, spi_phase, spi_polarity)
171 }
172 }
173
174 fn spi_set_config_inner(
175 &mut self,
176 spi_frequency: u32,
177 spi_phase: SpiPhase,
178 spi_polarity: SpiPolarity,
179 ) -> Result<(), SpiHalError> {
180 let handle = self.handle.clone();
181 let gallo = handle.block_on(self.gallo.lock());
182 handle
183 .block_on(gallo.spi_set_config(spi_frequency, spi_phase, spi_polarity))
184 .map_err(SpiHalError::from)
185 }
186
187 pub fn i2c_get_config(&self) -> Result<I2cFrequency, I2cHalError> {
192 if Self::in_async_context() {
193 block_in_place(|| self.i2c_get_config_inner())
194 } else {
195 self.i2c_get_config_inner()
196 }
197 }
198
199 fn i2c_get_config_inner(&self) -> Result<I2cFrequency, I2cHalError> {
200 let handle = self.handle.clone();
201 let gallo = handle.block_on(self.gallo.lock());
202 handle
203 .block_on(gallo.i2c_get_config())
204 .map_err(|e| match e {
205 PicoDeGalloError::Comms(c) => I2cHalError::Comms(format!("{c:?}")),
206 PicoDeGalloError::Endpoint(never) => match never {},
207 })
208 }
209
210 pub fn spi_get_config(&self) -> Result<SpiConfigurationInfo, SpiHalError> {
215 if Self::in_async_context() {
216 block_in_place(|| self.spi_get_config_inner())
217 } else {
218 self.spi_get_config_inner()
219 }
220 }
221
222 fn spi_get_config_inner(&self) -> Result<SpiConfigurationInfo, SpiHalError> {
223 let handle = self.handle.clone();
224 let gallo = handle.block_on(self.gallo.lock());
225 handle
226 .block_on(gallo.spi_get_config())
227 .map_err(|e| match e {
228 PicoDeGalloError::Comms(c) => SpiHalError::Comms(format!("{c:?}")),
229 PicoDeGalloError::Endpoint(never) => match never {},
230 })
231 }
232
233 pub fn pwm_set_config(
238 &mut self,
239 channel: u8,
240 frequency_hz: u32,
241 phase_correct: bool,
242 ) -> Result<(), PwmHalError> {
243 if Self::in_async_context() {
244 block_in_place(|| self.pwm_set_config_inner(channel, frequency_hz, phase_correct))
245 } else {
246 self.pwm_set_config_inner(channel, frequency_hz, phase_correct)
247 }
248 }
249
250 fn pwm_set_config_inner(
251 &self,
252 channel: u8,
253 frequency_hz: u32,
254 phase_correct: bool,
255 ) -> Result<(), PwmHalError> {
256 let handle = self.handle.clone();
257 let gallo = handle.block_on(self.gallo.lock());
258 handle
259 .block_on(gallo.pwm_set_config(channel, frequency_hz, phase_correct))
260 .map_err(PwmHalError::from)
261 }
262
263 pub fn pwm_get_config(
265 &self,
266 channel: u8,
267 ) -> Result<pico_de_gallo_lib::PwmConfigurationInfo, PwmHalError> {
268 if Self::in_async_context() {
269 block_in_place(|| self.pwm_get_config_inner(channel))
270 } else {
271 self.pwm_get_config_inner(channel)
272 }
273 }
274
275 fn pwm_get_config_inner(
276 &self,
277 channel: u8,
278 ) -> Result<pico_de_gallo_lib::PwmConfigurationInfo, PwmHalError> {
279 let handle = self.handle.clone();
280 let gallo = handle.block_on(self.gallo.lock());
281 handle
282 .block_on(gallo.pwm_get_config(channel))
283 .map_err(PwmHalError::from)
284 }
285
286 pub fn gpio(&self, pin: u8) -> Gpio {
288 let gallo = Arc::clone(&self.gallo);
289 let handle = self.handle.clone();
290 Gpio { pin, gallo, handle }
291 }
292
293 pub fn i2c(&self) -> I2c {
295 let gallo = Arc::clone(&self.gallo);
296 let handle = self.handle.clone();
297 I2c { gallo, handle }
298 }
299
300 pub fn spi(&self) -> Spi {
302 let gallo = Arc::clone(&self.gallo);
303 let handle = self.handle.clone();
304 Spi { gallo, handle }
305 }
306
307 pub fn uart(&self) -> Uart {
309 let gallo = Arc::clone(&self.gallo);
310 let handle = self.handle.clone();
311 Uart {
312 gallo,
313 handle,
314 timeout_ms: 1000,
315 }
316 }
317
318 pub fn pwm_channel(&self, channel: u8) -> PwmChannel {
324 let gallo = Arc::clone(&self.gallo);
325 let handle = self.handle.clone();
326 PwmChannel {
327 channel,
328 gallo,
329 handle,
330 }
331 }
332
333 pub fn adc_read(&self, channel: AdcChannel) -> Result<u16, AdcHalError> {
341 if Self::in_async_context() {
342 block_in_place(|| self.adc_read_inner(channel))
343 } else {
344 self.adc_read_inner(channel)
345 }
346 }
347
348 fn adc_read_inner(&self, channel: AdcChannel) -> Result<u16, AdcHalError> {
349 let handle = self.handle.clone();
350 let gallo = handle.block_on(self.gallo.lock());
351 handle
352 .block_on(gallo.adc_read(channel))
353 .map_err(AdcHalError::from)
354 }
355
356 pub fn adc_get_config(&self) -> Result<AdcConfigurationInfo, AdcHalError> {
358 if Self::in_async_context() {
359 block_in_place(|| self.adc_get_config_inner())
360 } else {
361 self.adc_get_config_inner()
362 }
363 }
364
365 fn adc_get_config_inner(&self) -> Result<AdcConfigurationInfo, AdcHalError> {
366 let handle = self.handle.clone();
367 let gallo = handle.block_on(self.gallo.lock());
368 handle
369 .block_on(gallo.adc_get_config())
370 .map_err(|e| match e {
371 PicoDeGalloError::Comms(c) => AdcHalError::Comms(format!("{c:?}")),
372 PicoDeGalloError::Endpoint(e) => AdcHalError::Adc(e),
373 })
374 }
375
376 pub fn gpio_subscribe(&self, pin: u8, edge: GpioEdge) -> Result<(), GpioHalError> {
382 if Self::in_async_context() {
383 block_in_place(|| self.gpio_subscribe_inner(pin, edge))
384 } else {
385 self.gpio_subscribe_inner(pin, edge)
386 }
387 }
388
389 fn gpio_subscribe_inner(&self, pin: u8, edge: GpioEdge) -> Result<(), GpioHalError> {
390 let handle = self.handle.clone();
391 let gallo = handle.block_on(self.gallo.lock());
392 handle
393 .block_on(gallo.gpio_subscribe(pin, edge))
394 .map_err(GpioHalError::from)
395 }
396
397 pub fn gpio_unsubscribe(&self, pin: u8) -> Result<(), GpioHalError> {
401 if Self::in_async_context() {
402 block_in_place(|| self.gpio_unsubscribe_inner(pin))
403 } else {
404 self.gpio_unsubscribe_inner(pin)
405 }
406 }
407
408 fn gpio_unsubscribe_inner(&self, pin: u8) -> Result<(), GpioHalError> {
409 let handle = self.handle.clone();
410 let gallo = handle.block_on(self.gallo.lock());
411 handle
412 .block_on(gallo.gpio_unsubscribe(pin))
413 .map_err(GpioHalError::from)
414 }
415
416 pub fn spi_device(&self, cs_pin: u8) -> Result<SpiDev, SpiHalError> {
428 let gallo = Arc::clone(&self.gallo);
429 let handle = self.handle.clone();
430
431 let guard = handle.block_on(gallo.lock());
433 handle
434 .block_on(guard.gpio_put(cs_pin, GpioState::High))
435 .map_err(|e| SpiHalError::Comms(format!("CS init failed: {e:?}")))?;
436 drop(guard);
437
438 Ok(SpiDev {
439 gallo,
440 handle,
441 cs_pin,
442 })
443 }
444
445 pub fn delay(&self) -> Delay {
447 Delay
448 }
449
450 pub fn onewire(&self) -> OneWire {
456 OneWire {
457 gallo: self.gallo.clone(),
458 handle: self.handle.clone(),
459 }
460 }
461
462 fn in_async_context() -> bool {
464 Handle::try_current().is_ok()
465 }
466}
467
468#[derive(Debug)]
472pub enum GpioHalError {
473 Gpio(GpioError),
475 Comms(String),
477}
478
479impl core::fmt::Display for GpioHalError {
480 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
481 match self {
482 Self::Gpio(e) => write!(f, "{e}"),
483 Self::Comms(msg) => write!(f, "communication error: {msg}"),
484 }
485 }
486}
487
488impl std::error::Error for GpioHalError {}
489
490impl From<PicoDeGalloError<GpioError>> for GpioHalError {
491 fn from(e: PicoDeGalloError<GpioError>) -> Self {
492 match e {
493 PicoDeGalloError::Endpoint(e) => Self::Gpio(e),
494 PicoDeGalloError::Comms(c) => Self::Comms(format!("{c:?}")),
495 }
496 }
497}
498
499impl embedded_hal::digital::Error for GpioHalError {
500 fn kind(&self) -> embedded_hal::digital::ErrorKind {
501 embedded_hal::digital::ErrorKind::Other
502 }
503}
504
505#[derive(Debug)]
507pub enum I2cHalError {
508 I2c(I2cError),
510 Comms(String),
512}
513
514impl core::fmt::Display for I2cHalError {
515 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
516 match self {
517 Self::I2c(e) => write!(f, "{e}"),
518 Self::Comms(msg) => write!(f, "communication error: {msg}"),
519 }
520 }
521}
522
523impl std::error::Error for I2cHalError {}
524
525impl From<PicoDeGalloError<I2cError>> for I2cHalError {
526 fn from(e: PicoDeGalloError<I2cError>) -> Self {
527 match e {
528 PicoDeGalloError::Endpoint(e) => Self::I2c(e),
529 PicoDeGalloError::Comms(c) => Self::Comms(format!("{c:?}")),
530 }
531 }
532}
533
534impl From<PicoDeGalloError<pico_de_gallo_lib::I2cBatchError>> for I2cHalError {
535 fn from(e: PicoDeGalloError<pico_de_gallo_lib::I2cBatchError>) -> Self {
536 match e {
537 PicoDeGalloError::Endpoint(batch_err) => Self::I2c(batch_err.kind),
538 PicoDeGalloError::Comms(c) => Self::Comms(format!("{c:?}")),
539 }
540 }
541}
542
543impl embedded_hal::i2c::Error for I2cHalError {
544 fn kind(&self) -> embedded_hal::i2c::ErrorKind {
545 match self {
546 Self::I2c(I2cError::NoAcknowledge) => embedded_hal::i2c::ErrorKind::NoAcknowledge(
547 embedded_hal::i2c::NoAcknowledgeSource::Unknown,
548 ),
549 Self::I2c(I2cError::ArbitrationLoss) => embedded_hal::i2c::ErrorKind::ArbitrationLoss,
550 Self::I2c(I2cError::Bus) => embedded_hal::i2c::ErrorKind::Bus,
551 Self::I2c(I2cError::Overrun) => embedded_hal::i2c::ErrorKind::Overrun,
552 _ => embedded_hal::i2c::ErrorKind::Other,
553 }
554 }
555}
556
557#[derive(Debug)]
559pub enum SpiHalError {
560 Spi(SpiError),
562 Comms(String),
564}
565
566impl core::fmt::Display for SpiHalError {
567 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
568 match self {
569 Self::Spi(e) => write!(f, "{e}"),
570 Self::Comms(msg) => write!(f, "communication error: {msg}"),
571 }
572 }
573}
574
575impl std::error::Error for SpiHalError {}
576
577impl From<PicoDeGalloError<SpiError>> for SpiHalError {
578 fn from(e: PicoDeGalloError<SpiError>) -> Self {
579 match e {
580 PicoDeGalloError::Endpoint(e) => Self::Spi(e),
581 PicoDeGalloError::Comms(c) => Self::Comms(format!("{c:?}")),
582 }
583 }
584}
585
586impl From<PicoDeGalloError<pico_de_gallo_lib::SpiBatchError>> for SpiHalError {
587 fn from(e: PicoDeGalloError<pico_de_gallo_lib::SpiBatchError>) -> Self {
588 match e {
589 PicoDeGalloError::Endpoint(batch_err) => Self::Spi(batch_err.kind),
590 PicoDeGalloError::Comms(c) => Self::Comms(format!("{c:?}")),
591 }
592 }
593}
594
595impl embedded_hal::spi::Error for SpiHalError {
596 fn kind(&self) -> embedded_hal::spi::ErrorKind {
597 embedded_hal::spi::ErrorKind::Other
598 }
599}
600
601#[derive(Debug)]
603pub enum UartHalError {
604 Uart(UartError),
606 Comms(String),
608}
609
610impl core::fmt::Display for UartHalError {
611 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
612 match self {
613 Self::Uart(e) => write!(f, "{e}"),
614 Self::Comms(msg) => write!(f, "communication error: {msg}"),
615 }
616 }
617}
618
619impl std::error::Error for UartHalError {}
620
621impl From<PicoDeGalloError<UartError>> for UartHalError {
622 fn from(e: PicoDeGalloError<UartError>) -> Self {
623 match e {
624 PicoDeGalloError::Endpoint(e) => Self::Uart(e),
625 PicoDeGalloError::Comms(c) => Self::Comms(format!("{c:?}")),
626 }
627 }
628}
629
630impl embedded_io::Error for UartHalError {
631 fn kind(&self) -> embedded_io::ErrorKind {
632 match self {
633 Self::Uart(UartError::Overrun) => embedded_io::ErrorKind::Other,
634 Self::Uart(UartError::Break) => embedded_io::ErrorKind::Other,
635 Self::Uart(UartError::Parity) => embedded_io::ErrorKind::Other,
636 Self::Uart(UartError::Framing) => embedded_io::ErrorKind::Other,
637 Self::Uart(UartError::InvalidBaudRate) => embedded_io::ErrorKind::InvalidInput,
638 _ => embedded_io::ErrorKind::Other,
639 }
640 }
641}
642
643pub struct Gpio {
650 pin: u8,
651 gallo: Arc<Mutex<PicoDeGallo>>,
652 handle: Handle,
653}
654
655impl Gpio {
656 pub fn set_config(
662 &mut self,
663 direction: GpioDirection,
664 pull: GpioPull,
665 ) -> std::result::Result<(), GpioHalError> {
666 if Hal::in_async_context() {
667 block_in_place(|| self.set_config_inner(direction, pull))
668 } else {
669 self.set_config_inner(direction, pull)
670 }
671 }
672
673 fn set_config_inner(
674 &mut self,
675 direction: GpioDirection,
676 pull: GpioPull,
677 ) -> std::result::Result<(), GpioHalError> {
678 let handle = &self.handle;
679 let gallo = handle.block_on(self.gallo.lock());
680 handle
681 .block_on(gallo.gpio_set_config(self.pin, direction, pull))
682 .map_err(GpioHalError::from)
683 }
684
685 fn set_low_inner(&mut self) -> std::result::Result<(), GpioHalError> {
686 let handle = &self.handle;
687 let gallo = handle.block_on(self.gallo.lock());
688 handle
689 .block_on(gallo.gpio_put(self.pin, GpioState::Low))
690 .map_err(GpioHalError::from)
691 }
692
693 fn set_high_inner(&mut self) -> std::result::Result<(), GpioHalError> {
694 let handle = &self.handle;
695 let gallo = handle.block_on(self.gallo.lock());
696 handle
697 .block_on(gallo.gpio_put(self.pin, GpioState::High))
698 .map_err(GpioHalError::from)
699 }
700
701 fn is_low_inner(&mut self) -> std::result::Result<bool, GpioHalError> {
702 let handle = &self.handle;
703 let gallo = handle.block_on(self.gallo.lock());
704 handle
705 .block_on(gallo.gpio_get(self.pin))
706 .map_err(GpioHalError::from)
707 .map(|s| s == GpioState::Low)
708 }
709
710 fn is_high_inner(&mut self) -> std::result::Result<bool, GpioHalError> {
711 let handle = &self.handle;
712 let gallo = handle.block_on(self.gallo.lock());
713 handle
714 .block_on(gallo.gpio_get(self.pin))
715 .map_err(GpioHalError::from)
716 .map(|s| s == GpioState::High)
717 }
718}
719
720impl embedded_hal::digital::ErrorType for Gpio {
721 type Error = GpioHalError;
722}
723
724impl embedded_hal::digital::OutputPin for Gpio {
725 fn set_low(&mut self) -> std::result::Result<(), Self::Error> {
726 if Hal::in_async_context() {
727 block_in_place(|| self.set_low_inner())
728 } else {
729 self.set_low_inner()
730 }
731 }
732
733 fn set_high(&mut self) -> std::result::Result<(), Self::Error> {
734 if Hal::in_async_context() {
735 block_in_place(|| self.set_high_inner())
736 } else {
737 self.set_high_inner()
738 }
739 }
740}
741
742impl embedded_hal::digital::InputPin for Gpio {
743 fn is_low(&mut self) -> std::result::Result<bool, Self::Error> {
744 if Hal::in_async_context() {
745 block_in_place(|| self.is_low_inner())
746 } else {
747 self.is_low_inner()
748 }
749 }
750
751 fn is_high(&mut self) -> std::result::Result<bool, Self::Error> {
752 if Hal::in_async_context() {
753 block_in_place(|| self.is_high_inner())
754 } else {
755 self.is_high_inner()
756 }
757 }
758}
759
760impl embedded_hal::digital::StatefulOutputPin for Gpio {
761 fn is_set_low(&mut self) -> std::result::Result<bool, Self::Error> {
762 self.is_low_inner()
763 }
764
765 fn is_set_high(&mut self) -> std::result::Result<bool, Self::Error> {
766 self.is_high_inner()
767 }
768}
769
770impl embedded_hal_async::digital::Wait for Gpio {
771 async fn wait_for_high(&mut self) -> Result<(), Self::Error> {
772 let gallo = self.gallo.lock().await;
773 gallo
774 .gpio_wait_for_high(self.pin)
775 .await
776 .map_err(GpioHalError::from)
777 }
778
779 async fn wait_for_low(&mut self) -> Result<(), Self::Error> {
780 let gallo = self.gallo.lock().await;
781 gallo
782 .gpio_wait_for_low(self.pin)
783 .await
784 .map_err(GpioHalError::from)
785 }
786
787 async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> {
788 let gallo = self.gallo.lock().await;
789 gallo
790 .gpio_wait_for_rising_edge(self.pin)
791 .await
792 .map_err(GpioHalError::from)
793 }
794
795 async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> {
796 let gallo = self.gallo.lock().await;
797 gallo
798 .gpio_wait_for_falling_edge(self.pin)
799 .await
800 .map_err(GpioHalError::from)
801 }
802
803 async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> {
804 let gallo = self.gallo.lock().await;
805 gallo
806 .gpio_wait_for_any_edge(self.pin)
807 .await
808 .map_err(GpioHalError::from)
809 }
810}
811
812pub struct I2c {
819 gallo: Arc<Mutex<PicoDeGallo>>,
820 handle: Handle,
821}
822
823impl I2c {
824 fn transaction_inner(
825 &mut self,
826 address: embedded_hal::i2c::SevenBitAddress,
827 operations: &mut [embedded_hal::i2c::Operation<'_>],
828 ) -> std::result::Result<(), I2cHalError> {
829 use pico_de_gallo_lib::I2cBatchOp;
830
831 let handle = &self.handle;
832 let gallo = handle.block_on(self.gallo.lock());
833
834 let batch_ops: Vec<I2cBatchOp<'_>> = operations
836 .iter()
837 .map(|op| match op {
838 embedded_hal::i2c::Operation::Read(buf) => I2cBatchOp::Read {
839 len: buf.len() as u16,
840 },
841 embedded_hal::i2c::Operation::Write(data) => I2cBatchOp::Write { data },
842 })
843 .collect();
844
845 let result = handle
846 .block_on(gallo.i2c_batch(address, &batch_ops))
847 .map_err(I2cHalError::from)?;
848
849 let mut offset = 0usize;
851 for op in operations.iter_mut() {
852 if let embedded_hal::i2c::Operation::Read(buf) = op {
853 let len = buf.len();
854 buf.copy_from_slice(&result[offset..offset + len]);
855 offset += len;
856 }
857 }
858
859 Ok(())
860 }
861}
862
863impl embedded_hal::i2c::ErrorType for I2c {
864 type Error = I2cHalError;
865}
866
867impl embedded_hal::i2c::I2c<embedded_hal::i2c::SevenBitAddress> for I2c {
868 fn transaction(
869 &mut self,
870 address: embedded_hal::i2c::SevenBitAddress,
871 operations: &mut [embedded_hal::i2c::Operation<'_>],
872 ) -> std::result::Result<(), Self::Error> {
873 if Hal::in_async_context() {
874 block_in_place(|| self.transaction_inner(address, operations))
875 } else {
876 self.transaction_inner(address, operations)
877 }
878 }
879}
880
881impl embedded_hal_async::i2c::I2c<embedded_hal_async::i2c::SevenBitAddress> for I2c {
882 async fn transaction(
883 &mut self,
884 address: embedded_hal_async::i2c::SevenBitAddress,
885 operations: &mut [embedded_hal_async::i2c::Operation<'_>],
886 ) -> std::result::Result<(), Self::Error> {
887 use pico_de_gallo_lib::I2cBatchOp;
888
889 let gallo = self.gallo.lock().await;
890
891 let batch_ops: Vec<I2cBatchOp<'_>> = operations
892 .iter()
893 .map(|op| match op {
894 embedded_hal_async::i2c::Operation::Read(buf) => I2cBatchOp::Read {
895 len: buf.len() as u16,
896 },
897 embedded_hal_async::i2c::Operation::Write(data) => I2cBatchOp::Write { data },
898 })
899 .collect();
900
901 let result = gallo
902 .i2c_batch(address, &batch_ops)
903 .await
904 .map_err(I2cHalError::from)?;
905
906 let mut offset = 0usize;
907 for op in operations.iter_mut() {
908 if let embedded_hal_async::i2c::Operation::Read(buf) = op {
909 let len = buf.len();
910 buf.copy_from_slice(&result[offset..offset + len]);
911 offset += len;
912 }
913 }
914
915 Ok(())
916 }
917}
918
919pub struct Spi {
927 gallo: Arc<Mutex<PicoDeGallo>>,
928 handle: Handle,
929}
930
931impl Spi {
932 fn read_inner(&mut self, words: &mut [u8]) -> std::result::Result<(), SpiHalError> {
933 let handle = &self.handle;
934 let gallo = handle.block_on(self.gallo.lock());
935 let contents = handle
936 .block_on(gallo.spi_read(words.len() as u16))
937 .map_err(SpiHalError::from)?;
938 words.copy_from_slice(&contents);
939 Ok(())
940 }
941
942 fn write_inner(&mut self, words: &[u8]) -> std::result::Result<(), SpiHalError> {
943 let handle = &self.handle;
944 let gallo = handle.block_on(self.gallo.lock());
945 handle
946 .block_on(gallo.spi_write(words))
947 .map_err(SpiHalError::from)
948 }
949
950 fn transfer_inner(
951 &mut self,
952 read: &mut [u8],
953 write: &[u8],
954 ) -> std::result::Result<(), SpiHalError> {
955 let handle = &self.handle;
956 let gallo = handle.block_on(self.gallo.lock());
957 let contents = handle
958 .block_on(gallo.spi_transfer(write))
959 .map_err(SpiHalError::from)?;
960 let len = read.len().min(contents.len());
961 read[..len].copy_from_slice(&contents[..len]);
962 Ok(())
963 }
964
965 fn flush_inner(&mut self) -> std::result::Result<(), SpiHalError> {
966 let handle = &self.handle;
967 let gallo = handle.block_on(self.gallo.lock());
968 handle
969 .block_on(gallo.spi_flush())
970 .map_err(SpiHalError::from)
971 }
972}
973
974impl embedded_hal::spi::ErrorType for Spi {
975 type Error = SpiHalError;
976}
977
978impl embedded_hal::spi::SpiBus for Spi {
979 fn read(&mut self, words: &mut [u8]) -> std::result::Result<(), Self::Error> {
980 if Hal::in_async_context() {
981 block_in_place(|| self.read_inner(words))
982 } else {
983 self.read_inner(words)
984 }
985 }
986
987 fn write(&mut self, words: &[u8]) -> std::result::Result<(), Self::Error> {
988 if Hal::in_async_context() {
989 block_in_place(|| self.write_inner(words))
990 } else {
991 self.write_inner(words)
992 }
993 }
994
995 fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> std::result::Result<(), Self::Error> {
996 if Hal::in_async_context() {
997 block_in_place(|| self.transfer_inner(read, write))
998 } else {
999 self.transfer_inner(read, write)
1000 }
1001 }
1002
1003 fn transfer_in_place(&mut self, words: &mut [u8]) -> std::result::Result<(), Self::Error> {
1004 if Hal::in_async_context() {
1005 block_in_place(|| {
1006 let write_copy = words.to_vec();
1007 self.transfer_inner(words, &write_copy)
1008 })
1009 } else {
1010 let write_copy = words.to_vec();
1011 self.transfer_inner(words, &write_copy)
1012 }
1013 }
1014
1015 fn flush(&mut self) -> std::result::Result<(), Self::Error> {
1016 if Hal::in_async_context() {
1017 block_in_place(|| self.flush_inner())
1018 } else {
1019 self.flush_inner()
1020 }
1021 }
1022}
1023
1024impl embedded_hal_async::spi::SpiBus for Spi {
1025 async fn read(&mut self, words: &mut [u8]) -> std::result::Result<(), Self::Error> {
1026 let gallo = self.gallo.lock().await;
1027 let contents = gallo
1028 .spi_read(words.len() as u16)
1029 .await
1030 .map_err(SpiHalError::from)?;
1031 words.copy_from_slice(&contents);
1032 Ok(())
1033 }
1034
1035 async fn write(&mut self, words: &[u8]) -> std::result::Result<(), Self::Error> {
1036 let gallo = self.gallo.lock().await;
1037 gallo.spi_write(words).await.map_err(SpiHalError::from)
1038 }
1039
1040 async fn transfer(
1041 &mut self,
1042 read: &mut [u8],
1043 write: &[u8],
1044 ) -> std::result::Result<(), Self::Error> {
1045 let gallo = self.gallo.lock().await;
1046 let contents = gallo.spi_transfer(write).await.map_err(SpiHalError::from)?;
1047 let len = read.len().min(contents.len());
1048 read[..len].copy_from_slice(&contents[..len]);
1049 Ok(())
1050 }
1051
1052 async fn transfer_in_place(
1053 &mut self,
1054 words: &mut [u8],
1055 ) -> std::result::Result<(), Self::Error> {
1056 let gallo = self.gallo.lock().await;
1057 let write_copy = words.to_vec();
1058 let contents = gallo
1059 .spi_transfer(&write_copy)
1060 .await
1061 .map_err(SpiHalError::from)?;
1062 let len = words.len().min(contents.len());
1063 words[..len].copy_from_slice(&contents[..len]);
1064 Ok(())
1065 }
1066
1067 async fn flush(&mut self) -> std::result::Result<(), Self::Error> {
1068 let gallo = self.gallo.lock().await;
1069 gallo.spi_flush().await.map_err(SpiHalError::from)
1070 }
1071}
1072
1073pub struct SpiDev {
1098 gallo: Arc<Mutex<PicoDeGallo>>,
1099 handle: Handle,
1100 cs_pin: u8,
1101}
1102
1103impl SpiDev {
1104 fn transaction_inner(
1106 &mut self,
1107 operations: &mut [embedded_hal::spi::Operation<'_, u8>],
1108 ) -> std::result::Result<(), SpiHalError> {
1109 use pico_de_gallo_lib::SpiBatchOp;
1110
1111 let handle = &self.handle;
1112 let gallo = handle.block_on(self.gallo.lock());
1113
1114 let mut in_place_bufs: Vec<(usize, Vec<u8>)> = Vec::new();
1117 let mut batch_ops: Vec<SpiBatchOp<'_>> = operations
1118 .iter()
1119 .enumerate()
1120 .map(|(i, op)| match op {
1121 embedded_hal::spi::Operation::Read(buf) => SpiBatchOp::Read {
1122 len: buf.len() as u16,
1123 },
1124 embedded_hal::spi::Operation::Write(data) => SpiBatchOp::Write { data },
1125 embedded_hal::spi::Operation::Transfer(_read, write) => {
1126 SpiBatchOp::Transfer { data: write }
1127 }
1128 embedded_hal::spi::Operation::TransferInPlace(buf) => {
1129 in_place_bufs.push((i, buf.to_vec()));
1130 SpiBatchOp::Transfer { data: &[] }
1131 }
1132 embedded_hal::spi::Operation::DelayNs(ns) => SpiBatchOp::DelayNs { ns: *ns },
1133 })
1134 .collect();
1135
1136 for (idx, buf) in &in_place_bufs {
1138 batch_ops[*idx] = SpiBatchOp::Transfer { data: buf };
1139 }
1140
1141 let result = handle
1142 .block_on(gallo.spi_batch(self.cs_pin, &batch_ops))
1143 .map_err(SpiHalError::from)?;
1144
1145 let mut offset = 0usize;
1147 for op in operations.iter_mut() {
1148 match op {
1149 embedded_hal::spi::Operation::Read(buf) => {
1150 let len = buf.len();
1151 buf.copy_from_slice(&result[offset..offset + len]);
1152 offset += len;
1153 }
1154 embedded_hal::spi::Operation::Transfer(read, _write) => {
1155 let len = read.len();
1156 read.copy_from_slice(&result[offset..offset + len]);
1157 offset += len;
1158 }
1159 embedded_hal::spi::Operation::TransferInPlace(buf) => {
1160 let len = buf.len();
1161 buf.copy_from_slice(&result[offset..offset + len]);
1162 offset += len;
1163 }
1164 _ => {}
1165 }
1166 }
1167
1168 Ok(())
1169 }
1170}
1171
1172impl embedded_hal::spi::ErrorType for SpiDev {
1173 type Error = SpiHalError;
1174}
1175
1176impl embedded_hal::spi::SpiDevice for SpiDev {
1177 fn transaction(
1178 &mut self,
1179 operations: &mut [embedded_hal::spi::Operation<'_, u8>],
1180 ) -> std::result::Result<(), Self::Error> {
1181 if Hal::in_async_context() {
1182 block_in_place(|| self.transaction_inner(operations))
1183 } else {
1184 self.transaction_inner(operations)
1185 }
1186 }
1187}
1188
1189impl embedded_hal_async::spi::SpiDevice for SpiDev {
1190 async fn transaction(
1191 &mut self,
1192 operations: &mut [embedded_hal_async::spi::Operation<'_, u8>],
1193 ) -> std::result::Result<(), Self::Error> {
1194 use pico_de_gallo_lib::SpiBatchOp;
1195
1196 let gallo = self.gallo.lock().await;
1197
1198 let mut in_place_bufs: Vec<(usize, Vec<u8>)> = Vec::new();
1200 let mut batch_ops: Vec<SpiBatchOp<'_>> = operations
1201 .iter()
1202 .enumerate()
1203 .map(|(i, op)| match op {
1204 embedded_hal_async::spi::Operation::Read(buf) => SpiBatchOp::Read {
1205 len: buf.len() as u16,
1206 },
1207 embedded_hal_async::spi::Operation::Write(data) => SpiBatchOp::Write { data },
1208 embedded_hal_async::spi::Operation::Transfer(_read, write) => {
1209 SpiBatchOp::Transfer { data: write }
1210 }
1211 embedded_hal_async::spi::Operation::TransferInPlace(buf) => {
1212 in_place_bufs.push((i, buf.to_vec()));
1213 SpiBatchOp::Transfer { data: &[] }
1214 }
1215 embedded_hal_async::spi::Operation::DelayNs(ns) => SpiBatchOp::DelayNs { ns: *ns },
1216 })
1217 .collect();
1218
1219 for (idx, buf) in &in_place_bufs {
1221 batch_ops[*idx] = SpiBatchOp::Transfer { data: buf };
1222 }
1223
1224 let result = gallo
1225 .spi_batch(self.cs_pin, &batch_ops)
1226 .await
1227 .map_err(SpiHalError::from)?;
1228
1229 let mut offset = 0usize;
1231 for op in operations.iter_mut() {
1232 match op {
1233 embedded_hal_async::spi::Operation::Read(buf) => {
1234 let len = buf.len();
1235 buf.copy_from_slice(&result[offset..offset + len]);
1236 offset += len;
1237 }
1238 embedded_hal_async::spi::Operation::Transfer(read, _write) => {
1239 let len = read.len();
1240 read.copy_from_slice(&result[offset..offset + len]);
1241 offset += len;
1242 }
1243 embedded_hal_async::spi::Operation::TransferInPlace(buf) => {
1244 let len = buf.len();
1245 buf.copy_from_slice(&result[offset..offset + len]);
1246 offset += len;
1247 }
1248 _ => {}
1249 }
1250 }
1251
1252 Ok(())
1253 }
1254}
1255
1256pub struct Delay;
1263
1264impl embedded_hal::delay::DelayNs for Delay {
1265 fn delay_ns(&mut self, ns: u32) {
1266 std::thread::sleep(std::time::Duration::from_nanos(ns.into()))
1267 }
1268}
1269
1270impl embedded_hal_async::delay::DelayNs for Delay {
1271 async fn delay_ns(&mut self, ns: u32) {
1272 tokio::time::sleep(tokio::time::Duration::from_nanos(ns.into())).await
1273 }
1274}
1275
1276pub struct Uart {
1288 gallo: Arc<Mutex<PicoDeGallo>>,
1289 handle: Handle,
1290 timeout_ms: u32,
1291}
1292
1293impl Uart {
1294 pub fn set_timeout_ms(&mut self, timeout_ms: u32) {
1300 self.timeout_ms = timeout_ms;
1301 }
1302
1303 fn read_inner(&mut self, buf: &mut [u8]) -> std::result::Result<usize, UartHalError> {
1304 let handle = &self.handle;
1305 let gallo = handle.block_on(self.gallo.lock());
1306 let contents = handle
1307 .block_on(gallo.uart_read(buf.len() as u16, self.timeout_ms))
1308 .map_err(UartHalError::from)?;
1309 let n = contents.len().min(buf.len());
1310 buf[..n].copy_from_slice(&contents[..n]);
1311 Ok(n)
1312 }
1313
1314 fn write_inner(&mut self, buf: &[u8]) -> std::result::Result<usize, UartHalError> {
1315 let handle = &self.handle;
1316 let gallo = handle.block_on(self.gallo.lock());
1317 handle
1318 .block_on(gallo.uart_write(buf))
1319 .map_err(UartHalError::from)?;
1320 Ok(buf.len())
1321 }
1322
1323 fn flush_inner(&mut self) -> std::result::Result<(), UartHalError> {
1324 let handle = &self.handle;
1325 let gallo = handle.block_on(self.gallo.lock());
1326 handle
1327 .block_on(gallo.uart_flush())
1328 .map_err(UartHalError::from)
1329 }
1330}
1331
1332impl embedded_io::ErrorType for Uart {
1333 type Error = UartHalError;
1334}
1335
1336impl embedded_io::Read for Uart {
1337 fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, Self::Error> {
1338 if Hal::in_async_context() {
1339 block_in_place(|| self.read_inner(buf))
1340 } else {
1341 self.read_inner(buf)
1342 }
1343 }
1344}
1345
1346impl embedded_io::Write for Uart {
1347 fn write(&mut self, buf: &[u8]) -> std::result::Result<usize, Self::Error> {
1348 if Hal::in_async_context() {
1349 block_in_place(|| self.write_inner(buf))
1350 } else {
1351 self.write_inner(buf)
1352 }
1353 }
1354
1355 fn flush(&mut self) -> std::result::Result<(), Self::Error> {
1356 if Hal::in_async_context() {
1357 block_in_place(|| self.flush_inner())
1358 } else {
1359 self.flush_inner()
1360 }
1361 }
1362}
1363
1364impl embedded_io_async::Read for Uart {
1365 async fn read(&mut self, buf: &mut [u8]) -> std::result::Result<usize, Self::Error> {
1366 let gallo = self.gallo.lock().await;
1367 let contents = gallo
1368 .uart_read(buf.len() as u16, self.timeout_ms)
1369 .await
1370 .map_err(UartHalError::from)?;
1371 let n = contents.len().min(buf.len());
1372 buf[..n].copy_from_slice(&contents[..n]);
1373 Ok(n)
1374 }
1375}
1376
1377impl embedded_io_async::Write for Uart {
1378 async fn write(&mut self, buf: &[u8]) -> std::result::Result<usize, Self::Error> {
1379 let gallo = self.gallo.lock().await;
1380 gallo.uart_write(buf).await.map_err(UartHalError::from)?;
1381 Ok(buf.len())
1382 }
1383
1384 async fn flush(&mut self) -> std::result::Result<(), Self::Error> {
1385 let gallo = self.gallo.lock().await;
1386 gallo.uart_flush().await.map_err(UartHalError::from)
1387 }
1388}
1389
1390#[derive(Debug)]
1396pub enum PwmHalError {
1397 Pwm(PwmError),
1399 Comms(String),
1401}
1402
1403impl core::fmt::Display for PwmHalError {
1404 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1405 match self {
1406 Self::Pwm(e) => write!(f, "{e}"),
1407 Self::Comms(msg) => write!(f, "communication error: {msg}"),
1408 }
1409 }
1410}
1411
1412impl std::error::Error for PwmHalError {}
1413
1414impl From<PicoDeGalloError<PwmError>> for PwmHalError {
1415 fn from(e: PicoDeGalloError<PwmError>) -> Self {
1416 match e {
1417 PicoDeGalloError::Endpoint(e) => Self::Pwm(e),
1418 PicoDeGalloError::Comms(c) => Self::Comms(format!("{c:?}")),
1419 }
1420 }
1421}
1422
1423impl embedded_hal::pwm::Error for PwmHalError {
1424 fn kind(&self) -> embedded_hal::pwm::ErrorKind {
1425 embedded_hal::pwm::ErrorKind::Other
1426 }
1427}
1428
1429pub struct PwmChannel {
1437 channel: u8,
1438 gallo: Arc<tokio::sync::Mutex<PicoDeGallo>>,
1439 handle: Handle,
1440}
1441
1442impl embedded_hal::pwm::ErrorType for PwmChannel {
1443 type Error = PwmHalError;
1444}
1445
1446impl embedded_hal::pwm::SetDutyCycle for PwmChannel {
1447 fn max_duty_cycle(&self) -> u16 {
1448 let handle = &self.handle;
1449 let gallo = handle.block_on(self.gallo.lock());
1450 handle
1451 .block_on(gallo.pwm_get_duty_cycle(self.channel))
1452 .map(|info| info.max_duty)
1453 .unwrap_or(u16::MAX)
1454 }
1455
1456 fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> {
1457 let handle = &self.handle;
1458 let gallo = handle.block_on(self.gallo.lock());
1459 handle
1460 .block_on(gallo.pwm_set_duty_cycle(self.channel, duty))
1461 .map_err(PwmHalError::from)
1462 }
1463}
1464
1465#[derive(Debug)]
1471pub enum AdcHalError {
1472 Adc(AdcError),
1474 Comms(String),
1476}
1477
1478impl core::fmt::Display for AdcHalError {
1479 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1480 match self {
1481 Self::Adc(e) => write!(f, "{e}"),
1482 Self::Comms(msg) => write!(f, "communication error: {msg}"),
1483 }
1484 }
1485}
1486
1487impl std::error::Error for AdcHalError {}
1488
1489impl From<PicoDeGalloError<AdcError>> for AdcHalError {
1490 fn from(e: PicoDeGalloError<AdcError>) -> Self {
1491 match e {
1492 PicoDeGalloError::Endpoint(e) => Self::Adc(e),
1493 PicoDeGalloError::Comms(c) => Self::Comms(format!("{c:?}")),
1494 }
1495 }
1496}
1497
1498#[derive(Debug)]
1500pub enum OneWireHalError {
1501 OneWire(OneWireError),
1503 Comms(String),
1505}
1506
1507impl core::fmt::Display for OneWireHalError {
1508 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1509 match self {
1510 Self::OneWire(e) => write!(f, "{e}"),
1511 Self::Comms(msg) => write!(f, "communication error: {msg}"),
1512 }
1513 }
1514}
1515
1516impl std::error::Error for OneWireHalError {}
1517
1518impl From<PicoDeGalloError<OneWireError>> for OneWireHalError {
1519 fn from(e: PicoDeGalloError<OneWireError>) -> Self {
1520 match e {
1521 PicoDeGalloError::Endpoint(e) => Self::OneWire(e),
1522 PicoDeGalloError::Comms(c) => Self::Comms(format!("{c:?}")),
1523 }
1524 }
1525}
1526
1527pub struct OneWire {
1532 gallo: Arc<Mutex<PicoDeGallo>>,
1533 handle: Handle,
1534}
1535
1536impl OneWire {
1537 pub fn reset(&self) -> Result<bool, OneWireHalError> {
1541 if Hal::in_async_context() {
1542 block_in_place(|| self.handle.block_on(self.reset_inner()))
1543 } else {
1544 self.handle.block_on(self.reset_inner())
1545 }
1546 }
1547
1548 async fn reset_inner(&self) -> Result<bool, OneWireHalError> {
1549 self.gallo
1550 .lock()
1551 .await
1552 .onewire_reset()
1553 .await
1554 .map_err(OneWireHalError::from)
1555 }
1556
1557 pub fn read(&self, len: u16) -> Result<Vec<u8>, OneWireHalError> {
1559 if Hal::in_async_context() {
1560 block_in_place(|| self.handle.block_on(self.read_inner(len)))
1561 } else {
1562 self.handle.block_on(self.read_inner(len))
1563 }
1564 }
1565
1566 async fn read_inner(&self, len: u16) -> Result<Vec<u8>, OneWireHalError> {
1567 self.gallo
1568 .lock()
1569 .await
1570 .onewire_read(len)
1571 .await
1572 .map_err(OneWireHalError::from)
1573 }
1574
1575 pub fn write(&self, data: &[u8]) -> Result<(), OneWireHalError> {
1577 if Hal::in_async_context() {
1578 block_in_place(|| self.handle.block_on(self.write_inner(data)))
1579 } else {
1580 self.handle.block_on(self.write_inner(data))
1581 }
1582 }
1583
1584 async fn write_inner(&self, data: &[u8]) -> Result<(), OneWireHalError> {
1585 self.gallo
1586 .lock()
1587 .await
1588 .onewire_write(data)
1589 .await
1590 .map_err(OneWireHalError::from)
1591 }
1592
1593 pub fn write_pullup(
1595 &self,
1596 data: &[u8],
1597 pullup_duration_ms: u16,
1598 ) -> Result<(), OneWireHalError> {
1599 if Hal::in_async_context() {
1600 block_in_place(|| {
1601 self.handle
1602 .block_on(self.write_pullup_inner(data, pullup_duration_ms))
1603 })
1604 } else {
1605 self.handle
1606 .block_on(self.write_pullup_inner(data, pullup_duration_ms))
1607 }
1608 }
1609
1610 async fn write_pullup_inner(
1611 &self,
1612 data: &[u8],
1613 pullup_duration_ms: u16,
1614 ) -> Result<(), OneWireHalError> {
1615 self.gallo
1616 .lock()
1617 .await
1618 .onewire_write_pullup(data, pullup_duration_ms)
1619 .await
1620 .map_err(OneWireHalError::from)
1621 }
1622
1623 pub fn search(&self) -> Result<Option<u64>, OneWireHalError> {
1625 if Hal::in_async_context() {
1626 block_in_place(|| self.handle.block_on(self.search_inner()))
1627 } else {
1628 self.handle.block_on(self.search_inner())
1629 }
1630 }
1631
1632 async fn search_inner(&self) -> Result<Option<u64>, OneWireHalError> {
1633 self.gallo
1634 .lock()
1635 .await
1636 .onewire_search()
1637 .await
1638 .map_err(OneWireHalError::from)
1639 }
1640
1641 pub fn search_next(&self) -> Result<Option<u64>, OneWireHalError> {
1643 if Hal::in_async_context() {
1644 block_in_place(|| self.handle.block_on(self.search_next_inner()))
1645 } else {
1646 self.handle.block_on(self.search_next_inner())
1647 }
1648 }
1649
1650 async fn search_next_inner(&self) -> Result<Option<u64>, OneWireHalError> {
1651 self.gallo
1652 .lock()
1653 .await
1654 .onewire_search_next()
1655 .await
1656 .map_err(OneWireHalError::from)
1657 }
1658}
1659
1660#[cfg(test)]
1661mod tests {
1662 use super::*;
1663
1664 #[test]
1667 fn digital_error_kind_is_other() {
1668 use embedded_hal::digital::Error as _;
1669 let err = GpioHalError::Gpio(GpioError::Other);
1670 assert_eq!(err.kind(), embedded_hal::digital::ErrorKind::Other);
1671 }
1672
1673 #[test]
1674 fn i2c_error_kind_nack() {
1675 use embedded_hal::i2c::Error as _;
1676 let err = I2cHalError::I2c(I2cError::NoAcknowledge);
1677 assert_eq!(
1678 err.kind(),
1679 embedded_hal::i2c::ErrorKind::NoAcknowledge(
1680 embedded_hal::i2c::NoAcknowledgeSource::Unknown
1681 )
1682 );
1683 }
1684
1685 #[test]
1686 fn i2c_error_kind_bus() {
1687 use embedded_hal::i2c::Error as _;
1688 let err = I2cHalError::I2c(I2cError::Bus);
1689 assert_eq!(err.kind(), embedded_hal::i2c::ErrorKind::Bus);
1690 }
1691
1692 #[test]
1693 fn i2c_error_kind_arbitration_loss() {
1694 use embedded_hal::i2c::Error as _;
1695 let err = I2cHalError::I2c(I2cError::ArbitrationLoss);
1696 assert_eq!(err.kind(), embedded_hal::i2c::ErrorKind::ArbitrationLoss);
1697 }
1698
1699 #[test]
1700 fn i2c_error_kind_overrun() {
1701 use embedded_hal::i2c::Error as _;
1702 let err = I2cHalError::I2c(I2cError::Overrun);
1703 assert_eq!(err.kind(), embedded_hal::i2c::ErrorKind::Overrun);
1704 }
1705
1706 #[test]
1707 fn i2c_error_kind_other_for_comms() {
1708 use embedded_hal::i2c::Error as _;
1709 let err = I2cHalError::Comms("USB disconnected".into());
1710 assert_eq!(err.kind(), embedded_hal::i2c::ErrorKind::Other);
1711 }
1712
1713 #[test]
1714 fn spi_error_kind_is_other() {
1715 use embedded_hal::spi::Error as _;
1716 let err = SpiHalError::Spi(SpiError::Other);
1717 assert_eq!(err.kind(), embedded_hal::spi::ErrorKind::Other);
1718 }
1719
1720 #[test]
1721 fn spi_device_error_type_matches_spi_bus() {
1722 fn assert_error_type<T: embedded_hal::spi::ErrorType<Error = SpiHalError>>() {}
1725 assert_error_type::<Spi>();
1726 assert_error_type::<SpiDev>();
1727 }
1728
1729 #[test]
1730 fn spi_device_comms_error_kind_is_other() {
1731 use embedded_hal::spi::Error as _;
1732 let err = SpiHalError::Comms("CS assert failed".into());
1733 assert_eq!(err.kind(), embedded_hal::spi::ErrorKind::Other);
1734 }
1735
1736 #[test]
1737 fn uart_error_kind_invalid_baud_rate() {
1738 use embedded_io::Error as _;
1739 let err = UartHalError::Uart(UartError::InvalidBaudRate);
1740 assert_eq!(err.kind(), embedded_io::ErrorKind::InvalidInput);
1741 }
1742
1743 #[test]
1744 fn uart_error_kind_overrun() {
1745 use embedded_io::Error as _;
1746 let err = UartHalError::Uart(UartError::Overrun);
1747 assert_eq!(err.kind(), embedded_io::ErrorKind::Other);
1748 }
1749
1750 #[test]
1751 fn uart_error_kind_comms() {
1752 use embedded_io::Error as _;
1753 let err = UartHalError::Comms("USB disconnected".into());
1754 assert_eq!(err.kind(), embedded_io::ErrorKind::Other);
1755 }
1756
1757 #[test]
1758 fn uart_hal_error_display() {
1759 let err = UartHalError::Uart(UartError::Framing);
1760 assert_eq!(format!("{err}"), "UART framing error");
1761
1762 let err = UartHalError::Comms("timeout".into());
1763 assert_eq!(format!("{err}"), "communication error: timeout");
1764 }
1765
1766 #[test]
1767 fn uart_hal_error_from_endpoint() {
1768 let e: UartHalError = PicoDeGalloError::Endpoint(UartError::Break).into();
1769 assert!(matches!(e, UartHalError::Uart(UartError::Break)));
1770 }
1771
1772 #[test]
1773 fn uart_hal_error_from_comms() {
1774 let e = UartHalError::Comms("USB disconnected".into());
1775 assert!(matches!(e, UartHalError::Comms(_)));
1776 }
1777
1778 #[test]
1781 fn pwm_error_kind_is_other() {
1782 use embedded_hal::pwm::Error as _;
1783 let err = PwmHalError::Pwm(PwmError::InvalidChannel);
1784 assert_eq!(err.kind(), embedded_hal::pwm::ErrorKind::Other);
1785 }
1786
1787 #[test]
1788 fn pwm_comms_error_kind_is_other() {
1789 use embedded_hal::pwm::Error as _;
1790 let err = PwmHalError::Comms("timeout".into());
1791 assert_eq!(err.kind(), embedded_hal::pwm::ErrorKind::Other);
1792 }
1793
1794 #[test]
1795 fn pwm_hal_error_display_endpoint() {
1796 let err = PwmHalError::Pwm(PwmError::InvalidChannel);
1797 assert_eq!(format!("{err}"), "invalid PWM channel");
1798 }
1799
1800 #[test]
1801 fn pwm_hal_error_display_comms() {
1802 let err = PwmHalError::Comms("USB gone".into());
1803 assert_eq!(format!("{err}"), "communication error: USB gone");
1804 }
1805
1806 #[test]
1809 fn handle_try_current_fails_outside_tokio() {
1810 let result = Handle::try_current();
1814 assert!(result.is_err());
1815 }
1816
1817 #[tokio::test]
1818 async fn handle_try_current_succeeds_inside_tokio() {
1819 let result = Handle::try_current();
1823 assert!(result.is_ok());
1824 }
1825
1826 #[test]
1829 fn delay_ns_does_not_panic() {
1830 use embedded_hal::delay::DelayNs;
1831 let mut delay = Delay;
1832 delay.delay_ns(1);
1834 }
1835
1836 #[tokio::test]
1837 async fn async_delay_ns_does_not_panic() {
1838 use embedded_hal_async::delay::DelayNs;
1839 let mut delay = Delay;
1840 delay.delay_ns(1).await;
1841 }
1842
1843 #[test]
1846 fn adc_hal_error_display_conversion_failed() {
1847 let err = AdcHalError::Adc(AdcError::ConversionFailed);
1848 assert_eq!(format!("{err}"), "ADC conversion failed");
1849 }
1850
1851 #[test]
1852 fn adc_hal_error_display_comms() {
1853 let err = AdcHalError::Comms("timeout".into());
1854 assert_eq!(format!("{err}"), "communication error: timeout");
1855 }
1856
1857 #[test]
1858 fn adc_hal_error_from_endpoint() {
1859 let e: PicoDeGalloError<AdcError> = PicoDeGalloError::Endpoint(AdcError::Other);
1860 let hal_err = AdcHalError::from(e);
1861 match hal_err {
1862 AdcHalError::Adc(AdcError::Other) => {}
1863 other => panic!("expected Adc(Other), got {other:?}"),
1864 }
1865 }
1866
1867 #[test]
1870 fn onewire_hal_error_display_no_presence() {
1871 let err = OneWireHalError::OneWire(OneWireError::NoPresence);
1872 assert_eq!(format!("{err}"), "no device present on 1-Wire bus");
1873 }
1874
1875 #[test]
1876 fn onewire_hal_error_display_comms() {
1877 let err = OneWireHalError::Comms("timeout".into());
1878 assert_eq!(format!("{err}"), "communication error: timeout");
1879 }
1880
1881 #[test]
1882 fn onewire_hal_error_from_endpoint() {
1883 let e: PicoDeGalloError<OneWireError> = PicoDeGalloError::Endpoint(OneWireError::BusError);
1884 let hal_err = OneWireHalError::from(e);
1885 match hal_err {
1886 OneWireHalError::OneWire(OneWireError::BusError) => {}
1887 other => panic!("expected OneWire(BusError), got {other:?}"),
1888 }
1889 }
1890}