1#![cfg_attr(not(feature = "use-std"), no_std)]
57
58use postcard_rpc::{TopicDirection, endpoints, topics};
59use postcard_schema::Schema;
60use serde::{Deserialize, Serialize};
61
62include!(concat!(env!("OUT_DIR"), "/schema_version.rs"));
64
65pub const MICROSOFT_VID: u16 = 0x045e;
67
68pub const PICO_DE_GALLO_PID: u16 = 0x067d;
70
71pub const MAX_TRANSFER_SIZE: usize = 4096;
75
76pub type I2cWriteResponse = Result<(), I2cError>;
80
81#[cfg(feature = "use-std")]
84pub type I2cReadResponse<'a> = Result<Vec<u8>, I2cError>;
85#[cfg(not(feature = "use-std"))]
88pub type I2cReadResponse<'a> = Result<&'a [u8], I2cError>;
89
90#[cfg(feature = "use-std")]
93pub type I2cWriteReadResponse<'a> = Result<Vec<u8>, I2cError>;
94#[cfg(not(feature = "use-std"))]
97pub type I2cWriteReadResponse<'a> = Result<&'a [u8], I2cError>;
98
99pub type SpiWriteResponse = Result<(), SpiError>;
101
102#[cfg(feature = "use-std")]
105pub type SpiReadResponse<'a> = Result<Vec<u8>, SpiError>;
106#[cfg(not(feature = "use-std"))]
109pub type SpiReadResponse<'a> = Result<&'a [u8], SpiError>;
110
111pub type SpiFlushResponse = Result<(), SpiError>;
113
114#[cfg(feature = "use-std")]
117pub type SpiTransferResponse<'a> = Result<Vec<u8>, SpiError>;
118#[cfg(not(feature = "use-std"))]
121pub type SpiTransferResponse<'a> = Result<&'a [u8], SpiError>;
122
123pub type GpioGetResponse = Result<GpioState, GpioError>;
125pub type GpioPutResponse = Result<(), GpioError>;
127pub type GpioWaitResponse = Result<(), GpioError>;
129pub type GpioSetConfigurationResponse = Result<(), GpioError>;
131pub type GpioSubscribeResponse = Result<(), GpioError>;
133pub type GpioUnsubscribeResponse = Result<(), GpioError>;
135pub type I2cSetConfigurationResponse = Result<(), I2cConfigError>;
137#[cfg(feature = "use-std")]
141pub type I2cScanResponse<'a> = Result<Vec<u8>, I2cError>;
142#[cfg(not(feature = "use-std"))]
146pub type I2cScanResponse<'a> = Result<&'a [u8], I2cError>;
147pub type SpiSetConfigurationResponse = Result<(), SpiConfigError>;
149
150pub type I2cGetConfigurationResponse = I2cFrequency;
154
155pub type SpiGetConfigurationResponse = SpiConfigurationInfo;
159
160pub type UartWriteResponse = Result<(), UartError>;
162
163#[cfg(feature = "use-std")]
166pub type UartReadResponse<'a> = Result<Vec<u8>, UartError>;
167#[cfg(not(feature = "use-std"))]
170pub type UartReadResponse<'a> = Result<&'a [u8], UartError>;
171
172pub type UartFlushResponse = Result<(), UartError>;
174
175pub type UartSetConfigurationResponse = Result<(), UartConfigError>;
177
178pub type UartGetConfigurationResponse = Result<UartConfigurationInfo, UartError>;
182
183pub type PwmSetDutyCycleResponse = Result<(), PwmError>;
185pub type PwmGetDutyCycleResponse = Result<PwmDutyCycleInfo, PwmError>;
187pub type PwmEnableResponse = Result<(), PwmError>;
189pub type PwmDisableResponse = Result<(), PwmError>;
191pub type PwmSetConfigurationResponse = Result<(), PwmConfigError>;
193pub type PwmGetConfigurationResponse = Result<PwmConfigurationInfo, PwmError>;
195
196pub type AdcReadResponse = Result<u16, AdcError>;
198pub type AdcGetConfigurationResponse = Result<AdcConfigurationInfo, AdcError>;
200
201pub type OneWireResetResponse = Result<bool, OneWireError>;
204
205#[cfg(feature = "use-std")]
208pub type OneWireReadResponse<'a> = Result<Vec<u8>, OneWireError>;
209#[cfg(not(feature = "use-std"))]
212pub type OneWireReadResponse<'a> = Result<&'a [u8], OneWireError>;
213
214pub type OneWireWriteResponse = Result<(), OneWireError>;
216
217pub type OneWireWritePullupResponse = Result<(), OneWireError>;
219
220pub type OneWireSearchResponse = Result<Option<u64>, OneWireError>;
224
225#[cfg(feature = "use-std")]
229pub type I2cBatchResponse<'a> = Result<Vec<u8>, I2cBatchError>;
230#[cfg(not(feature = "use-std"))]
234pub type I2cBatchResponse<'a> = Result<&'a [u8], I2cBatchError>;
235
236#[cfg(feature = "use-std")]
240pub type SpiBatchResponse<'a> = Result<Vec<u8>, SpiBatchError>;
241#[cfg(not(feature = "use-std"))]
245pub type SpiBatchResponse<'a> = Result<&'a [u8], SpiBatchError>;
246
247endpoints! {
248 list = ENDPOINT_LIST;
249 | EndpointTy | RequestTy | ResponseTy | Path |
250 | ---------- | --------- | ---------- | ---- |
251 | PingEndpoint | u32 | u32 | "ping" |
252 | I2cRead | I2cReadRequest | I2cReadResponse<'a> | "i2c/read" |
253 | I2cWrite | I2cWriteRequest<'a> | I2cWriteResponse | "i2c/write" |
254 | I2cWriteRead | I2cWriteReadRequest<'a> | I2cWriteReadResponse<'b> | "i2c/write-read" |
255 | SpiRead | SpiReadRequest | SpiReadResponse<'a> | "spi/read" |
256 | SpiWrite | SpiWriteRequest<'a> | SpiWriteResponse | "spi/write" |
257 | SpiFlush | () | SpiFlushResponse | "spi/flush" |
258 | SpiTransfer | SpiTransferRequest<'a> | SpiTransferResponse<'b> | "spi/transfer" |
259 | GpioGet | GpioGetRequest | GpioGetResponse | "gpio/get" |
260 | GpioPut | GpioPutRequest | GpioPutResponse | "gpio/put" |
261 | GpioWaitForHigh | GpioWaitRequest | GpioWaitResponse | "gpio/wait-high" |
262 | GpioWaitForLow | GpioWaitRequest | GpioWaitResponse | "gpio/wait-low" |
263 | GpioWaitForRising | GpioWaitRequest | GpioWaitResponse | "gpio/wait-rising" |
264 | GpioWaitForFalling | GpioWaitRequest | GpioWaitResponse | "gpio/wait-falling" |
265 | GpioWaitForAny | GpioWaitRequest | GpioWaitResponse | "gpio/wait-any" |
266 | I2cSetConfiguration | I2cSetConfigurationRequest | I2cSetConfigurationResponse | "i2c/set-config" |
267 | I2cScan | I2cScanRequest | I2cScanResponse<'a> | "i2c/scan" |
268 | SpiSetConfiguration | SpiSetConfigurationRequest | SpiSetConfigurationResponse | "spi/set-config" |
269 | GpioSetConfiguration | GpioSetConfigurationRequest | GpioSetConfigurationResponse | "gpio/set-config" |
270 | I2cGetConfiguration | () | I2cGetConfigurationResponse | "i2c/get-config" |
271 | SpiGetConfiguration | () | SpiGetConfigurationResponse | "spi/get-config" |
272 | UartRead | UartReadRequest | UartReadResponse<'a> | "uart/read" |
273 | UartWrite | UartWriteRequest<'a> | UartWriteResponse | "uart/write" |
274 | UartFlush | () | UartFlushResponse | "uart/flush" |
275 | UartSetConfiguration | UartSetConfigurationRequest | UartSetConfigurationResponse | "uart/set-config" |
276 | UartGetConfiguration | () | UartGetConfigurationResponse | "uart/get-config" |
277 | PwmSetDutyCycle | PwmSetDutyCycleRequest | PwmSetDutyCycleResponse | "pwm/set-duty-cycle" |
278 | PwmGetDutyCycle | PwmGetDutyCycleRequest | PwmGetDutyCycleResponse | "pwm/get-duty-cycle" |
279 | PwmEnable | PwmEnableRequest | PwmEnableResponse | "pwm/enable" |
280 | PwmDisable | PwmDisableRequest | PwmDisableResponse | "pwm/disable" |
281 | PwmSetConfiguration | PwmSetConfigurationRequest | PwmSetConfigurationResponse | "pwm/set-config" |
282 | PwmGetConfiguration | PwmGetConfigurationRequest | PwmGetConfigurationResponse | "pwm/get-config" |
283 | AdcRead | AdcReadRequest | AdcReadResponse | "adc/read" |
284 | AdcGetConfiguration | () | AdcGetConfigurationResponse | "adc/get-config" |
285 | GpioSubscribe | GpioSubscribeRequest | GpioSubscribeResponse | "gpio/subscribe" |
286 | GpioUnsubscribe | GpioUnsubscribeRequest | GpioUnsubscribeResponse | "gpio/unsubscribe" |
287 | I2cBatch | I2cBatchRequest<'a> | I2cBatchResponse<'b> | "i2c/batch" |
288 | SpiBatch | SpiBatchRequest<'a> | SpiBatchResponse<'b> | "spi/batch" |
289 | OneWireReset | () | OneWireResetResponse | "onewire/reset" |
290 | OneWireRead | OneWireReadRequest | OneWireReadResponse<'a> | "onewire/read" |
291 | OneWireWrite | OneWireWriteRequest<'a> | OneWireWriteResponse | "onewire/write" |
292 | OneWireWritePullup | OneWireWritePullupRequest<'a> | OneWireWritePullupResponse | "onewire/write-pullup" |
293 | OneWireSearch | () | OneWireSearchResponse | "onewire/search" |
294 | OneWireSearchNext | () | OneWireSearchResponse | "onewire/search-next" |
295 | Version | () | VersionInfo | "version" |
296 | GetDeviceInfo | () | DeviceInfo | "device/info" |
297}
298
299topics! {
300 list = TOPICS_IN_LIST;
301 direction = TopicDirection::ToServer;
302 | TopicTy | MessageTy | Path |
303 | ------- | --------- | ---- |
304}
305
306topics! {
307 list = TOPICS_OUT_LIST;
308 direction = TopicDirection::ToClient;
309 | TopicTy | MessageTy | Path | Cfg |
310 | ------- | --------- | ---- | --- |
311 | GpioEventTopic | GpioEvent | "gpio/event" | |
312}
313
314#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
322pub struct I2cWriteReadRequest<'a> {
323 pub address: u8,
325 pub contents: &'a [u8],
327 pub count: u16,
329}
330
331#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq)]
341pub enum I2cError {
342 Bus,
344 NoAcknowledge,
346 ArbitrationLoss,
348 Overrun,
350 BufferTooLong,
352 AddressOutOfRange,
354 Other,
356}
357
358impl core::fmt::Display for I2cError {
359 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
360 match self {
361 Self::Bus => write!(f, "I2C bus error"),
362 Self::NoAcknowledge => write!(f, "no acknowledge from target"),
363 Self::ArbitrationLoss => write!(f, "I2C arbitration loss"),
364 Self::Overrun => write!(f, "I2C data overrun"),
365 Self::BufferTooLong => write!(f, "buffer exceeds firmware limit"),
366 Self::AddressOutOfRange => write!(f, "I2C address out of range"),
367 Self::Other => write!(f, "I2C error"),
368 }
369 }
370}
371
372#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
374pub struct I2cReadRequest {
375 pub address: u8,
377 pub count: u16,
379}
380
381#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
383pub struct I2cWriteRequest<'a> {
384 pub address: u8,
386 pub contents: &'a [u8],
388}
389
390#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
395pub struct I2cScanRequest {
396 pub include_reserved: bool,
399}
400
401#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq)]
410pub enum SpiError {
411 BufferTooLong,
413 Other,
415}
416
417impl core::fmt::Display for SpiError {
418 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
419 match self {
420 Self::BufferTooLong => write!(f, "buffer exceeds firmware limit"),
421 Self::Other => write!(f, "SPI error"),
422 }
423 }
424}
425
426#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
428pub struct SpiReadRequest {
429 pub count: u16,
431}
432
433#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
435pub struct SpiWriteRequest<'a> {
436 pub contents: &'a [u8],
438}
439
440#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
445pub struct SpiTransferRequest<'a> {
446 pub contents: &'a [u8],
448}
449
450pub type SpiTransferError = SpiError;
455
456#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
460pub struct GpioGetRequest {
461 pub pin: u8,
463}
464
465#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq)]
472pub enum GpioError {
473 InvalidPin,
475 Other,
477 WrongDirection,
479 PinMonitored,
482 PinNotMonitored,
484}
485
486impl core::fmt::Display for GpioError {
487 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
488 match self {
489 Self::InvalidPin => write!(f, "invalid GPIO pin number"),
490 Self::Other => write!(f, "GPIO error"),
491 Self::WrongDirection => write!(f, "GPIO pin configured in wrong direction"),
492 Self::PinMonitored => write!(f, "GPIO pin is being monitored for events"),
493 Self::PinNotMonitored => write!(f, "GPIO pin is not monitored"),
494 }
495 }
496}
497
498#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
500pub struct GpioPutRequest {
501 pub pin: u8,
503 pub state: GpioState,
505}
506
507#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq, Hash)]
512pub enum GpioState {
513 Low,
515 High,
517}
518
519impl From<bool> for GpioState {
520 fn from(value: bool) -> Self {
521 if value {
522 GpioState::High
523 } else {
524 GpioState::Low
525 }
526 }
527}
528
529impl From<GpioState> for bool {
530 fn from(state: GpioState) -> Self {
531 matches!(state, GpioState::High)
532 }
533}
534
535#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
537pub struct GpioWaitRequest {
538 pub pin: u8,
540}
541
542#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq, Hash)]
547#[repr(u8)]
548pub enum GpioDirection {
549 Input = 0,
551 Output = 1,
553}
554
555#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq, Hash)]
560#[repr(u8)]
561pub enum GpioPull {
562 None = 0,
564 Up = 1,
566 Down = 2,
568}
569
570#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
576pub struct GpioSetConfigurationRequest {
577 pub pin: u8,
579 pub direction: GpioDirection,
581 pub pull: GpioPull,
583}
584
585#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq, Hash)]
596#[repr(u8)]
597pub enum GpioEdge {
598 Rising = 0,
600 Falling = 1,
602 Any = 2,
604}
605
606impl core::fmt::Display for GpioEdge {
607 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
608 match self {
609 Self::Rising => write!(f, "rising"),
610 Self::Falling => write!(f, "falling"),
611 Self::Any => write!(f, "any"),
612 }
613 }
614}
615
616#[derive(Serialize, Deserialize, Schema, Debug, Clone, PartialEq, Eq)]
625pub struct GpioEvent {
626 pub pin: u8,
628 pub edge: GpioEdge,
630 pub state: GpioState,
633 pub timestamp_us: u64,
635}
636
637#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
644pub struct GpioSubscribeRequest {
645 pub pin: u8,
647 pub edge: GpioEdge,
649}
650
651#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
656pub struct GpioUnsubscribeRequest {
657 pub pin: u8,
659}
660
661#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
668pub struct I2cSetConfigurationRequest {
669 pub frequency: I2cFrequency,
671}
672
673#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq)]
680#[repr(u8)]
681pub enum I2cFrequency {
682 Standard = 0,
684 Fast = 1,
686 FastPlus = 2,
688}
689
690pub type I2cConfigError = I2cError;
695
696#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
701pub struct SpiSetConfigurationRequest {
702 pub spi_frequency: u32,
704 pub spi_phase: SpiPhase,
706 pub spi_polarity: SpiPolarity,
708}
709
710#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq, Hash)]
715pub enum SpiPhase {
716 CaptureOnFirstTransition = 0,
718 CaptureOnSecondTransition = 1,
720}
721
722#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq, Hash)]
727pub enum SpiPolarity {
728 IdleLow = 0,
730 IdleHigh = 1,
732}
733
734pub type SpiConfigError = SpiError;
739
740#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq)]
749pub enum UartError {
750 BufferTooLong,
752 Overrun,
755 Break,
757 Parity,
759 Framing,
761 InvalidBaudRate,
763 Other,
765 Unsupported,
768}
769
770impl core::fmt::Display for UartError {
771 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
772 match self {
773 Self::BufferTooLong => write!(f, "buffer exceeds firmware limit"),
774 Self::Overrun => write!(f, "UART receiver overrun"),
775 Self::Break => write!(f, "UART break condition"),
776 Self::Parity => write!(f, "UART parity error"),
777 Self::Framing => write!(f, "UART framing error"),
778 Self::InvalidBaudRate => write!(f, "invalid baud rate"),
779 Self::Other => write!(f, "UART error"),
780 Self::Unsupported => write!(f, "UART not supported on this hardware"),
781 }
782 }
783}
784
785#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
792pub struct UartReadRequest {
793 pub count: u16,
795 pub timeout_ms: u32,
798}
799
800#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
802pub struct UartWriteRequest<'a> {
803 pub contents: &'a [u8],
805}
806
807#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
817pub struct UartSetConfigurationRequest {
818 pub baud_rate: u32,
820}
821
822pub type UartConfigError = UartError;
827
828#[derive(Serialize, Deserialize, Schema, Debug, Clone, PartialEq, Eq)]
833pub struct UartConfigurationInfo {
834 pub baud_rate: u32,
836}
837
838#[derive(Serialize, Deserialize, Schema, Debug, Clone, PartialEq, Eq)]
843pub struct SpiConfigurationInfo {
844 pub spi_frequency: u32,
846 pub spi_phase: SpiPhase,
848 pub spi_polarity: SpiPolarity,
850}
851
852pub const NUM_PWM_CHANNELS: usize = 4;
859
860#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq)]
867pub enum PwmError {
868 InvalidChannel,
871 InvalidDutyCycle,
874 InvalidConfiguration,
877 Other,
879}
880
881impl core::fmt::Display for PwmError {
882 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
883 match self {
884 Self::InvalidChannel => write!(f, "invalid PWM channel"),
885 Self::InvalidDutyCycle => write!(f, "duty cycle exceeds maximum"),
886 Self::InvalidConfiguration => write!(f, "invalid PWM configuration"),
887 Self::Other => write!(f, "PWM error"),
888 }
889 }
890}
891
892#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
898pub struct PwmSetDutyCycleRequest {
899 pub channel: u8,
901 pub duty: u16,
903}
904
905#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
907pub struct PwmGetDutyCycleRequest {
908 pub channel: u8,
910}
911
912#[derive(Serialize, Deserialize, Schema, Debug, Clone, PartialEq, Eq)]
917pub struct PwmDutyCycleInfo {
918 pub max_duty: u16,
920 pub current_duty: u16,
922}
923
924#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
929pub struct PwmEnableRequest {
930 pub channel: u8,
932}
933
934#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
939pub struct PwmDisableRequest {
940 pub channel: u8,
942}
943
944#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
952pub struct PwmSetConfigurationRequest {
953 pub channel: u8,
955 pub frequency_hz: u32,
957 pub phase_correct: bool,
960}
961
962#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
964pub struct PwmGetConfigurationRequest {
965 pub channel: u8,
967}
968
969pub type PwmConfigError = PwmError;
974
975#[derive(Serialize, Deserialize, Schema, Debug, Clone, PartialEq, Eq)]
980pub struct PwmConfigurationInfo {
981 pub frequency_hz: u32,
984 pub phase_correct: bool,
986 pub enabled: bool,
988}
989
990pub const NUM_ADC_GPIO_CHANNELS: usize = 4;
997
998pub const ADC_RESOLUTION_BITS: u8 = 12;
1002
1003pub const ADC_NOMINAL_REFERENCE_MV: u16 = 3300;
1009
1010#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq)]
1021pub enum AdcChannel {
1022 Adc0 = 0,
1024 Adc1 = 1,
1026 Adc2 = 2,
1028 Adc3 = 3,
1030}
1031
1032impl core::fmt::Display for AdcChannel {
1033 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1034 match self {
1035 Self::Adc0 => write!(f, "ADC0 (GPIO26)"),
1036 Self::Adc1 => write!(f, "ADC1 (GPIO27)"),
1037 Self::Adc2 => write!(f, "ADC2 (GPIO28)"),
1038 Self::Adc3 => write!(f, "ADC3 (GPIO29)"),
1039 }
1040 }
1041}
1042
1043#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq)]
1051pub enum AdcError {
1052 ConversionFailed,
1054 Other,
1056 Unsupported,
1059}
1060
1061impl core::fmt::Display for AdcError {
1062 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1063 match self {
1064 Self::ConversionFailed => write!(f, "ADC conversion failed"),
1065 Self::Other => write!(f, "ADC error"),
1066 Self::Unsupported => write!(f, "ADC not supported on this hardware"),
1067 }
1068 }
1069}
1070
1071pub type AdcConfigError = AdcError;
1076
1077#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
1082pub struct AdcReadRequest {
1083 pub channel: AdcChannel,
1085}
1086
1087#[derive(Serialize, Deserialize, Schema, Debug, Clone, PartialEq, Eq)]
1092pub struct AdcConfigurationInfo {
1093 pub resolution_bits: u8,
1095 pub nominal_reference_mv: u16,
1100 pub num_gpio_channels: u8,
1102}
1103
1104#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq)]
1113pub enum OneWireError {
1114 NoPresence,
1116 BusError,
1118 BufferTooLong,
1120 Other,
1122 Unsupported,
1125}
1126
1127impl core::fmt::Display for OneWireError {
1128 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1129 match self {
1130 Self::NoPresence => write!(f, "no device present on 1-Wire bus"),
1131 Self::BusError => write!(f, "1-Wire bus error"),
1132 Self::BufferTooLong => write!(f, "buffer exceeds firmware limit"),
1133 Self::Other => write!(f, "1-Wire error"),
1134 Self::Unsupported => write!(f, "1-Wire not supported on this hardware"),
1135 }
1136 }
1137}
1138
1139#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
1144pub struct OneWireReadRequest {
1145 pub len: u16,
1147}
1148
1149#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
1155pub struct OneWireWriteRequest<'a> {
1156 pub data: &'a [u8],
1158}
1159
1160#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
1167pub struct OneWireWritePullupRequest<'a> {
1168 pub data: &'a [u8],
1170 pub pullup_duration_ms: u16,
1172}
1173
1174pub const MAX_BATCH_OPS: usize = 64;
1179
1180#[derive(Serialize, Deserialize, Schema, Debug, Clone, PartialEq)]
1189pub enum I2cBatchOp<'a> {
1190 Read { len: u16 },
1192 Write {
1194 #[serde(borrow)]
1195 data: &'a [u8],
1196 },
1197}
1198
1199#[derive(Serialize, Deserialize, Schema, Debug, Clone, PartialEq)]
1208pub enum SpiBatchOp<'a> {
1209 Read { len: u16 },
1211 Write {
1213 #[serde(borrow)]
1214 data: &'a [u8],
1215 },
1216 Transfer {
1218 #[serde(borrow)]
1219 data: &'a [u8],
1220 },
1221 DelayNs { ns: u32 },
1223}
1224
1225#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
1246pub struct I2cBatchRequest<'a> {
1247 pub address: u8,
1249 pub count: u16,
1251 pub ops: &'a [u8],
1253}
1254
1255#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq)]
1262pub struct I2cBatchError {
1263 pub failed_op: u16,
1265 pub kind: I2cError,
1267}
1268
1269impl core::fmt::Display for I2cBatchError {
1270 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1271 write!(
1272 f,
1273 "I2C batch operation {} failed: {}",
1274 self.failed_op, self.kind
1275 )
1276 }
1277}
1278
1279#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
1297pub struct SpiBatchRequest<'a> {
1298 pub cs_pin: u8,
1302 pub count: u16,
1304 pub ops: &'a [u8],
1306}
1307
1308#[derive(Serialize, Deserialize, Schema, Debug, Clone, Copy, PartialEq, Eq)]
1313pub struct SpiBatchError {
1314 pub failed_op: u16,
1316 pub kind: SpiError,
1318}
1319
1320impl core::fmt::Display for SpiBatchError {
1321 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1322 write!(
1323 f,
1324 "SPI batch operation {} failed: {}",
1325 self.failed_op, self.kind
1326 )
1327 }
1328}
1329
1330#[cfg(feature = "use-std")]
1338pub fn encode_i2c_batch_ops(ops: &[I2cBatchOp<'_>]) -> Vec<u8> {
1339 assert!(ops.len() <= MAX_BATCH_OPS, "too many batch operations");
1340 let mut buf = Vec::new();
1341 let mut tmp = [0u8; 128];
1342 for op in ops {
1343 let encoded = postcard::to_slice(op, &mut tmp).expect("I2cBatchOp encode failed");
1344 buf.extend_from_slice(encoded);
1345 }
1346 buf
1347}
1348
1349#[cfg(feature = "use-std")]
1357pub fn encode_spi_batch_ops(ops: &[SpiBatchOp<'_>]) -> Vec<u8> {
1358 assert!(ops.len() <= MAX_BATCH_OPS, "too many batch operations");
1359 let mut buf = Vec::new();
1360 let mut tmp = [0u8; 128];
1361 for op in ops {
1362 let encoded = postcard::to_slice(op, &mut tmp).expect("SpiBatchOp encode failed");
1363 buf.extend_from_slice(encoded);
1364 }
1365 buf
1366}
1367
1368pub fn i2c_batch_response_len(ops: &[I2cBatchOp<'_>]) -> usize {
1371 ops.iter()
1372 .map(|op| match op {
1373 I2cBatchOp::Read { len } => *len as usize,
1374 I2cBatchOp::Write { .. } => 0,
1375 })
1376 .sum()
1377}
1378
1379pub fn spi_batch_response_len(ops: &[SpiBatchOp<'_>]) -> usize {
1382 ops.iter()
1383 .map(|op| match op {
1384 SpiBatchOp::Read { len } => *len as usize,
1385 SpiBatchOp::Transfer { data } => data.len(),
1386 _ => 0,
1387 })
1388 .sum()
1389}
1390
1391#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
1394pub struct VersionInfo {
1395 pub major: u16,
1397 pub minor: u16,
1399 pub patch: u32,
1401}
1402
1403#[derive(Serialize, Deserialize, Schema, Debug, PartialEq, Eq, Clone, Copy)]
1423pub struct Capabilities(pub u64);
1424
1425impl Capabilities {
1426 pub const NONE: Self = Self(0);
1428 pub const I2C: Self = Self(1 << 0);
1430 pub const SPI: Self = Self(1 << 1);
1432 pub const UART: Self = Self(1 << 2);
1434 pub const GPIO: Self = Self(1 << 3);
1436 pub const PWM: Self = Self(1 << 4);
1438 pub const ADC: Self = Self(1 << 5);
1440 pub const ONEWIRE: Self = Self(1 << 6);
1442
1443 pub const fn contains(self, other: Self) -> bool {
1445 (self.0 & other.0) == other.0
1446 }
1447
1448 pub const fn bits(self) -> u64 {
1450 self.0
1451 }
1452}
1453
1454impl core::ops::BitOr for Capabilities {
1455 type Output = Self;
1456
1457 fn bitor(self, rhs: Self) -> Self {
1458 Self(self.0 | rhs.0)
1459 }
1460}
1461
1462impl core::ops::BitAnd for Capabilities {
1463 type Output = Self;
1464
1465 fn bitand(self, rhs: Self) -> Self {
1466 Self(self.0 & rhs.0)
1467 }
1468}
1469
1470#[derive(Serialize, Deserialize, Schema, Debug, PartialEq)]
1477pub struct DeviceInfo {
1478 pub fw_major: u16,
1480 pub fw_minor: u16,
1482 pub fw_patch: u32,
1484 pub schema_major: u16,
1486 pub schema_minor: u16,
1488 pub schema_patch: u32,
1490 pub hw_version: u8,
1492 pub capabilities: Capabilities,
1494}
1495
1496#[cfg(test)]
1497mod tests {
1498 use super::*;
1499 use postcard::{from_bytes, to_allocvec};
1500
1501 #[test]
1504 fn i2c_read_request_round_trip() {
1505 let req = I2cReadRequest {
1506 address: 0x48,
1507 count: 4,
1508 };
1509 let bytes = to_allocvec(&req).unwrap();
1510 let decoded: I2cReadRequest = from_bytes(&bytes).unwrap();
1511 assert_eq!(req, decoded);
1512 }
1513
1514 #[test]
1515 fn i2c_write_request_round_trip() {
1516 let data = [0xDE, 0xAD, 0xBE, 0xEF];
1517 let req = I2cWriteRequest {
1518 address: 0x50,
1519 contents: &data,
1520 };
1521 let bytes = to_allocvec(&req).unwrap();
1522 let decoded: I2cWriteRequest = from_bytes(&bytes).unwrap();
1523 assert_eq!(req, decoded);
1524 }
1525
1526 #[test]
1527 fn i2c_write_read_request_round_trip() {
1528 let data = [0x01, 0x02];
1529 let req = I2cWriteReadRequest {
1530 address: 0x68,
1531 contents: &data,
1532 count: 6,
1533 };
1534 let bytes = to_allocvec(&req).unwrap();
1535 let decoded: I2cWriteReadRequest = from_bytes(&bytes).unwrap();
1536 assert_eq!(req, decoded);
1537 }
1538
1539 #[test]
1540 fn i2c_read_request_max_count() {
1541 let req = I2cReadRequest {
1542 address: 0x7F,
1543 count: u16::MAX,
1544 };
1545 let bytes = to_allocvec(&req).unwrap();
1546 let decoded: I2cReadRequest = from_bytes(&bytes).unwrap();
1547 assert_eq!(req, decoded);
1548 }
1549
1550 #[test]
1553 fn spi_read_request_round_trip() {
1554 let req = SpiReadRequest { count: 128 };
1555 let bytes = to_allocvec(&req).unwrap();
1556 let decoded: SpiReadRequest = from_bytes(&bytes).unwrap();
1557 assert_eq!(req, decoded);
1558 }
1559
1560 #[test]
1561 fn spi_write_request_round_trip() {
1562 let data = [0xCA, 0xFE];
1563 let req = SpiWriteRequest { contents: &data };
1564 let bytes = to_allocvec(&req).unwrap();
1565 let decoded: SpiWriteRequest = from_bytes(&bytes).unwrap();
1566 assert_eq!(req, decoded);
1567 }
1568
1569 #[test]
1570 fn spi_transfer_request_round_trip() {
1571 let data = [0x01, 0x02, 0x03, 0x04];
1572 let req = SpiTransferRequest { contents: &data };
1573 let bytes = to_allocvec(&req).unwrap();
1574 let decoded: SpiTransferRequest = from_bytes(&bytes).unwrap();
1575 assert_eq!(req, decoded);
1576 }
1577
1578 #[test]
1579 #[cfg(feature = "use-std")]
1580 fn spi_transfer_request_max_size() {
1581 let data = vec![0xAA; MAX_TRANSFER_SIZE];
1582 let req = SpiTransferRequest { contents: &data };
1583 let bytes = to_allocvec(&req).unwrap();
1584 let decoded: SpiTransferRequest = from_bytes(&bytes).unwrap();
1585 assert_eq!(req, decoded);
1586 }
1587
1588 #[test]
1591 fn gpio_get_request_round_trip() {
1592 for pin in 0..8u8 {
1593 let req = GpioGetRequest { pin };
1594 let bytes = to_allocvec(&req).unwrap();
1595 let decoded: GpioGetRequest = from_bytes(&bytes).unwrap();
1596 assert_eq!(req, decoded);
1597 }
1598 }
1599
1600 #[test]
1601 fn gpio_put_request_round_trip() {
1602 for state in [GpioState::Low, GpioState::High] {
1603 let req = GpioPutRequest { pin: 3, state };
1604 let bytes = to_allocvec(&req).unwrap();
1605 let decoded: GpioPutRequest = from_bytes(&bytes).unwrap();
1606 assert_eq!(req, decoded);
1607 }
1608 }
1609
1610 #[test]
1611 fn gpio_wait_request_round_trip() {
1612 let req = GpioWaitRequest { pin: 7 };
1613 let bytes = to_allocvec(&req).unwrap();
1614 let decoded: GpioWaitRequest = from_bytes(&bytes).unwrap();
1615 assert_eq!(req, decoded);
1616 }
1617
1618 #[test]
1619 fn gpio_state_round_trip() {
1620 for state in [GpioState::Low, GpioState::High] {
1621 let bytes = to_allocvec(&state).unwrap();
1622 let decoded: GpioState = from_bytes(&bytes).unwrap();
1623 assert_eq!(state, decoded);
1624 }
1625 }
1626
1627 #[test]
1628 fn gpio_state_from_bool() {
1629 assert_eq!(GpioState::from(true), GpioState::High);
1630 assert_eq!(GpioState::from(false), GpioState::Low);
1631 }
1632
1633 #[test]
1634 fn bool_from_gpio_state() {
1635 assert!(bool::from(GpioState::High));
1636 assert!(!bool::from(GpioState::Low));
1637 }
1638
1639 #[test]
1642 fn i2c_set_configuration_request_round_trip() {
1643 let req = I2cSetConfigurationRequest {
1644 frequency: I2cFrequency::Fast,
1645 };
1646 let bytes = to_allocvec(&req).unwrap();
1647 let decoded: I2cSetConfigurationRequest = from_bytes(&bytes).unwrap();
1648 assert_eq!(req, decoded);
1649 }
1650
1651 #[test]
1652 fn spi_set_configuration_request_round_trip() {
1653 let req = SpiSetConfigurationRequest {
1654 spi_frequency: 1_000_000,
1655 spi_phase: SpiPhase::CaptureOnSecondTransition,
1656 spi_polarity: SpiPolarity::IdleHigh,
1657 };
1658 let bytes = to_allocvec(&req).unwrap();
1659 let decoded: SpiSetConfigurationRequest = from_bytes(&bytes).unwrap();
1660 assert_eq!(req, decoded);
1661 }
1662
1663 #[test]
1664 fn spi_phase_round_trip() {
1665 for phase in [
1666 SpiPhase::CaptureOnFirstTransition,
1667 SpiPhase::CaptureOnSecondTransition,
1668 ] {
1669 let bytes = to_allocvec(&phase).unwrap();
1670 let decoded: SpiPhase = from_bytes(&bytes).unwrap();
1671 assert_eq!(phase, decoded);
1672 }
1673 }
1674
1675 #[test]
1676 fn spi_polarity_round_trip() {
1677 for pol in [SpiPolarity::IdleLow, SpiPolarity::IdleHigh] {
1678 let bytes = to_allocvec(&pol).unwrap();
1679 let decoded: SpiPolarity = from_bytes(&bytes).unwrap();
1680 assert_eq!(pol, decoded);
1681 }
1682 }
1683
1684 #[test]
1687 fn version_info_round_trip() {
1688 let ver = VersionInfo {
1689 major: 1,
1690 minor: 2,
1691 patch: 42,
1692 };
1693 let bytes = to_allocvec(&ver).unwrap();
1694 let decoded: VersionInfo = from_bytes(&bytes).unwrap();
1695 assert_eq!(ver, decoded);
1696 }
1697
1698 #[test]
1701 fn i2c_error_variants_round_trip() {
1702 for err in [
1703 I2cError::Bus,
1704 I2cError::NoAcknowledge,
1705 I2cError::ArbitrationLoss,
1706 I2cError::Overrun,
1707 I2cError::BufferTooLong,
1708 I2cError::AddressOutOfRange,
1709 I2cError::Other,
1710 ] {
1711 let bytes = to_allocvec(&err).unwrap();
1712 let decoded: I2cError = from_bytes(&bytes).unwrap();
1713 assert_eq!(err, decoded);
1714 }
1715 }
1716
1717 #[test]
1718 fn spi_error_variants_round_trip() {
1719 for err in [SpiError::BufferTooLong, SpiError::Other] {
1720 let bytes = to_allocvec(&err).unwrap();
1721 let decoded: SpiError = from_bytes(&bytes).unwrap();
1722 assert_eq!(err, decoded);
1723 }
1724 }
1725
1726 #[test]
1727 fn gpio_error_variants_round_trip() {
1728 for err in [
1729 GpioError::InvalidPin,
1730 GpioError::Other,
1731 GpioError::WrongDirection,
1732 GpioError::PinMonitored,
1733 GpioError::PinNotMonitored,
1734 ] {
1735 let bytes = to_allocvec(&err).unwrap();
1736 let decoded: GpioError = from_bytes(&bytes).unwrap();
1737 assert_eq!(err, decoded);
1738 }
1739 }
1740
1741 #[test]
1742 #[cfg(feature = "use-std")]
1743 fn i2c_error_display() {
1744 assert_eq!(
1745 format!("{}", I2cError::NoAcknowledge),
1746 "no acknowledge from target"
1747 );
1748 assert_eq!(format!("{}", I2cError::Bus), "I2C bus error");
1749 assert_eq!(
1750 format!("{}", I2cError::ArbitrationLoss),
1751 "I2C arbitration loss"
1752 );
1753 assert_eq!(format!("{}", I2cError::Overrun), "I2C data overrun");
1754 assert_eq!(
1755 format!("{}", I2cError::BufferTooLong),
1756 "buffer exceeds firmware limit"
1757 );
1758 assert_eq!(
1759 format!("{}", I2cError::AddressOutOfRange),
1760 "I2C address out of range"
1761 );
1762 assert_eq!(format!("{}", I2cError::Other), "I2C error");
1763 }
1764
1765 #[test]
1766 #[cfg(feature = "use-std")]
1767 fn spi_error_display() {
1768 assert_eq!(
1769 format!("{}", SpiError::BufferTooLong),
1770 "buffer exceeds firmware limit"
1771 );
1772 assert_eq!(format!("{}", SpiError::Other), "SPI error");
1773 }
1774
1775 #[test]
1776 #[cfg(feature = "use-std")]
1777 fn gpio_error_display() {
1778 assert_eq!(
1779 format!("{}", GpioError::InvalidPin),
1780 "invalid GPIO pin number"
1781 );
1782 assert_eq!(format!("{}", GpioError::Other), "GPIO error");
1783 assert_eq!(
1784 format!("{}", GpioError::WrongDirection),
1785 "GPIO pin configured in wrong direction"
1786 );
1787 assert_eq!(
1788 format!("{}", GpioError::PinMonitored),
1789 "GPIO pin is being monitored for events"
1790 );
1791 assert_eq!(
1792 format!("{}", GpioError::PinNotMonitored),
1793 "GPIO pin is not monitored"
1794 );
1795 }
1796
1797 #[test]
1804 fn i2c_read_request_wire_stability() {
1805 let req = I2cReadRequest {
1806 address: 0x48,
1807 count: 4,
1808 };
1809 let bytes = to_allocvec(&req).unwrap();
1810 assert_eq!(
1811 bytes,
1812 to_allocvec(&req).unwrap(),
1813 "encoding is deterministic"
1814 );
1815 let decoded: I2cReadRequest = from_bytes(&bytes).unwrap();
1817 assert_eq!(decoded, req);
1818 let snapshot = bytes.clone();
1820 let freshly_encoded = to_allocvec(&decoded).unwrap();
1821 assert_eq!(freshly_encoded, snapshot, "wire format must not change");
1822 }
1823
1824 #[test]
1825 fn i2c_set_configuration_request_wire_stability() {
1826 let req = I2cSetConfigurationRequest {
1827 frequency: I2cFrequency::Fast,
1828 };
1829 let bytes = to_allocvec(&req).unwrap();
1830 let canonical = bytes.clone();
1831 let decoded: I2cSetConfigurationRequest = from_bytes(&bytes).unwrap();
1832 assert_eq!(decoded, req);
1833 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
1834 }
1835
1836 #[test]
1837 fn spi_set_configuration_request_wire_stability() {
1838 let req = SpiSetConfigurationRequest {
1839 spi_frequency: 1_000_000,
1840 spi_phase: SpiPhase::CaptureOnFirstTransition,
1841 spi_polarity: SpiPolarity::IdleLow,
1842 };
1843 let bytes = to_allocvec(&req).unwrap();
1844 let canonical = bytes.clone();
1845 let decoded: SpiSetConfigurationRequest = from_bytes(&bytes).unwrap();
1846 assert_eq!(decoded, req);
1847 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
1848 }
1849
1850 #[test]
1851 fn version_info_wire_stability() {
1852 let ver = VersionInfo {
1853 major: 1,
1854 minor: 0,
1855 patch: 0,
1856 };
1857 let bytes = to_allocvec(&ver).unwrap();
1858 let canonical = bytes.clone();
1859 let decoded: VersionInfo = from_bytes(&bytes).unwrap();
1860 assert_eq!(decoded, ver);
1861 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
1862 }
1863
1864 #[test]
1865 fn gpio_put_request_wire_stability() {
1866 let req = GpioPutRequest {
1867 pin: 0,
1868 state: GpioState::High,
1869 };
1870 let bytes = to_allocvec(&req).unwrap();
1871 let canonical = bytes.clone();
1872 let decoded: GpioPutRequest = from_bytes(&bytes).unwrap();
1873 assert_eq!(decoded, req);
1874 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
1875 }
1876
1877 #[test]
1880 fn i2c_read_request_zero_count() {
1881 let req = I2cReadRequest {
1882 address: 0x00,
1883 count: 0,
1884 };
1885 let bytes = to_allocvec(&req).unwrap();
1886 let decoded: I2cReadRequest = from_bytes(&bytes).unwrap();
1887 assert_eq!(req, decoded);
1888 }
1889
1890 #[test]
1891 fn i2c_read_request_max_address() {
1892 let req = I2cReadRequest {
1893 address: u8::MAX,
1894 count: 1,
1895 };
1896 let bytes = to_allocvec(&req).unwrap();
1897 let decoded: I2cReadRequest = from_bytes(&bytes).unwrap();
1898 assert_eq!(req, decoded);
1899 }
1900
1901 #[test]
1902 fn spi_read_request_max_count() {
1903 let req = SpiReadRequest { count: u16::MAX };
1904 let bytes = to_allocvec(&req).unwrap();
1905 let decoded: SpiReadRequest = from_bytes(&bytes).unwrap();
1906 assert_eq!(req, decoded);
1907 }
1908
1909 #[test]
1910 fn spi_read_request_zero_count() {
1911 let req = SpiReadRequest { count: 0 };
1912 let bytes = to_allocvec(&req).unwrap();
1913 let decoded: SpiReadRequest = from_bytes(&bytes).unwrap();
1914 assert_eq!(req, decoded);
1915 }
1916
1917 #[test]
1918 fn i2c_write_request_empty_contents() {
1919 let req = I2cWriteRequest {
1920 address: 0x50,
1921 contents: &[],
1922 };
1923 let bytes = to_allocvec(&req).unwrap();
1924 let decoded: I2cWriteRequest = from_bytes(&bytes).unwrap();
1925 assert_eq!(req, decoded);
1926 }
1927
1928 #[test]
1929 fn spi_write_request_empty_contents() {
1930 let req = SpiWriteRequest { contents: &[] };
1931 let bytes = to_allocvec(&req).unwrap();
1932 let decoded: SpiWriteRequest = from_bytes(&bytes).unwrap();
1933 assert_eq!(req, decoded);
1934 }
1935
1936 #[test]
1937 fn i2c_write_read_request_empty_contents_max_count() {
1938 let req = I2cWriteReadRequest {
1939 address: 0x7F,
1940 contents: &[],
1941 count: u16::MAX,
1942 };
1943 let bytes = to_allocvec(&req).unwrap();
1944 let decoded: I2cWriteReadRequest = from_bytes(&bytes).unwrap();
1945 assert_eq!(req, decoded);
1946 }
1947
1948 #[test]
1949 fn gpio_get_request_all_pins() {
1950 for pin in 0..=u8::MAX {
1951 let req = GpioGetRequest { pin };
1952 let bytes = to_allocvec(&req).unwrap();
1953 let decoded: GpioGetRequest = from_bytes(&bytes).unwrap();
1954 assert_eq!(req, decoded);
1955 }
1956 }
1957
1958 #[test]
1959 fn gpio_wait_request_all_pins() {
1960 for pin in 0..=u8::MAX {
1961 let req = GpioWaitRequest { pin };
1962 let bytes = to_allocvec(&req).unwrap();
1963 let decoded: GpioWaitRequest = from_bytes(&bytes).unwrap();
1964 assert_eq!(req, decoded);
1965 }
1966 }
1967
1968 #[test]
1969 fn version_info_boundary_values() {
1970 for ver in [
1971 VersionInfo {
1972 major: 0,
1973 minor: 0,
1974 patch: 0,
1975 },
1976 VersionInfo {
1977 major: u16::MAX,
1978 minor: u16::MAX,
1979 patch: u32::MAX,
1980 },
1981 ] {
1982 let bytes = to_allocvec(&ver).unwrap();
1983 let decoded: VersionInfo = from_bytes(&bytes).unwrap();
1984 assert_eq!(ver, decoded);
1985 }
1986 }
1987
1988 #[test]
1989 fn spi_set_configuration_request_all_enum_combinations() {
1990 for (phase, polarity) in [
1991 (SpiPhase::CaptureOnFirstTransition, SpiPolarity::IdleLow),
1992 (SpiPhase::CaptureOnFirstTransition, SpiPolarity::IdleHigh),
1993 (SpiPhase::CaptureOnSecondTransition, SpiPolarity::IdleLow),
1994 (SpiPhase::CaptureOnSecondTransition, SpiPolarity::IdleHigh),
1995 ] {
1996 let req = SpiSetConfigurationRequest {
1997 spi_frequency: 500_000,
1998 spi_phase: phase,
1999 spi_polarity: polarity,
2000 };
2001 let bytes = to_allocvec(&req).unwrap();
2002 let decoded: SpiSetConfigurationRequest = from_bytes(&bytes).unwrap();
2003 assert_eq!(req, decoded);
2004 }
2005 }
2006
2007 #[test]
2008 fn i2c_set_configuration_request_all_frequencies() {
2009 for freq in [
2010 I2cFrequency::Standard,
2011 I2cFrequency::Fast,
2012 I2cFrequency::FastPlus,
2013 ] {
2014 let req = I2cSetConfigurationRequest { frequency: freq };
2015 let bytes = to_allocvec(&req).unwrap();
2016 let decoded: I2cSetConfigurationRequest = from_bytes(&bytes).unwrap();
2017 assert_eq!(req, decoded);
2018 }
2019 }
2020
2021 #[test]
2022 fn i2c_frequency_discriminants_are_stable() {
2023 assert_eq!(I2cFrequency::Standard as u8, 0);
2024 assert_eq!(I2cFrequency::Fast as u8, 1);
2025 assert_eq!(I2cFrequency::FastPlus as u8, 2);
2026 }
2027
2028 #[test]
2029 fn spi_set_configuration_request_max_frequency() {
2030 let req = SpiSetConfigurationRequest {
2031 spi_frequency: u32::MAX,
2032 spi_phase: SpiPhase::CaptureOnFirstTransition,
2033 spi_polarity: SpiPolarity::IdleLow,
2034 };
2035 let bytes = to_allocvec(&req).unwrap();
2036 let decoded: SpiSetConfigurationRequest = from_bytes(&bytes).unwrap();
2037 assert_eq!(req, decoded);
2038 }
2039
2040 #[test]
2042 fn spi_phase_discriminants_are_stable() {
2043 assert_eq!(
2044 to_allocvec(&SpiPhase::CaptureOnFirstTransition).unwrap(),
2045 to_allocvec(&SpiPhase::CaptureOnFirstTransition).unwrap()
2046 );
2047 assert_ne!(
2049 to_allocvec(&SpiPhase::CaptureOnFirstTransition).unwrap(),
2050 to_allocvec(&SpiPhase::CaptureOnSecondTransition).unwrap()
2051 );
2052 }
2053
2054 #[test]
2055 fn spi_polarity_discriminants_are_stable() {
2056 assert_ne!(
2057 to_allocvec(&SpiPolarity::IdleLow).unwrap(),
2058 to_allocvec(&SpiPolarity::IdleHigh).unwrap()
2059 );
2060 }
2061
2062 #[test]
2063 fn gpio_state_discriminants_are_stable() {
2064 assert_ne!(
2065 to_allocvec(&GpioState::Low).unwrap(),
2066 to_allocvec(&GpioState::High).unwrap()
2067 );
2068 }
2069
2070 #[test]
2073 fn gpio_direction_round_trip() {
2074 for dir in [GpioDirection::Input, GpioDirection::Output] {
2075 let bytes = to_allocvec(&dir).unwrap();
2076 let decoded: GpioDirection = from_bytes(&bytes).unwrap();
2077 assert_eq!(dir, decoded);
2078 }
2079 }
2080
2081 #[test]
2082 fn gpio_pull_round_trip() {
2083 for pull in [GpioPull::None, GpioPull::Up, GpioPull::Down] {
2084 let bytes = to_allocvec(&pull).unwrap();
2085 let decoded: GpioPull = from_bytes(&bytes).unwrap();
2086 assert_eq!(pull, decoded);
2087 }
2088 }
2089
2090 #[test]
2091 fn gpio_set_configuration_request_round_trip() {
2092 let req = GpioSetConfigurationRequest {
2093 pin: 3,
2094 direction: GpioDirection::Input,
2095 pull: GpioPull::Up,
2096 };
2097 let bytes = to_allocvec(&req).unwrap();
2098 let decoded: GpioSetConfigurationRequest = from_bytes(&bytes).unwrap();
2099 assert_eq!(req, decoded);
2100 }
2101
2102 #[test]
2103 fn gpio_set_configuration_request_all_combinations() {
2104 for dir in [GpioDirection::Input, GpioDirection::Output] {
2105 for pull in [GpioPull::None, GpioPull::Up, GpioPull::Down] {
2106 let req = GpioSetConfigurationRequest {
2107 pin: 0,
2108 direction: dir,
2109 pull,
2110 };
2111 let bytes = to_allocvec(&req).unwrap();
2112 let decoded: GpioSetConfigurationRequest = from_bytes(&bytes).unwrap();
2113 assert_eq!(req, decoded);
2114 }
2115 }
2116 }
2117
2118 #[test]
2119 fn gpio_direction_discriminants_are_stable() {
2120 assert_eq!(GpioDirection::Input as u8, 0);
2121 assert_eq!(GpioDirection::Output as u8, 1);
2122 }
2123
2124 #[test]
2125 fn gpio_pull_discriminants_are_stable() {
2126 assert_eq!(GpioPull::None as u8, 0);
2127 assert_eq!(GpioPull::Up as u8, 1);
2128 assert_eq!(GpioPull::Down as u8, 2);
2129 }
2130
2131 #[test]
2132 #[cfg(feature = "use-std")]
2133 fn gpio_direction_golden_bytes() {
2134 assert_eq!(to_allocvec(&GpioDirection::Input).unwrap(), vec![0x00]);
2136 assert_eq!(to_allocvec(&GpioDirection::Output).unwrap(), vec![0x01]);
2137 }
2138
2139 #[test]
2140 #[cfg(feature = "use-std")]
2141 fn gpio_pull_golden_bytes() {
2142 assert_eq!(to_allocvec(&GpioPull::None).unwrap(), vec![0x00]);
2144 assert_eq!(to_allocvec(&GpioPull::Up).unwrap(), vec![0x01]);
2145 assert_eq!(to_allocvec(&GpioPull::Down).unwrap(), vec![0x02]);
2146 }
2147
2148 #[test]
2149 fn gpio_set_configuration_request_wire_stability() {
2150 let req = GpioSetConfigurationRequest {
2151 pin: 5,
2152 direction: GpioDirection::Output,
2153 pull: GpioPull::None,
2154 };
2155 let bytes = to_allocvec(&req).unwrap();
2156 let canonical = bytes.clone();
2157 let decoded: GpioSetConfigurationRequest = from_bytes(&bytes).unwrap();
2158 assert_eq!(decoded, req);
2159 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
2160 }
2161
2162 #[test]
2165 fn spi_configuration_info_round_trip() {
2166 let info = SpiConfigurationInfo {
2167 spi_frequency: 1_000_000,
2168 spi_phase: SpiPhase::CaptureOnFirstTransition,
2169 spi_polarity: SpiPolarity::IdleLow,
2170 };
2171 let bytes = to_allocvec(&info).unwrap();
2172 let decoded: SpiConfigurationInfo = from_bytes(&bytes).unwrap();
2173 assert_eq!(info, decoded);
2174 }
2175
2176 #[test]
2177 fn spi_configuration_info_all_variants() {
2178 let info = SpiConfigurationInfo {
2179 spi_frequency: 25_000_000,
2180 spi_phase: SpiPhase::CaptureOnSecondTransition,
2181 spi_polarity: SpiPolarity::IdleHigh,
2182 };
2183 let bytes = to_allocvec(&info).unwrap();
2184 let decoded: SpiConfigurationInfo = from_bytes(&bytes).unwrap();
2185 assert_eq!(info, decoded);
2186 }
2187
2188 #[test]
2189 fn spi_configuration_info_golden_bytes() {
2190 let info = SpiConfigurationInfo {
2192 spi_frequency: 1_000_000,
2193 spi_phase: SpiPhase::CaptureOnFirstTransition,
2194 spi_polarity: SpiPolarity::IdleLow,
2195 };
2196 let bytes = to_allocvec(&info).unwrap();
2197 let decoded: SpiConfigurationInfo = from_bytes(&bytes).unwrap();
2198 assert_eq!(decoded, info);
2199 assert_eq!(bytes[bytes.len() - 2], 0x00); assert_eq!(bytes[bytes.len() - 1], 0x00); }
2203
2204 #[test]
2205 fn i2c_frequency_round_trip_all_variants() {
2206 for freq in [
2207 I2cFrequency::Standard,
2208 I2cFrequency::Fast,
2209 I2cFrequency::FastPlus,
2210 ] {
2211 let bytes = to_allocvec(&freq).unwrap();
2212 let decoded: I2cFrequency = from_bytes(&bytes).unwrap();
2213 assert_eq!(freq, decoded);
2214 }
2215 }
2216
2217 #[test]
2220 fn uart_read_request_round_trip() {
2221 let req = UartReadRequest {
2222 count: 64,
2223 timeout_ms: 1000,
2224 };
2225 let bytes = to_allocvec(&req).unwrap();
2226 let decoded: UartReadRequest = from_bytes(&bytes).unwrap();
2227 assert_eq!(req, decoded);
2228 }
2229
2230 #[test]
2231 fn uart_read_request_zero_timeout() {
2232 let req = UartReadRequest {
2233 count: 10,
2234 timeout_ms: 0,
2235 };
2236 let bytes = to_allocvec(&req).unwrap();
2237 let decoded: UartReadRequest = from_bytes(&bytes).unwrap();
2238 assert_eq!(req, decoded);
2239 }
2240
2241 #[test]
2242 fn uart_read_request_max_count() {
2243 let req = UartReadRequest {
2244 count: u16::MAX,
2245 timeout_ms: 5000,
2246 };
2247 let bytes = to_allocvec(&req).unwrap();
2248 let decoded: UartReadRequest = from_bytes(&bytes).unwrap();
2249 assert_eq!(req, decoded);
2250 }
2251
2252 #[test]
2253 fn uart_write_request_round_trip() {
2254 let data = [0x48, 0x65, 0x6c, 0x6c, 0x6f];
2255 let req = UartWriteRequest { contents: &data };
2256 let bytes = to_allocvec(&req).unwrap();
2257 let decoded: UartWriteRequest = from_bytes(&bytes).unwrap();
2258 assert_eq!(req, decoded);
2259 }
2260
2261 #[test]
2262 fn uart_write_request_empty_contents() {
2263 let req = UartWriteRequest { contents: &[] };
2264 let bytes = to_allocvec(&req).unwrap();
2265 let decoded: UartWriteRequest = from_bytes(&bytes).unwrap();
2266 assert_eq!(req, decoded);
2267 }
2268
2269 #[test]
2270 fn uart_set_configuration_request_round_trip() {
2271 let req = UartSetConfigurationRequest { baud_rate: 115_200 };
2272 let bytes = to_allocvec(&req).unwrap();
2273 let decoded: UartSetConfigurationRequest = from_bytes(&bytes).unwrap();
2274 assert_eq!(req, decoded);
2275 }
2276
2277 #[test]
2278 fn uart_set_configuration_request_common_baud_rates() {
2279 for baud in [9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600] {
2280 let req = UartSetConfigurationRequest { baud_rate: baud };
2281 let bytes = to_allocvec(&req).unwrap();
2282 let decoded: UartSetConfigurationRequest = from_bytes(&bytes).unwrap();
2283 assert_eq!(req, decoded);
2284 }
2285 }
2286
2287 #[test]
2288 fn uart_configuration_info_round_trip() {
2289 let info = UartConfigurationInfo { baud_rate: 115_200 };
2290 let bytes = to_allocvec(&info).unwrap();
2291 let decoded: UartConfigurationInfo = from_bytes(&bytes).unwrap();
2292 assert_eq!(info, decoded);
2293 }
2294
2295 #[test]
2296 fn uart_error_variants_round_trip() {
2297 for err in [
2298 UartError::BufferTooLong,
2299 UartError::Overrun,
2300 UartError::Break,
2301 UartError::Parity,
2302 UartError::Framing,
2303 UartError::InvalidBaudRate,
2304 UartError::Other,
2305 UartError::Unsupported,
2306 ] {
2307 let bytes = to_allocvec(&err).unwrap();
2308 let decoded: UartError = from_bytes(&bytes).unwrap();
2309 assert_eq!(err, decoded);
2310 }
2311 }
2312
2313 #[test]
2314 #[cfg(feature = "use-std")]
2315 fn uart_error_display() {
2316 assert_eq!(
2317 format!("{}", UartError::BufferTooLong),
2318 "buffer exceeds firmware limit"
2319 );
2320 assert_eq!(format!("{}", UartError::Overrun), "UART receiver overrun");
2321 assert_eq!(format!("{}", UartError::Break), "UART break condition");
2322 assert_eq!(format!("{}", UartError::Parity), "UART parity error");
2323 assert_eq!(format!("{}", UartError::Framing), "UART framing error");
2324 assert_eq!(
2325 format!("{}", UartError::InvalidBaudRate),
2326 "invalid baud rate"
2327 );
2328 assert_eq!(format!("{}", UartError::Other), "UART error");
2329 assert_eq!(
2330 format!("{}", UartError::Unsupported),
2331 "UART not supported on this hardware"
2332 );
2333 }
2334
2335 #[test]
2336 fn uart_read_request_wire_stability() {
2337 let req = UartReadRequest {
2338 count: 64,
2339 timeout_ms: 1000,
2340 };
2341 let bytes = to_allocvec(&req).unwrap();
2342 let canonical = bytes.clone();
2343 let decoded: UartReadRequest = from_bytes(&bytes).unwrap();
2344 assert_eq!(decoded, req);
2345 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
2346 }
2347
2348 #[test]
2349 fn uart_set_configuration_request_wire_stability() {
2350 let req = UartSetConfigurationRequest { baud_rate: 115_200 };
2351 let bytes = to_allocvec(&req).unwrap();
2352 let canonical = bytes.clone();
2353 let decoded: UartSetConfigurationRequest = from_bytes(&bytes).unwrap();
2354 assert_eq!(decoded, req);
2355 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
2356 }
2357
2358 #[test]
2359 fn uart_configuration_info_wire_stability() {
2360 let info = UartConfigurationInfo { baud_rate: 115_200 };
2361 let bytes = to_allocvec(&info).unwrap();
2362 let canonical = bytes.clone();
2363 let decoded: UartConfigurationInfo = from_bytes(&bytes).unwrap();
2364 assert_eq!(decoded, info);
2365 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
2366 }
2367
2368 #[test]
2371 fn pwm_set_duty_cycle_request_round_trip() {
2372 let req = PwmSetDutyCycleRequest {
2373 channel: 2,
2374 duty: 32768,
2375 };
2376 let bytes = to_allocvec(&req).unwrap();
2377 let decoded: PwmSetDutyCycleRequest = from_bytes(&bytes).unwrap();
2378 assert_eq!(req, decoded);
2379 }
2380
2381 #[test]
2382 fn pwm_set_duty_cycle_request_zero_duty() {
2383 let req = PwmSetDutyCycleRequest {
2384 channel: 0,
2385 duty: 0,
2386 };
2387 let bytes = to_allocvec(&req).unwrap();
2388 let decoded: PwmSetDutyCycleRequest = from_bytes(&bytes).unwrap();
2389 assert_eq!(req, decoded);
2390 }
2391
2392 #[test]
2393 fn pwm_set_duty_cycle_request_max_duty() {
2394 let req = PwmSetDutyCycleRequest {
2395 channel: 3,
2396 duty: u16::MAX,
2397 };
2398 let bytes = to_allocvec(&req).unwrap();
2399 let decoded: PwmSetDutyCycleRequest = from_bytes(&bytes).unwrap();
2400 assert_eq!(req, decoded);
2401 }
2402
2403 #[test]
2404 fn pwm_get_duty_cycle_request_round_trip() {
2405 let req = PwmGetDutyCycleRequest { channel: 1 };
2406 let bytes = to_allocvec(&req).unwrap();
2407 let decoded: PwmGetDutyCycleRequest = from_bytes(&bytes).unwrap();
2408 assert_eq!(req, decoded);
2409 }
2410
2411 #[test]
2412 fn pwm_duty_cycle_info_round_trip() {
2413 let info = PwmDutyCycleInfo {
2414 max_duty: 65535,
2415 current_duty: 32768,
2416 };
2417 let bytes = to_allocvec(&info).unwrap();
2418 let decoded: PwmDutyCycleInfo = from_bytes(&bytes).unwrap();
2419 assert_eq!(info, decoded);
2420 }
2421
2422 #[test]
2423 fn pwm_enable_request_round_trip() {
2424 let req = PwmEnableRequest { channel: 0 };
2425 let bytes = to_allocvec(&req).unwrap();
2426 let decoded: PwmEnableRequest = from_bytes(&bytes).unwrap();
2427 assert_eq!(req, decoded);
2428 }
2429
2430 #[test]
2431 fn pwm_disable_request_round_trip() {
2432 let req = PwmDisableRequest { channel: 3 };
2433 let bytes = to_allocvec(&req).unwrap();
2434 let decoded: PwmDisableRequest = from_bytes(&bytes).unwrap();
2435 assert_eq!(req, decoded);
2436 }
2437
2438 #[test]
2439 fn pwm_set_configuration_request_round_trip() {
2440 let req = PwmSetConfigurationRequest {
2441 channel: 1,
2442 frequency_hz: 1_000,
2443 phase_correct: false,
2444 };
2445 let bytes = to_allocvec(&req).unwrap();
2446 let decoded: PwmSetConfigurationRequest = from_bytes(&bytes).unwrap();
2447 assert_eq!(req, decoded);
2448 }
2449
2450 #[test]
2451 fn pwm_set_configuration_request_phase_correct() {
2452 let req = PwmSetConfigurationRequest {
2453 channel: 2,
2454 frequency_hz: 50,
2455 phase_correct: true,
2456 };
2457 let bytes = to_allocvec(&req).unwrap();
2458 let decoded: PwmSetConfigurationRequest = from_bytes(&bytes).unwrap();
2459 assert_eq!(req, decoded);
2460 }
2461
2462 #[test]
2463 fn pwm_set_configuration_request_common_frequencies() {
2464 for freq in [50, 100, 1_000, 10_000, 50_000, 100_000, 1_000_000] {
2465 let req = PwmSetConfigurationRequest {
2466 channel: 0,
2467 frequency_hz: freq,
2468 phase_correct: false,
2469 };
2470 let bytes = to_allocvec(&req).unwrap();
2471 let decoded: PwmSetConfigurationRequest = from_bytes(&bytes).unwrap();
2472 assert_eq!(req, decoded);
2473 }
2474 }
2475
2476 #[test]
2477 fn pwm_get_configuration_request_round_trip() {
2478 let req = PwmGetConfigurationRequest { channel: 3 };
2479 let bytes = to_allocvec(&req).unwrap();
2480 let decoded: PwmGetConfigurationRequest = from_bytes(&bytes).unwrap();
2481 assert_eq!(req, decoded);
2482 }
2483
2484 #[test]
2485 fn pwm_configuration_info_round_trip() {
2486 let info = PwmConfigurationInfo {
2487 frequency_hz: 1_000,
2488 phase_correct: false,
2489 enabled: true,
2490 };
2491 let bytes = to_allocvec(&info).unwrap();
2492 let decoded: PwmConfigurationInfo = from_bytes(&bytes).unwrap();
2493 assert_eq!(info, decoded);
2494 }
2495
2496 #[test]
2497 fn pwm_error_variants_round_trip() {
2498 for err in [
2499 PwmError::InvalidChannel,
2500 PwmError::InvalidDutyCycle,
2501 PwmError::InvalidConfiguration,
2502 PwmError::Other,
2503 ] {
2504 let bytes = to_allocvec(&err).unwrap();
2505 let decoded: PwmError = from_bytes(&bytes).unwrap();
2506 assert_eq!(err, decoded);
2507 }
2508 }
2509
2510 #[test]
2511 #[cfg(feature = "use-std")]
2512 fn pwm_error_display() {
2513 assert_eq!(
2514 format!("{}", PwmError::InvalidChannel),
2515 "invalid PWM channel"
2516 );
2517 assert_eq!(
2518 format!("{}", PwmError::InvalidDutyCycle),
2519 "duty cycle exceeds maximum"
2520 );
2521 assert_eq!(
2522 format!("{}", PwmError::InvalidConfiguration),
2523 "invalid PWM configuration"
2524 );
2525 assert_eq!(format!("{}", PwmError::Other), "PWM error");
2526 }
2527
2528 #[test]
2529 fn pwm_set_duty_cycle_request_wire_stability() {
2530 let req = PwmSetDutyCycleRequest {
2531 channel: 1,
2532 duty: 1000,
2533 };
2534 let bytes = to_allocvec(&req).unwrap();
2535 let canonical = bytes.clone();
2536 let decoded: PwmSetDutyCycleRequest = from_bytes(&bytes).unwrap();
2537 assert_eq!(decoded, req);
2538 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
2539 }
2540
2541 #[test]
2542 fn pwm_set_configuration_request_wire_stability() {
2543 let req = PwmSetConfigurationRequest {
2544 channel: 0,
2545 frequency_hz: 1_000,
2546 phase_correct: false,
2547 };
2548 let bytes = to_allocvec(&req).unwrap();
2549 let canonical = bytes.clone();
2550 let decoded: PwmSetConfigurationRequest = from_bytes(&bytes).unwrap();
2551 assert_eq!(decoded, req);
2552 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
2553 }
2554
2555 #[test]
2556 fn pwm_configuration_info_wire_stability() {
2557 let info = PwmConfigurationInfo {
2558 frequency_hz: 50_000,
2559 phase_correct: true,
2560 enabled: true,
2561 };
2562 let bytes = to_allocvec(&info).unwrap();
2563 let canonical = bytes.clone();
2564 let decoded: PwmConfigurationInfo = from_bytes(&bytes).unwrap();
2565 assert_eq!(decoded, info);
2566 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
2567 }
2568
2569 #[test]
2572 fn adc_read_request_round_trip() {
2573 let req = AdcReadRequest {
2574 channel: AdcChannel::Adc2,
2575 };
2576 let bytes = to_allocvec(&req).unwrap();
2577 let decoded: AdcReadRequest = from_bytes(&bytes).unwrap();
2578 assert_eq!(req, decoded);
2579 }
2580
2581 #[test]
2582 #[cfg(feature = "use-std")]
2583 fn adc_channel_display() {
2584 assert_eq!(format!("{}", AdcChannel::Adc0), "ADC0 (GPIO26)");
2585 assert_eq!(format!("{}", AdcChannel::Adc1), "ADC1 (GPIO27)");
2586 assert_eq!(format!("{}", AdcChannel::Adc2), "ADC2 (GPIO28)");
2587 assert_eq!(format!("{}", AdcChannel::Adc3), "ADC3 (GPIO29)");
2588 }
2589
2590 #[test]
2591 #[cfg(feature = "use-std")]
2592 fn adc_error_display() {
2593 assert_eq!(
2594 format!("{}", AdcError::ConversionFailed),
2595 "ADC conversion failed"
2596 );
2597 assert_eq!(format!("{}", AdcError::Other), "ADC error");
2598 assert_eq!(
2599 format!("{}", AdcError::Unsupported),
2600 "ADC not supported on this hardware"
2601 );
2602 }
2603
2604 #[test]
2605 fn adc_configuration_info_round_trip() {
2606 let info = AdcConfigurationInfo {
2607 resolution_bits: 12,
2608 nominal_reference_mv: 3300,
2609 num_gpio_channels: 4,
2610 };
2611 let bytes = to_allocvec(&info).unwrap();
2612 let decoded: AdcConfigurationInfo = from_bytes(&bytes).unwrap();
2613 assert_eq!(info, decoded);
2614 }
2615
2616 #[test]
2617 fn adc_read_request_wire_stability() {
2618 let req = AdcReadRequest {
2619 channel: AdcChannel::Adc1,
2620 };
2621 let bytes = to_allocvec(&req).unwrap();
2622 let canonical = bytes.clone();
2623 let decoded: AdcReadRequest = from_bytes(&bytes).unwrap();
2624 assert_eq!(decoded, req);
2625 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
2626 }
2627
2628 #[test]
2629 fn adc_configuration_info_wire_stability() {
2630 let info = AdcConfigurationInfo {
2631 resolution_bits: 12,
2632 nominal_reference_mv: 3300,
2633 num_gpio_channels: 4,
2634 };
2635 let bytes = to_allocvec(&info).unwrap();
2636 let canonical = bytes.clone();
2637 let decoded: AdcConfigurationInfo = from_bytes(&bytes).unwrap();
2638 assert_eq!(decoded, info);
2639 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
2640 }
2641
2642 #[test]
2643 fn adc_channel_discriminants_are_stable() {
2644 assert_eq!(to_allocvec(&AdcChannel::Adc0).unwrap(), [0]);
2646 assert_eq!(to_allocvec(&AdcChannel::Adc1).unwrap(), [1]);
2647 assert_eq!(to_allocvec(&AdcChannel::Adc2).unwrap(), [2]);
2648 assert_eq!(to_allocvec(&AdcChannel::Adc3).unwrap(), [3]);
2649 }
2650
2651 #[test]
2654 fn gpio_edge_round_trip() {
2655 for edge in [GpioEdge::Rising, GpioEdge::Falling, GpioEdge::Any] {
2656 let bytes = to_allocvec(&edge).unwrap();
2657 let decoded: GpioEdge = from_bytes(&bytes).unwrap();
2658 assert_eq!(edge, decoded);
2659 }
2660 }
2661
2662 #[test]
2663 fn gpio_edge_discriminants_are_stable() {
2664 assert_eq!(GpioEdge::Rising as u8, 0);
2665 assert_eq!(GpioEdge::Falling as u8, 1);
2666 assert_eq!(GpioEdge::Any as u8, 2);
2667 }
2668
2669 #[test]
2670 #[cfg(feature = "use-std")]
2671 fn gpio_edge_display() {
2672 assert_eq!(format!("{}", GpioEdge::Rising), "rising");
2673 assert_eq!(format!("{}", GpioEdge::Falling), "falling");
2674 assert_eq!(format!("{}", GpioEdge::Any), "any");
2675 }
2676
2677 #[test]
2678 fn gpio_event_round_trip() {
2679 let event = GpioEvent {
2680 pin: 2,
2681 edge: GpioEdge::Rising,
2682 state: GpioState::High,
2683 timestamp_us: 123_456_789,
2684 };
2685 let bytes = to_allocvec(&event).unwrap();
2686 let decoded: GpioEvent = from_bytes(&bytes).unwrap();
2687 assert_eq!(event, decoded);
2688 }
2689
2690 #[test]
2691 fn gpio_event_all_edge_variants() {
2692 for edge in [GpioEdge::Rising, GpioEdge::Falling, GpioEdge::Any] {
2693 for state in [GpioState::Low, GpioState::High] {
2694 let event = GpioEvent {
2695 pin: 0,
2696 edge,
2697 state,
2698 timestamp_us: 0,
2699 };
2700 let bytes = to_allocvec(&event).unwrap();
2701 let decoded: GpioEvent = from_bytes(&bytes).unwrap();
2702 assert_eq!(event, decoded);
2703 }
2704 }
2705 }
2706
2707 #[test]
2708 fn gpio_event_wire_stability() {
2709 let event = GpioEvent {
2710 pin: 1,
2711 edge: GpioEdge::Falling,
2712 state: GpioState::Low,
2713 timestamp_us: 999_999,
2714 };
2715 let bytes = to_allocvec(&event).unwrap();
2716 let canonical = bytes.clone();
2717 let decoded: GpioEvent = from_bytes(&bytes).unwrap();
2718 assert_eq!(decoded, event);
2719 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
2720 }
2721
2722 #[test]
2723 fn gpio_subscribe_request_round_trip() {
2724 for edge in [GpioEdge::Rising, GpioEdge::Falling, GpioEdge::Any] {
2725 let req = GpioSubscribeRequest { pin: 3, edge };
2726 let bytes = to_allocvec(&req).unwrap();
2727 let decoded: GpioSubscribeRequest = from_bytes(&bytes).unwrap();
2728 assert_eq!(req, decoded);
2729 }
2730 }
2731
2732 #[test]
2733 fn gpio_unsubscribe_request_round_trip() {
2734 for pin in 0..4u8 {
2735 let req = GpioUnsubscribeRequest { pin };
2736 let bytes = to_allocvec(&req).unwrap();
2737 let decoded: GpioUnsubscribeRequest = from_bytes(&bytes).unwrap();
2738 assert_eq!(req, decoded);
2739 }
2740 }
2741
2742 #[test]
2743 fn gpio_subscribe_request_wire_stability() {
2744 let req = GpioSubscribeRequest {
2745 pin: 2,
2746 edge: GpioEdge::Any,
2747 };
2748 let bytes = to_allocvec(&req).unwrap();
2749 let canonical = bytes.clone();
2750 let decoded: GpioSubscribeRequest = from_bytes(&bytes).unwrap();
2751 assert_eq!(decoded, req);
2752 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
2753 }
2754
2755 #[test]
2758 fn i2c_batch_op_round_trip() {
2759 let ops = [
2760 I2cBatchOp::Read { len: 16 },
2761 I2cBatchOp::Write {
2762 data: &[0xAA, 0xBB],
2763 },
2764 ];
2765 for op in &ops {
2766 let bytes = to_allocvec(op).unwrap();
2767 let decoded: I2cBatchOp = from_bytes(&bytes).unwrap();
2768 assert_eq!(&decoded, op);
2769 }
2770 }
2771
2772 #[test]
2773 fn spi_batch_op_round_trip() {
2774 let ops = [
2775 SpiBatchOp::Read { len: 8 },
2776 SpiBatchOp::Write {
2777 data: &[0x01, 0x02],
2778 },
2779 SpiBatchOp::Transfer { data: &[0xFF; 4] },
2780 SpiBatchOp::DelayNs { ns: 1_000_000 },
2781 ];
2782 for op in &ops {
2783 let bytes = to_allocvec(op).unwrap();
2784 let decoded: SpiBatchOp = from_bytes(&bytes).unwrap();
2785 assert_eq!(&decoded, op);
2786 }
2787 }
2788
2789 #[cfg(feature = "use-std")]
2790 #[test]
2791 fn i2c_batch_ops_take_from_bytes() {
2792 let ops = [
2793 I2cBatchOp::Write {
2794 data: &[0xAA, 0xBB],
2795 },
2796 I2cBatchOp::Read { len: 4 },
2797 ];
2798 let encoded = encode_i2c_batch_ops(&ops);
2799 let mut remaining: &[u8] = &encoded;
2800 let mut decoded = Vec::new();
2801 while !remaining.is_empty() {
2802 let (op, rest) = postcard::take_from_bytes::<I2cBatchOp>(remaining).unwrap();
2803 decoded.push(op);
2804 remaining = rest;
2805 }
2806 assert_eq!(decoded.len(), 2);
2807 assert_eq!(decoded[0], ops[0]);
2808 assert_eq!(decoded[1], ops[1]);
2809 }
2810
2811 #[cfg(feature = "use-std")]
2812 #[test]
2813 fn spi_batch_ops_take_from_bytes() {
2814 let ops = [
2815 SpiBatchOp::Write {
2816 data: &[0x01, 0x02],
2817 },
2818 SpiBatchOp::Read { len: 8 },
2819 SpiBatchOp::Transfer { data: &[0xFF; 4] },
2820 SpiBatchOp::DelayNs { ns: 1000 },
2821 ];
2822 let encoded = encode_spi_batch_ops(&ops);
2823 let mut remaining: &[u8] = &encoded;
2824 let mut decoded = Vec::new();
2825 while !remaining.is_empty() {
2826 let (op, rest) = postcard::take_from_bytes::<SpiBatchOp>(remaining).unwrap();
2827 decoded.push(op);
2828 remaining = rest;
2829 }
2830 assert_eq!(decoded.len(), 4);
2831 for (d, o) in decoded.iter().zip(ops.iter()) {
2832 assert_eq!(d, o);
2833 }
2834 }
2835
2836 #[cfg(feature = "use-std")]
2837 #[test]
2838 fn i2c_batch_request_round_trip() {
2839 let ops = encode_i2c_batch_ops(&[
2840 I2cBatchOp::Write {
2841 data: &[0xAA, 0xBB],
2842 },
2843 I2cBatchOp::Read { len: 4 },
2844 ]);
2845 let req = I2cBatchRequest {
2846 address: 0x50,
2847 count: 2,
2848 ops: &ops,
2849 };
2850 let bytes = to_allocvec(&req).unwrap();
2851 let decoded: I2cBatchRequest = from_bytes(&bytes).unwrap();
2852 assert_eq!(decoded, req);
2853 }
2854
2855 #[cfg(feature = "use-std")]
2856 #[test]
2857 fn spi_batch_request_round_trip() {
2858 let ops = encode_spi_batch_ops(&[
2859 SpiBatchOp::Write {
2860 data: &[0x01, 0x02],
2861 },
2862 SpiBatchOp::Read { len: 8 },
2863 SpiBatchOp::Transfer { data: &[0xFF; 4] },
2864 SpiBatchOp::DelayNs { ns: 1000 },
2865 ]);
2866 let req = SpiBatchRequest {
2867 cs_pin: 2,
2868 count: 4,
2869 ops: &ops,
2870 };
2871 let bytes = to_allocvec(&req).unwrap();
2872 let decoded: SpiBatchRequest = from_bytes(&bytes).unwrap();
2873 assert_eq!(decoded, req);
2874 }
2875
2876 #[test]
2877 fn i2c_batch_error_round_trip() {
2878 let err = I2cBatchError {
2879 failed_op: 3,
2880 kind: I2cError::NoAcknowledge,
2881 };
2882 let bytes = to_allocvec(&err).unwrap();
2883 let decoded: I2cBatchError = from_bytes(&bytes).unwrap();
2884 assert_eq!(decoded, err);
2885 }
2886
2887 #[test]
2888 fn spi_batch_error_round_trip() {
2889 let err = SpiBatchError {
2890 failed_op: 1,
2891 kind: SpiError::Other,
2892 };
2893 let bytes = to_allocvec(&err).unwrap();
2894 let decoded: SpiBatchError = from_bytes(&bytes).unwrap();
2895 assert_eq!(decoded, err);
2896 }
2897
2898 #[cfg(feature = "use-std")]
2899 #[test]
2900 fn encode_i2c_empty_batch() {
2901 let ops = encode_i2c_batch_ops(&[]);
2902 assert!(ops.is_empty());
2903 assert_eq!(i2c_batch_response_len(&[]), 0);
2904 }
2905
2906 #[cfg(feature = "use-std")]
2907 #[test]
2908 fn encode_spi_empty_batch() {
2909 let ops = encode_spi_batch_ops(&[]);
2910 assert!(ops.is_empty());
2911 assert_eq!(spi_batch_response_len(&[]), 0);
2912 }
2913
2914 #[test]
2915 fn i2c_batch_response_len_mixed() {
2916 let ops = [
2917 I2cBatchOp::Write {
2918 data: &[0x00, 0x10],
2919 },
2920 I2cBatchOp::Read { len: 16 },
2921 I2cBatchOp::Write {
2922 data: &[0x00, 0x20],
2923 },
2924 I2cBatchOp::Read { len: 32 },
2925 ];
2926 assert_eq!(i2c_batch_response_len(&ops), 48);
2927 }
2928
2929 #[test]
2930 fn spi_batch_response_len_mixed() {
2931 let ops = [
2932 SpiBatchOp::Write {
2933 data: &[0x01, 0x02],
2934 },
2935 SpiBatchOp::Read { len: 8 },
2936 SpiBatchOp::Transfer { data: &[0xFF; 4] },
2937 SpiBatchOp::DelayNs { ns: 1000 },
2938 ];
2939 assert_eq!(spi_batch_response_len(&ops), 12);
2941 }
2942
2943 #[cfg(feature = "use-std")]
2944 #[test]
2945 #[should_panic(expected = "too many batch operations")]
2946 fn encode_i2c_batch_ops_panics_over_limit() {
2947 let ops: Vec<I2cBatchOp> = (0..MAX_BATCH_OPS + 1)
2948 .map(|_| I2cBatchOp::Read { len: 1 })
2949 .collect();
2950 encode_i2c_batch_ops(&ops);
2951 }
2952
2953 #[cfg(feature = "use-std")]
2954 #[test]
2955 #[should_panic(expected = "too many batch operations")]
2956 fn encode_spi_batch_ops_panics_over_limit() {
2957 let ops: Vec<SpiBatchOp> = (0..MAX_BATCH_OPS + 1)
2958 .map(|_| SpiBatchOp::Read { len: 1 })
2959 .collect();
2960 encode_spi_batch_ops(&ops);
2961 }
2962
2963 #[cfg(feature = "use-std")]
2964 #[test]
2965 fn i2c_batch_ops_at_max_limit() {
2966 let ops: Vec<I2cBatchOp> = (0..MAX_BATCH_OPS)
2967 .map(|_| I2cBatchOp::Read { len: 1 })
2968 .collect();
2969 let encoded = encode_i2c_batch_ops(&ops);
2970 let mut remaining: &[u8] = &encoded;
2972 let mut count = 0;
2973 while !remaining.is_empty() {
2974 let (_, rest) = postcard::take_from_bytes::<I2cBatchOp>(remaining).unwrap();
2975 remaining = rest;
2976 count += 1;
2977 }
2978 assert_eq!(count, MAX_BATCH_OPS);
2979 assert_eq!(i2c_batch_response_len(&ops), MAX_BATCH_OPS);
2980 }
2981
2982 #[cfg(feature = "use-std")]
2983 #[test]
2984 fn spi_batch_ops_at_max_limit() {
2985 let ops: Vec<SpiBatchOp> = (0..MAX_BATCH_OPS)
2986 .map(|_| SpiBatchOp::Read { len: 1 })
2987 .collect();
2988 let encoded = encode_spi_batch_ops(&ops);
2989 let mut remaining: &[u8] = &encoded;
2990 let mut count = 0;
2991 while !remaining.is_empty() {
2992 let (_, rest) = postcard::take_from_bytes::<SpiBatchOp>(remaining).unwrap();
2993 remaining = rest;
2994 count += 1;
2995 }
2996 assert_eq!(count, MAX_BATCH_OPS);
2997 assert_eq!(spi_batch_response_len(&ops), MAX_BATCH_OPS);
2998 }
2999
3000 #[test]
3001 fn i2c_batch_write_only_response_len() {
3002 let ops = [
3003 I2cBatchOp::Write {
3004 data: &[0x00, 0x10],
3005 },
3006 I2cBatchOp::Write { data: &[0xFF; 32] },
3007 ];
3008 assert_eq!(i2c_batch_response_len(&ops), 0);
3010 }
3011
3012 #[test]
3013 #[cfg(feature = "use-std")]
3014 fn i2c_batch_error_display() {
3015 let err = I2cBatchError {
3016 failed_op: 2,
3017 kind: I2cError::Bus,
3018 };
3019 assert_eq!(
3020 format!("{err}"),
3021 "I2C batch operation 2 failed: I2C bus error"
3022 );
3023 }
3024
3025 #[test]
3026 #[cfg(feature = "use-std")]
3027 fn spi_batch_error_display() {
3028 let err = SpiBatchError {
3029 failed_op: 0,
3030 kind: SpiError::Other,
3031 };
3032 assert_eq!(format!("{err}"), "SPI batch operation 0 failed: SPI error");
3033 }
3034
3035 #[test]
3038 fn onewire_read_request_round_trip() {
3039 let req = OneWireReadRequest { len: 9 };
3040 let bytes = to_allocvec(&req).unwrap();
3041 let decoded: OneWireReadRequest = from_bytes(&bytes).unwrap();
3042 assert_eq!(req, decoded);
3043 }
3044
3045 #[test]
3046 fn onewire_write_request_round_trip() {
3047 let data = [0xCC, 0x44];
3048 let req = OneWireWriteRequest { data: &data };
3049 let bytes = to_allocvec(&req).unwrap();
3050 let decoded: OneWireWriteRequest = from_bytes(&bytes).unwrap();
3051 assert_eq!(req, decoded);
3052 }
3053
3054 #[test]
3055 fn onewire_write_pullup_request_round_trip() {
3056 let data = [0xCC, 0x44];
3057 let req = OneWireWritePullupRequest {
3058 data: &data,
3059 pullup_duration_ms: 750,
3060 };
3061 let bytes = to_allocvec(&req).unwrap();
3062 let decoded: OneWireWritePullupRequest = from_bytes(&bytes).unwrap();
3063 assert_eq!(req, decoded);
3064 }
3065
3066 #[test]
3067 fn onewire_error_variants_round_trip() {
3068 for err in [
3069 OneWireError::NoPresence,
3070 OneWireError::BusError,
3071 OneWireError::BufferTooLong,
3072 OneWireError::Other,
3073 OneWireError::Unsupported,
3074 ] {
3075 let bytes = to_allocvec(&err).unwrap();
3076 let decoded: OneWireError = from_bytes(&bytes).unwrap();
3077 assert_eq!(err, decoded);
3078 }
3079 }
3080
3081 #[test]
3082 #[cfg(feature = "use-std")]
3083 fn onewire_error_display() {
3084 assert_eq!(
3085 format!("{}", OneWireError::NoPresence),
3086 "no device present on 1-Wire bus"
3087 );
3088 assert_eq!(format!("{}", OneWireError::BusError), "1-Wire bus error");
3089 assert_eq!(
3090 format!("{}", OneWireError::BufferTooLong),
3091 "buffer exceeds firmware limit"
3092 );
3093 assert_eq!(format!("{}", OneWireError::Other), "1-Wire error");
3094 assert_eq!(
3095 format!("{}", OneWireError::Unsupported),
3096 "1-Wire not supported on this hardware"
3097 );
3098 }
3099
3100 #[test]
3101 fn onewire_error_discriminants_are_stable() {
3102 assert_eq!(to_allocvec(&OneWireError::NoPresence).unwrap(), [0]);
3103 assert_eq!(to_allocvec(&OneWireError::BusError).unwrap(), [1]);
3104 assert_eq!(to_allocvec(&OneWireError::BufferTooLong).unwrap(), [2]);
3105 assert_eq!(to_allocvec(&OneWireError::Other).unwrap(), [3]);
3106 assert_eq!(to_allocvec(&OneWireError::Unsupported).unwrap(), [4]);
3107 }
3108
3109 #[test]
3110 fn onewire_read_request_wire_stability() {
3111 let req = OneWireReadRequest { len: 9 };
3112 let bytes = to_allocvec(&req).unwrap();
3113 let canonical = bytes.clone();
3114 let decoded: OneWireReadRequest = from_bytes(&bytes).unwrap();
3115 assert_eq!(decoded, req);
3116 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
3117 }
3118
3119 #[test]
3120 fn onewire_write_pullup_request_wire_stability() {
3121 let data = [0xCC, 0x44];
3122 let req = OneWireWritePullupRequest {
3123 data: &data,
3124 pullup_duration_ms: 750,
3125 };
3126 let bytes = to_allocvec(&req).unwrap();
3127 let canonical = bytes.clone();
3128 let decoded: OneWireWritePullupRequest = from_bytes(&bytes).unwrap();
3129 assert_eq!(decoded, req);
3130 assert_eq!(to_allocvec(&decoded).unwrap(), canonical);
3131 }
3132
3133 #[test]
3134 fn onewire_read_request_zero_len() {
3135 let req = OneWireReadRequest { len: 0 };
3136 let bytes = to_allocvec(&req).unwrap();
3137 let decoded: OneWireReadRequest = from_bytes(&bytes).unwrap();
3138 assert_eq!(req, decoded);
3139 }
3140
3141 #[test]
3142 fn onewire_read_request_max_len() {
3143 let req = OneWireReadRequest { len: u16::MAX };
3144 let bytes = to_allocvec(&req).unwrap();
3145 let decoded: OneWireReadRequest = from_bytes(&bytes).unwrap();
3146 assert_eq!(req, decoded);
3147 }
3148
3149 #[test]
3150 fn onewire_write_request_empty() {
3151 let req = OneWireWriteRequest { data: &[] };
3152 let bytes = to_allocvec(&req).unwrap();
3153 let decoded: OneWireWriteRequest = from_bytes(&bytes).unwrap();
3154 assert_eq!(req, decoded);
3155 }
3156
3157 #[test]
3158 fn onewire_search_response_some_round_trip() {
3159 let resp: OneWireSearchResponse = Ok(Some(0x0028_FF12_3456_7800));
3160 let bytes = to_allocvec(&resp).unwrap();
3161 let decoded: OneWireSearchResponse = from_bytes(&bytes).unwrap();
3162 assert_eq!(resp, decoded);
3163 }
3164
3165 #[test]
3166 fn onewire_search_response_none_round_trip() {
3167 let resp: OneWireSearchResponse = Ok(None);
3168 let bytes = to_allocvec(&resp).unwrap();
3169 let decoded: OneWireSearchResponse = from_bytes(&bytes).unwrap();
3170 assert_eq!(resp, decoded);
3171 }
3172
3173 #[test]
3174 fn onewire_reset_response_round_trip() {
3175 for present in [true, false] {
3176 let resp: OneWireResetResponse = Ok(present);
3177 let bytes = to_allocvec(&resp).unwrap();
3178 let decoded: OneWireResetResponse = from_bytes(&bytes).unwrap();
3179 assert_eq!(resp, decoded);
3180 }
3181 }
3182
3183 #[test]
3188 fn capabilities_bitflag_basics() {
3189 let caps = Capabilities::I2C | Capabilities::SPI;
3190 assert!(caps.contains(Capabilities::I2C));
3191 assert!(caps.contains(Capabilities::SPI));
3192 assert!(!caps.contains(Capabilities::UART));
3193 assert!(!caps.contains(Capabilities::GPIO));
3194 assert_eq!(caps.bits(), 0b11);
3195 }
3196
3197 #[test]
3198 fn capabilities_none_is_zero() {
3199 assert_eq!(Capabilities::NONE.bits(), 0);
3200 assert!(!Capabilities::NONE.contains(Capabilities::I2C));
3201 }
3202
3203 #[test]
3204 fn capabilities_round_trip() {
3205 let caps = Capabilities::I2C
3206 | Capabilities::SPI
3207 | Capabilities::GPIO
3208 | Capabilities::PWM
3209 | Capabilities::ADC;
3210 let bytes = to_allocvec(&caps).unwrap();
3211 let decoded: Capabilities = from_bytes(&bytes).unwrap();
3212 assert_eq!(caps, decoded);
3213 }
3214
3215 #[test]
3216 fn device_info_round_trip() {
3217 let info = DeviceInfo {
3218 fw_major: 0,
3219 fw_minor: 8,
3220 fw_patch: 0,
3221 schema_major: 0,
3222 schema_minor: 4,
3223 schema_patch: 0,
3224 hw_version: 1,
3225 capabilities: Capabilities::I2C
3226 | Capabilities::SPI
3227 | Capabilities::UART
3228 | Capabilities::GPIO
3229 | Capabilities::PWM
3230 | Capabilities::ADC
3231 | Capabilities::ONEWIRE,
3232 };
3233 let bytes = to_allocvec(&info).unwrap();
3234 let decoded: DeviceInfo = from_bytes(&bytes).unwrap();
3235 assert_eq!(info, decoded);
3236 }
3237
3238 #[test]
3239 fn device_info_no_capabilities_round_trip() {
3240 let info = DeviceInfo {
3241 fw_major: 1,
3242 fw_minor: 0,
3243 fw_patch: 0,
3244 schema_major: 1,
3245 schema_minor: 0,
3246 schema_patch: 0,
3247 hw_version: 2,
3248 capabilities: Capabilities::NONE,
3249 };
3250 let bytes = to_allocvec(&info).unwrap();
3251 let decoded: DeviceInfo = from_bytes(&bytes).unwrap();
3252 assert_eq!(info, decoded);
3253 }
3254}