1use super::{
49 bsd_16_crc,
50 parameter::{
51 decode_string_bytes, BrokerState, DefaultSlotValue, DhcpMode, DiscoveryCountStatus,
52 DiscoveryState, DisplayInvertMode, EndpointId, EndpointMode, EndpointType, Ipv4Address,
53 Ipv4Route, Ipv6Address, LampOnMode, LampState, MergeMode, NetworkInterface,
54 ParameterDescription, ParameterId, PinCode, PowerState, PresetPlaybackMode,
55 PresetProgrammed, ProductCategory, ProductDetail, ProtocolVersion, SelfTest,
56 SensorDefinition, SensorValue, SlotInfo, StaticConfigType, StatusMessage, StatusType,
57 SupportedTimes, TimeMode,
58 },
59 CommandClass, DeviceUID, EncodedFrame, EncodedParameterData, RdmError, SubDeviceId,
60 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE, DISCOVERY_UNIQUE_BRANCH_PREAMBLE_SEPARATOR_BYTE,
61 RDM_START_CODE_BYTE, RDM_SUB_START_CODE_BYTE,
62};
63use core::{fmt::Display, iter, result::Result};
64use macaddr::MacAddr6;
65
66#[cfg(not(feature = "alloc"))]
67use heapless::{String, Vec};
68
69#[derive(Copy, Clone, Debug, PartialEq)]
70pub enum ResponseNackReasonCode {
71 UnknownPid = 0x0000,
72 FormatError = 0x0001,
73 HardwareFault = 0x0002,
74 ProxyReject = 0x0003,
75 WriteProtect = 0x0004,
76 UnsupportedCommandClass = 0x0005,
77 DataOutOfRange = 0x0006,
78 BufferFull = 0x0007,
79 PacketSizeUnsupported = 0x0008,
80 SubDeviceIdOutOfRange = 0x0009,
81 ProxyBufferFull = 0x000a,
82 ActionNotSupported = 0x000b,
83 EndpointNumberInvalid = 0x000c,
84 InvalidEndpointMode = 0x000d,
85 UnknownUid = 0x000e,
86}
87
88impl TryFrom<u16> for ResponseNackReasonCode {
89 type Error = RdmError;
90
91 fn try_from(value: u16) -> Result<Self, RdmError> {
92 match value {
93 0x0000 => Ok(Self::UnknownPid),
94 0x0001 => Ok(Self::FormatError),
95 0x0002 => Ok(Self::HardwareFault),
96 0x0003 => Ok(Self::ProxyReject),
97 0x0004 => Ok(Self::WriteProtect),
98 0x0005 => Ok(Self::UnsupportedCommandClass),
99 0x0006 => Ok(Self::DataOutOfRange),
100 0x0007 => Ok(Self::BufferFull),
101 0x0008 => Ok(Self::PacketSizeUnsupported),
102 0x0009 => Ok(Self::SubDeviceIdOutOfRange),
103 0x000a => Ok(Self::ProxyBufferFull),
104 0x000b => Ok(Self::ActionNotSupported),
105 0x000c => Ok(Self::EndpointNumberInvalid),
106 0x000d => Ok(Self::InvalidEndpointMode),
107 0x000e => Ok(Self::UnknownUid),
108 value => Err(RdmError::InvalidNackReasonCode(value)),
109 }
110 }
111}
112
113impl Display for ResponseNackReasonCode {
114 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
115 let message = match self {
116 Self::UnknownPid => "The responder cannot comply with request because the message is not implemented in responder.",
117 Self::FormatError => "The responder cannot interpret request as controller data was not formatted correctly.",
118 Self::HardwareFault => "The responder cannot comply due to an internal hardware fault.",
119 Self::ProxyReject => "Proxy is not the RDM line master and cannot comply with message.",
120 Self::WriteProtect => "Command normally allowed but being blocked currently.",
121 Self::UnsupportedCommandClass => "Not valid for Command Class attempted. May be used where GET allowed but SET is not supported.",
122 Self::DataOutOfRange => "Value for given Parameter out of allowable range or not supported.",
123 Self::BufferFull => "Buffer or Queue space currently has no free space to store data.",
124 Self::PacketSizeUnsupported => "Incoming message exceeds buffer capacity.",
125 Self::SubDeviceIdOutOfRange => "Sub-Device is out of range or unknown.",
126 Self::ProxyBufferFull => "The proxy buffer is full and can not store any more Queued Message or Status Message responses.",
127 Self::ActionNotSupported => "The parameter data is valid but the SET operation cannot be performed with the current configuration.",
128 Self::EndpointNumberInvalid => "The Endpoint Number is invalid.",
129 Self::InvalidEndpointMode => "The Endpoint Mode is invalid.",
130 Self::UnknownUid => "The UID is not known to the responder.",
131 };
132
133 f.write_str(message)
134 }
135}
136
137#[derive(Copy, Clone, Debug, PartialEq)]
138pub enum ResponseType {
139 Ack = 0x00,
140 AckTimer = 0x01,
141 NackReason = 0x02,
142 AckOverflow = 0x03,
143}
144
145impl TryFrom<u8> for ResponseType {
146 type Error = RdmError;
147
148 fn try_from(value: u8) -> Result<Self, Self::Error> {
149 match value {
150 0x00 => Ok(Self::Ack),
151 0x01 => Ok(Self::AckTimer),
152 0x02 => Ok(Self::NackReason),
153 0x03 => Ok(Self::AckOverflow),
154 _ => Err(RdmError::InvalidResponseType(value)),
155 }
156 }
157}
158
159#[allow(clippy::large_enum_variant)]
160#[derive(Clone, Debug, PartialEq)]
161pub enum ResponseData {
162 ParameterData(Option<ResponseParameterData>),
163 EstimateResponseTime(u16),
164 NackReason(ResponseNackReasonCode),
165}
166
167impl ResponseData {
168 pub fn encode(&self) -> EncodedParameterData {
169 #[cfg(feature = "alloc")]
170 let mut buf = Vec::new();
171
172 #[cfg(not(feature = "alloc"))]
173 let mut buf = Vec::new();
174
175 match self {
176 Self::ParameterData(Some(data)) => {
177 let data = data.encode();
178
179 #[cfg(feature = "alloc")]
180 buf.reserve(data.len());
181
182 buf.extend(data);
183 }
184 Self::ParameterData(None) => {}
185 Self::EstimateResponseTime(time) => {
186 #[cfg(feature = "alloc")]
187 buf.reserve(2);
188
189 buf.extend(time.to_be_bytes());
190 }
191 Self::NackReason(reason) => {
192 #[cfg(feature = "alloc")]
193 buf.reserve(2);
194
195 buf.extend((*reason as u16).to_be_bytes());
196 }
197 }
198
199 buf
200 }
201
202 pub fn decode(
203 response_type: ResponseType,
204 command_class: CommandClass,
205 parameter_data_length: u8,
206 parameter_id: ParameterId,
207 bytes: &[u8],
208 ) -> Result<Self, RdmError> {
209 match response_type {
210 ResponseType::Ack | ResponseType::AckOverflow => {
211 let parameter_data = if parameter_data_length > 0 {
212 Some(ResponseParameterData::decode(
213 command_class,
214 parameter_id,
215 bytes,
216 )?)
217 } else {
218 None
219 };
220
221 Ok(ResponseData::ParameterData(parameter_data))
222 }
223 ResponseType::AckTimer => {
224 let estimated_response_time = u16::from_be_bytes(bytes[0..=1].try_into()?);
225
226 Ok(ResponseData::EstimateResponseTime(estimated_response_time))
227 }
228 ResponseType::NackReason => {
229 let nack_reason = u16::from_be_bytes(bytes[0..=1].try_into()?).try_into()?;
230
231 Ok(ResponseData::NackReason(nack_reason))
232 }
233 }
234 }
235}
236
237#[allow(clippy::large_enum_variant)]
238#[non_exhaustive]
239#[derive(Clone, Debug, PartialEq)]
240pub enum ResponseParameterData {
241 DiscMute {
243 control_field: u16,
244 binding_uid: Option<DeviceUID>,
245 },
246 DiscUnMute {
247 control_field: u16,
248 binding_uid: Option<DeviceUID>,
249 },
250 GetProxiedDeviceCount {
251 device_count: u16,
252 list_change: bool,
253 },
254 GetProxiedDevices(
255 #[cfg(feature = "alloc")] Vec<DeviceUID>,
256 #[cfg(not(feature = "alloc"))] Vec<DeviceUID, 38>,
257 ),
258 GetCommsStatus {
259 short_message: u16,
260 length_mismatch: u16,
261 checksum_fail: u16,
262 },
263 GetStatusMessages(
264 #[cfg(feature = "alloc")] Vec<StatusMessage>,
265 #[cfg(not(feature = "alloc"))] Vec<StatusMessage, 25>,
266 ),
267 GetStatusIdDescription(
268 #[cfg(feature = "alloc")] String,
269 #[cfg(not(feature = "alloc"))] String<32>,
270 ),
271 GetSubDeviceIdStatusReportThreshold(StatusType),
272 GetSupportedParameters(
273 #[cfg(feature = "alloc")] Vec<u16>,
274 #[cfg(not(feature = "alloc"))] Vec<u16, 115>,
275 ),
276 GetParameterDescription(ParameterDescription),
277 GetDeviceInfo {
278 protocol_version: ProtocolVersion,
279 model_id: u16,
280 product_category: ProductCategory,
281 software_version_id: u32,
282 footprint: u16,
283 current_personality: u8,
284 personality_count: u8,
285 start_address: u16,
286 sub_device_count: u16,
287 sensor_count: u8,
288 },
289 GetProductDetailIdList(
290 #[cfg(feature = "alloc")] Vec<ProductDetail>,
291 #[cfg(not(feature = "alloc"))] Vec<ProductDetail, 115>,
292 ),
293 GetDeviceModelDescription(
294 #[cfg(feature = "alloc")] String,
295 #[cfg(not(feature = "alloc"))] String<32>,
296 ),
297 GetManufacturerLabel(
298 #[cfg(feature = "alloc")] String,
299 #[cfg(not(feature = "alloc"))] String<32>,
300 ),
301 GetDeviceLabel(
302 #[cfg(feature = "alloc")] String,
303 #[cfg(not(feature = "alloc"))] String<32>,
304 ),
305 GetFactoryDefaults(bool),
306 GetLanguageCapabilities(
307 #[cfg(feature = "alloc")] Vec<String>,
308 #[cfg(not(feature = "alloc"))] Vec<String<2>, 115>,
309 ),
310 GetLanguage(
311 #[cfg(feature = "alloc")] String,
312 #[cfg(not(feature = "alloc"))] String<2>,
313 ),
314 GetSoftwareVersionLabel(
315 #[cfg(feature = "alloc")] String,
316 #[cfg(not(feature = "alloc"))] String<32>,
317 ),
318 GetBootSoftwareVersionId(u32),
319 GetBootSoftwareVersionLabel(
320 #[cfg(feature = "alloc")] String,
321 #[cfg(not(feature = "alloc"))] String<32>,
322 ),
323 GetDmxPersonality {
324 current_personality: u8,
325 personality_count: u8,
326 },
327 GetDmxPersonalityDescription {
328 id: u8,
329 dmx_slots_required: u16,
330 #[cfg(feature = "alloc")]
331 description: String,
332 #[cfg(not(feature = "alloc"))]
333 description: String<32>,
334 },
335 GetDmxStartAddress(u16),
336 GetSlotInfo(
337 #[cfg(feature = "alloc")] Vec<SlotInfo>,
338 #[cfg(not(feature = "alloc"))] Vec<SlotInfo, 46>,
339 ),
340 GetSlotDescription {
341 slot_id: u16,
342 #[cfg(feature = "alloc")]
343 description: String,
344 #[cfg(not(feature = "alloc"))]
345 description: String<32>,
346 },
347 GetDefaultSlotValue(
348 #[cfg(feature = "alloc")] Vec<DefaultSlotValue>,
349 #[cfg(not(feature = "alloc"))] Vec<DefaultSlotValue, 77>,
350 ),
351 GetSensorDefinition(SensorDefinition),
352 GetSensorValue(SensorValue),
353 SetSensorValue(SensorValue),
354 GetDeviceHours(u32),
355 GetLampHours(u32),
356 GetLampStrikes(u32),
357 GetLampState(LampState),
358 GetLampOnMode(LampOnMode),
359 GetDevicePowerCycles(u32),
360 GetDisplayInvert(DisplayInvertMode),
361 GetDisplayLevel(u8),
362 GetPanInvert(bool),
363 GetTiltInvert(bool),
364 GetPanTiltSwap(bool),
365 GetRealTimeClock {
366 year: u16,
367 month: u8,
368 day: u8,
369 hour: u8,
370 minute: u8,
371 second: u8,
372 },
373 GetIdentifyDevice(bool),
374 GetPowerState(PowerState),
375 GetPerformSelfTest(bool),
376 GetSelfTestDescription {
377 self_test_id: SelfTest,
378 #[cfg(feature = "alloc")]
379 description: String,
380 #[cfg(not(feature = "alloc"))]
381 description: String<32>,
382 },
383 GetPresetPlayback {
384 mode: PresetPlaybackMode,
385 level: u8,
386 },
387 GetDmxBlockAddress {
389 total_sub_device_footprint: u16,
390 base_dmx_address: u16,
391 },
392 GetDmxFailMode {
393 scene_id: PresetPlaybackMode,
394 loss_of_signal_delay: TimeMode,
395 hold_time: TimeMode,
396 level: u8,
397 },
398 GetDmxStartupMode {
399 scene_id: PresetPlaybackMode,
400 startup_delay: TimeMode,
401 hold_time: TimeMode,
402 level: u8,
403 },
404 GetPowerOnSelfTest(bool),
405 GetLockState {
406 lock_state_id: u8,
407 lock_state_count: u8,
408 },
409 GetLockStateDescription {
410 lock_state_id: u8,
411 #[cfg(feature = "alloc")]
412 description: String,
413 #[cfg(not(feature = "alloc"))]
414 description: String<32>,
415 },
416 GetLockPin(PinCode),
417 GetBurnIn(u8),
418 GetDimmerInfo {
419 minimum_level_lower_limit: u16,
420 minimum_level_upper_limit: u16,
421 maximum_level_lower_limit: u16,
422 maximum_level_upper_limit: u16,
423 number_of_supported_curves: u8,
424 levels_resolution: u8,
425 minimum_level_split_levels_supported: bool,
426 },
427 GetMinimumLevel {
428 minimum_level_increasing: u16,
429 minimum_level_decreasing: u16,
430 on_below_minimum: bool,
431 },
432 GetMaximumLevel(u16),
433 GetCurve {
434 curve_id: u8,
435 curve_count: u8,
436 },
437 GetCurveDescription {
438 curve_id: u8,
439 #[cfg(feature = "alloc")]
440 description: String,
441 #[cfg(not(feature = "alloc"))]
442 description: String<32>,
443 },
444 GetOutputResponseTime {
445 response_time_id: u8,
446 response_time_count: u8,
447 },
448 GetOutputResponseTimeDescription {
449 response_time_id: u8,
450 #[cfg(feature = "alloc")]
451 description: String,
452 #[cfg(not(feature = "alloc"))]
453 description: String<32>,
454 },
455 GetModulationFrequency {
456 modulation_frequency_id: u8,
457 modulation_frequency_count: u8,
458 },
459 GetModulationFrequencyDescription {
460 modulation_frequency_id: u8,
461 frequency: u32,
462 #[cfg(feature = "alloc")]
463 description: String,
464 #[cfg(not(feature = "alloc"))]
465 description: String<32>,
466 },
467 GetPresetInfo {
468 level_field_supported: bool,
469 preset_sequence_supported: bool,
470 split_times_supported: bool,
471 dmx_fail_infinite_delay_time_supported: bool,
472 dmx_fail_infinite_hold_time_supported: bool,
473 startup_infinite_hold_time_supported: bool,
474 maximum_scene_number: u16,
475 minimum_preset_fade_time_supported: u16,
476 maximum_preset_fade_time_supported: u16,
477 minimum_preset_wait_time_supported: u16,
478 maximum_preset_wait_time_supported: u16,
479 minimum_dmx_fail_delay_time_supported: SupportedTimes,
480 maximum_dmx_fail_delay_time_supported: SupportedTimes,
481 minimum_dmx_fail_hold_time_supported: SupportedTimes,
482 maximum_dmx_fail_hold_time_supported: SupportedTimes,
483 minimum_startup_delay_time_supported: SupportedTimes,
484 maximum_startup_delay_time_supported: SupportedTimes,
485 minimum_startup_hold_time_supported: SupportedTimes,
486 maximum_startup_hold_time_supported: SupportedTimes,
487 },
488 GetPresetStatus {
489 scene_id: u16,
490 up_fade_time: u16,
491 down_fade_time: u16,
492 wait_time: u16,
493 programmed: PresetProgrammed,
494 },
495 GetPresetMergeMode(MergeMode),
496 GetListInterfaces(
498 #[cfg(feature = "alloc")] Vec<NetworkInterface>,
499 #[cfg(not(feature = "alloc"))] Vec<NetworkInterface, 38>,
500 ),
501 GetInterfaceLabel {
502 interface_id: u32,
503 #[cfg(feature = "alloc")]
504 interface_label: String,
505 #[cfg(not(feature = "alloc"))]
506 interface_label: String<32>,
507 },
508 GetInterfaceHardwareAddressType1 {
509 interface_id: u32,
510 hardware_address: MacAddr6,
511 },
512 GetIpV4DhcpMode {
513 interface_id: u32,
514 dhcp_mode: bool,
515 },
516 GetIpV4ZeroConfMode {
517 interface_id: u32,
518 zero_conf_mode: bool,
519 },
520 GetIpV4CurrentAddress {
521 interface_id: u32,
522 address: Ipv4Address,
523 netmask: u8,
524 dhcp_status: DhcpMode,
525 },
526 GetIpV4StaticAddress {
527 interface_id: u32,
528 address: Ipv4Address,
529 netmask: u8,
530 },
531 GetIpV4DefaultRoute {
532 interface_id: u32,
533 address: Ipv4Route,
534 },
535 GetDnsIpV4NameServer {
536 name_server_index: u8,
537 address: Ipv4Address,
538 },
539 GetDnsHostName(
540 #[cfg(feature = "alloc")] String,
541 #[cfg(not(feature = "alloc"))] String<63>,
542 ),
543 GetDnsDomainName(
544 #[cfg(feature = "alloc")] String,
545 #[cfg(not(feature = "alloc"))] String<32>,
546 ),
547 GetEndpointList {
549 list_change_number: u32,
550 #[cfg(feature = "alloc")]
551 endpoint_list: Vec<(EndpointId, EndpointType)>,
552 #[cfg(not(feature = "alloc"))]
553 endpoint_list: Vec<(EndpointId, EndpointType), 75>,
554 },
555 GetEndpointListChange {
556 list_change_number: u32,
557 },
558 GetIdentifyEndpoint {
559 endpoint_id: EndpointId,
560 identify: bool,
561 },
562 SetIdentifyEndpoint {
563 endpoint_id: EndpointId,
564 },
565 GetEndpointToUniverse {
566 endpoint_id: EndpointId,
567 universe: u16,
568 },
569 SetEndpointToUniverse {
570 endpoint_id: EndpointId,
571 },
572 GetEndpointMode {
573 endpoint_id: EndpointId,
574 mode: EndpointMode,
575 },
576 SetEndpointMode {
577 endpoint_id: EndpointId,
578 },
579 GetEndpointLabel {
580 endpoint_id: EndpointId,
581 #[cfg(feature = "alloc")]
582 label: String,
583 #[cfg(not(feature = "alloc"))]
584 label: String<32>,
585 },
586 SetEndpointLabel {
587 endpoint_id: EndpointId,
588 },
589 GetRdmTrafficEnable {
590 endpoint_id: EndpointId,
591 enable: bool,
592 },
593 SetRdmTrafficEnable {
594 endpoint_id: EndpointId,
595 },
596 GetDiscoveryState {
597 endpoint_id: EndpointId,
598 device_count: DiscoveryCountStatus,
599 discovery_state: DiscoveryState,
600 },
601 SetDiscoveryState {
602 endpoint_id: EndpointId,
603 },
604 GetBackgroundDiscovery {
605 endpoint_id: EndpointId,
606 enabled: bool,
607 },
608 SetBackgroundDiscovery {
609 endpoint_id: EndpointId,
610 },
611 GetEndpointTiming {
612 endpoint_id: EndpointId,
613 current_setting_id: u8,
614 setting_count: u8,
615 },
616 SetEndpointTiming {
617 endpoint_id: EndpointId,
618 },
619 GetEndpointTimingDescription {
620 setting_id: u8,
621 #[cfg(feature = "alloc")]
622 description: String,
623 #[cfg(not(feature = "alloc"))]
624 description: String<32>,
625 },
626 GetEndpointResponders {
627 endpoint_id: EndpointId,
628 list_change_number: u32,
629 #[cfg(feature = "alloc")]
630 responders: Vec<DeviceUID>,
631 #[cfg(not(feature = "alloc"))]
632 responders: Vec<DeviceUID, 37>,
633 },
634 GetEndpointResponderListChange {
635 endpoint_id: EndpointId,
636 list_change_number: u32,
637 },
638 GetBindingControlFields {
639 endpoint_id: EndpointId,
640 uid: DeviceUID,
641 control_field: u16,
642 binding_uid: DeviceUID,
643 },
644 GetBackgroundQueuedStatusPolicy {
645 current_policy_id: u8,
646 policy_count: u8,
647 },
648 GetBackgroundQueuedStatusPolicyDescription {
649 policy_id: u8,
650 #[cfg(feature = "alloc")]
651 description: String,
652 #[cfg(not(feature = "alloc"))]
653 description: String<32>,
654 },
655 GetComponentScope {
657 scope_slot: u16,
658 #[cfg(feature = "alloc")]
659 scope_string: String,
660 #[cfg(not(feature = "alloc"))]
661 scope_string: String<63>,
662 static_config_type: StaticConfigType,
663 static_ipv4_address: Ipv4Address,
664 static_ipv6_address: Ipv6Address,
665 static_port: u16,
666 },
667 GetSearchDomain(
668 #[cfg(feature = "alloc")] String,
669 #[cfg(not(feature = "alloc"))] String<231>,
670 ),
671 GetTcpCommsStatus {
672 #[cfg(feature = "alloc")]
673 scope_string: String,
674 #[cfg(not(feature = "alloc"))]
675 scope_string: String<231>,
676 broker_ipv4_address: Ipv4Address,
677 broker_ipv6_address: Ipv6Address,
678 broker_port: u16,
679 unhealthy_tcp_events: u16,
680 },
681 GetBrokerStatus {
682 is_allowing_set_commands: bool,
683 broker_state: BrokerState,
684 },
685 ManufacturerSpecific(
686 #[cfg(feature = "alloc")] Vec<u8>,
687 #[cfg(not(feature = "alloc"))] Vec<u8, 231>,
688 ),
689 Unsupported(
690 #[cfg(feature = "alloc")] Vec<u8>,
691 #[cfg(not(feature = "alloc"))] Vec<u8, 231>,
692 ),
693}
694
695impl ResponseParameterData {
696 pub fn encode(&self) -> EncodedParameterData {
697 #[cfg(feature = "alloc")]
698 let mut buf = Vec::new();
699
700 #[cfg(not(feature = "alloc"))]
701 let mut buf = Vec::new();
702
703 match self {
704 Self::DiscMute {
705 control_field,
706 binding_uid,
707 } => {
708 #[cfg(feature = "alloc")]
709 buf.reserve(0x0e);
710
711 buf.extend(control_field.to_be_bytes());
712
713 if let Some(binding_uid) = binding_uid {
714 buf.extend(binding_uid.manufacturer_id.to_be_bytes());
715 buf.extend(binding_uid.device_id.to_be_bytes());
716 }
717 }
718 Self::DiscUnMute {
719 control_field,
720 binding_uid,
721 } => {
722 #[cfg(feature = "alloc")]
723 buf.reserve(0x0e);
724
725 buf.extend(control_field.to_be_bytes());
726
727 if let Some(binding_uid) = binding_uid {
728 buf.extend(binding_uid.manufacturer_id.to_be_bytes());
729 buf.extend(binding_uid.device_id.to_be_bytes());
730 }
731 }
732 Self::GetProxiedDeviceCount {
733 device_count,
734 list_change,
735 } => {
736 #[cfg(feature = "alloc")]
737 buf.reserve(0x03);
738
739 buf.extend(device_count.to_be_bytes());
740
741 #[cfg(feature = "alloc")]
742 buf.push(*list_change as u8);
743 #[cfg(not(feature = "alloc"))]
744 buf.push(*list_change as u8).unwrap();
745 }
746 Self::GetProxiedDevices(devices) => {
747 #[cfg(feature = "alloc")]
748 buf.reserve(devices.len() * 6);
749
750 for device in devices {
751 buf.extend(device.manufacturer_id.to_be_bytes());
752 buf.extend(device.device_id.to_be_bytes());
753 }
754 }
755 Self::GetCommsStatus {
756 short_message,
757 length_mismatch,
758 checksum_fail,
759 } => {
760 #[cfg(feature = "alloc")]
761 buf.reserve(6);
762
763 buf.extend(short_message.to_be_bytes());
764 buf.extend(length_mismatch.to_be_bytes());
765 buf.extend(checksum_fail.to_be_bytes());
766 }
767 Self::GetStatusMessages(messages) => {
768 for message in messages {
769 buf.extend(u16::from(message.sub_device_id).to_be_bytes());
770
771 #[cfg(feature = "alloc")]
772 buf.push(message.status_type as u8);
773 #[cfg(not(feature = "alloc"))]
774 buf.push(message.status_type as u8).unwrap();
775
776 buf.extend(message.status_message_id.to_be_bytes());
777 buf.extend(message.data_value1.to_be_bytes());
778 buf.extend(message.data_value2.to_be_bytes());
779
780 if let Some(description) = &message.description {
781 buf.extend(description.bytes());
782 }
783 }
784 }
785 Self::GetStatusIdDescription(description) => {
786 #[cfg(feature = "alloc")]
787 buf.reserve(description.len());
788
789 buf.extend(description.bytes());
790 }
791 Self::GetSubDeviceIdStatusReportThreshold(status) => {
792 #[cfg(feature = "alloc")]
793 buf.reserve(1);
794
795 #[cfg(feature = "alloc")]
796 buf.push(*status as u8);
797 #[cfg(not(feature = "alloc"))]
798 buf.push(*status as u8).unwrap();
799 }
800 Self::GetSupportedParameters(parameters) => {
801 #[cfg(feature = "alloc")]
802 buf.reserve(parameters.len() * 2);
803
804 for parameter in parameters {
805 buf.extend(parameter.to_be_bytes());
806 }
807 }
808 Self::GetParameterDescription(description) => {
809 #[cfg(feature = "alloc")]
810 buf.reserve(20 + description.description.len());
811
812 buf.extend(description.parameter_id.to_be_bytes());
813
814 #[cfg(feature = "alloc")]
815 buf.push(description.parameter_data_length);
816 #[cfg(not(feature = "alloc"))]
817 buf.push(description.parameter_data_length).unwrap();
818
819 #[cfg(feature = "alloc")]
820 buf.push(description.data_type.into());
821 #[cfg(not(feature = "alloc"))]
822 buf.push(description.data_type.into()).unwrap();
823
824 #[cfg(feature = "alloc")]
825 buf.push(description.command_class as u8);
826 #[cfg(not(feature = "alloc"))]
827 buf.push(description.command_class as u8).unwrap();
828
829 #[cfg(feature = "alloc")]
830 buf.push(description.command_class as u8);
831 #[cfg(not(feature = "alloc"))]
832 buf.push(description.command_class as u8).unwrap();
833
834 #[cfg(feature = "alloc")]
835 buf.push(description.unit_type.into());
836 #[cfg(not(feature = "alloc"))]
837 buf.push(description.unit_type.into()).unwrap();
838
839 #[cfg(feature = "alloc")]
840 buf.push(description.prefix as u8);
841 #[cfg(not(feature = "alloc"))]
842 buf.push(description.prefix as u8).unwrap();
843
844 buf.extend(description.raw_minimum_valid_value);
845 buf.extend(description.raw_maximum_valid_value);
846 buf.extend(description.raw_default_value);
847
848 #[cfg(feature = "alloc")]
849 buf.extend(description.description.bytes());
850 #[cfg(not(feature = "alloc"))]
851 buf.extend(description.description.bytes());
852 }
853 Self::GetDeviceInfo {
854 protocol_version,
855 model_id,
856 product_category,
857 software_version_id,
858 footprint,
859 current_personality,
860 personality_count,
861 start_address,
862 sub_device_count,
863 sensor_count,
864 } => {
865 #[cfg(feature = "alloc")]
866 buf.reserve(21);
867
868 buf.extend(u16::from(*protocol_version).to_be_bytes());
869
870 buf.extend(model_id.to_be_bytes());
871 buf.extend(u16::from(*product_category).to_be_bytes());
872 buf.extend(software_version_id.to_be_bytes());
873 buf.extend(footprint.to_be_bytes());
874
875 #[cfg(feature = "alloc")]
876 buf.push(*current_personality);
877 #[cfg(not(feature = "alloc"))]
878 buf.push(*current_personality).unwrap();
879
880 #[cfg(feature = "alloc")]
881 buf.push(*personality_count);
882 #[cfg(not(feature = "alloc"))]
883 buf.push(*personality_count).unwrap();
884
885 buf.extend(start_address.to_be_bytes());
886 buf.extend(sub_device_count.to_be_bytes());
887
888 #[cfg(feature = "alloc")]
889 buf.push(*sensor_count);
890 #[cfg(not(feature = "alloc"))]
891 buf.push(*sensor_count).unwrap();
892 }
893 Self::GetProductDetailIdList(details) => {
894 #[cfg(feature = "alloc")]
895 buf.reserve(details.len() * 2);
896
897 for &detail in details {
898 buf.extend(u16::from(detail).to_be_bytes());
899 }
900 }
901 Self::GetDeviceModelDescription(description) => {
902 #[cfg(feature = "alloc")]
903 buf.reserve(description.len());
904
905 buf.extend(description.bytes());
906 }
907 Self::GetManufacturerLabel(label) => {
908 #[cfg(feature = "alloc")]
909 buf.reserve(label.len());
910
911 buf.extend(label.bytes());
912 }
913 Self::GetDeviceLabel(label) => {
914 #[cfg(feature = "alloc")]
915 buf.reserve(label.len());
916
917 buf.extend(label.bytes());
918 }
919 Self::GetFactoryDefaults(defaults) => {
920 #[cfg(feature = "alloc")]
921 buf.reserve(1);
922
923 #[cfg(feature = "alloc")]
924 buf.push(*defaults as u8);
925 #[cfg(not(feature = "alloc"))]
926 buf.push(*defaults as u8).unwrap();
927 }
928 Self::GetLanguageCapabilities(languages) => {
929 #[cfg(feature = "alloc")]
930 buf.reserve(languages.len() * 2);
931
932 for language in languages {
933 buf.extend(language.bytes());
934 }
935 }
936 Self::GetLanguage(language) => {
937 #[cfg(feature = "alloc")]
938 buf.reserve(2);
939
940 buf.extend(language.bytes());
941 }
942 Self::GetSoftwareVersionLabel(label) => {
943 #[cfg(feature = "alloc")]
944 buf.reserve(label.len());
945
946 buf.extend(label.bytes());
947 }
948 Self::GetBootSoftwareVersionId(version_id) => {
949 #[cfg(feature = "alloc")]
950 buf.reserve(4);
951
952 buf.extend(version_id.to_be_bytes());
953 }
954 Self::GetBootSoftwareVersionLabel(label) => {
955 #[cfg(feature = "alloc")]
956 buf.reserve(label.len());
957
958 buf.extend(label.bytes());
959 }
960 Self::GetDmxPersonality {
961 current_personality,
962 personality_count,
963 } => {
964 #[cfg(feature = "alloc")]
965 buf.reserve(2);
966
967 #[cfg(feature = "alloc")]
968 buf.push(*current_personality);
969 #[cfg(not(feature = "alloc"))]
970 buf.push(*current_personality).unwrap();
971
972 #[cfg(feature = "alloc")]
973 buf.push(*personality_count);
974 #[cfg(not(feature = "alloc"))]
975 buf.push(*personality_count).unwrap();
976 }
977 Self::GetDmxPersonalityDescription {
978 id,
979 dmx_slots_required,
980 description,
981 } => {
982 #[cfg(feature = "alloc")]
983 buf.reserve(3 + description.len());
984
985 #[cfg(feature = "alloc")]
986 buf.push(*id);
987 #[cfg(not(feature = "alloc"))]
988 buf.push(*id).unwrap();
989
990 buf.extend(dmx_slots_required.to_be_bytes());
991 buf.extend(description.bytes());
992 }
993 Self::GetDmxStartAddress(address) => {
994 #[cfg(feature = "alloc")]
995 buf.reserve(2);
996
997 buf.extend(address.to_be_bytes());
998 }
999 Self::GetSlotInfo(slots) => {
1000 #[cfg(feature = "alloc")]
1001 buf.reserve(slots.len() * 5);
1002
1003 for slot in slots {
1004 buf.extend(slot.id.to_be_bytes());
1005
1006 #[cfg(feature = "alloc")]
1007 buf.push(slot.r#type.into());
1008 #[cfg(not(feature = "alloc"))]
1009 buf.push(slot.r#type.into()).unwrap();
1010
1011 buf.extend(slot.label_id.to_be_bytes());
1012 }
1013 }
1014 Self::GetSlotDescription {
1015 slot_id,
1016 description,
1017 } => {
1018 #[cfg(feature = "alloc")]
1019 buf.reserve(2 + description.len());
1020
1021 buf.extend(slot_id.to_be_bytes());
1022 buf.extend(description.bytes());
1023 }
1024 Self::GetDefaultSlotValue(values) => {
1025 #[cfg(feature = "alloc")]
1026 buf.reserve(values.len() * 3);
1027
1028 for slot in values {
1029 buf.extend(slot.id.to_be_bytes());
1030
1031 #[cfg(feature = "alloc")]
1032 buf.push(slot.value);
1033 #[cfg(not(feature = "alloc"))]
1034 buf.push(slot.value).unwrap();
1035 }
1036 }
1037 Self::GetSensorDefinition(definition) => {
1038 #[cfg(feature = "alloc")]
1039 buf.reserve(14 + definition.description.len());
1040
1041 #[cfg(feature = "alloc")]
1042 buf.push(definition.kind.into());
1043 #[cfg(not(feature = "alloc"))]
1044 buf.push(definition.kind.into()).unwrap();
1045
1046 #[cfg(feature = "alloc")]
1047 buf.push(definition.unit.into());
1048 #[cfg(not(feature = "alloc"))]
1049 buf.push(definition.unit.into()).unwrap();
1050
1051 #[cfg(feature = "alloc")]
1052 buf.push(definition.prefix as u8);
1053 #[cfg(not(feature = "alloc"))]
1054 buf.push(definition.prefix as u8).unwrap();
1055
1056 #[cfg(feature = "alloc")]
1057 buf.push(definition.prefix as u8);
1058 #[cfg(not(feature = "alloc"))]
1059 buf.push(definition.prefix as u8).unwrap();
1060
1061 buf.extend(definition.range_minimum_value.to_be_bytes());
1062 buf.extend(definition.range_maximum_value.to_be_bytes());
1063 buf.extend(definition.normal_minimum_value.to_be_bytes());
1064 buf.extend(definition.normal_maximum_value.to_be_bytes());
1065
1066 #[cfg(feature = "alloc")]
1067 buf.push(definition.is_lowest_highest_detected_value_supported as u8);
1068 #[cfg(not(feature = "alloc"))]
1069 buf.push(definition.is_lowest_highest_detected_value_supported as u8)
1070 .unwrap();
1071
1072 #[cfg(feature = "alloc")]
1073 buf.push(definition.is_recorded_value_supported as u8);
1074 #[cfg(not(feature = "alloc"))]
1075 buf.push(definition.is_recorded_value_supported as u8)
1076 .unwrap();
1077
1078 buf.extend(definition.description.bytes());
1079 }
1080 Self::GetSensorValue(sensor_value) => {
1081 #[cfg(feature = "alloc")]
1082 buf.reserve(9);
1083
1084 #[cfg(feature = "alloc")]
1085 buf.push(sensor_value.sensor_id);
1086 #[cfg(not(feature = "alloc"))]
1087 buf.push(sensor_value.sensor_id).unwrap();
1088
1089 buf.extend(sensor_value.current_value.to_be_bytes());
1090 buf.extend(sensor_value.lowest_detected_value.to_be_bytes());
1091 buf.extend(sensor_value.highest_detected_value.to_be_bytes());
1092 buf.extend(sensor_value.recorded_value.to_be_bytes());
1093 }
1094 Self::SetSensorValue(sensor_value) => {
1095 #[cfg(feature = "alloc")]
1096 buf.reserve(9);
1097
1098 #[cfg(feature = "alloc")]
1099 buf.push(sensor_value.sensor_id);
1100 #[cfg(not(feature = "alloc"))]
1101 buf.push(sensor_value.sensor_id).unwrap();
1102
1103 buf.extend(sensor_value.current_value.to_be_bytes());
1104 buf.extend(sensor_value.lowest_detected_value.to_be_bytes());
1105 buf.extend(sensor_value.highest_detected_value.to_be_bytes());
1106 buf.extend(sensor_value.recorded_value.to_be_bytes());
1107 }
1108 Self::GetDeviceHours(hours) => {
1109 #[cfg(feature = "alloc")]
1110 buf.reserve(4);
1111
1112 buf.extend(hours.to_be_bytes());
1113 }
1114 Self::GetLampHours(hours) => {
1115 #[cfg(feature = "alloc")]
1116 buf.reserve(4);
1117
1118 buf.extend(hours.to_be_bytes());
1119 }
1120 Self::GetLampStrikes(strikes) => {
1121 #[cfg(feature = "alloc")]
1122 buf.reserve(4);
1123
1124 buf.extend(strikes.to_be_bytes());
1125 }
1126 Self::GetLampState(state) => {
1127 #[cfg(feature = "alloc")]
1128 buf.reserve(1);
1129
1130 #[cfg(feature = "alloc")]
1131 buf.push((*state).into());
1132 #[cfg(not(feature = "alloc"))]
1133 buf.push((*state).into()).unwrap();
1134 }
1135 Self::GetLampOnMode(mode) => {
1136 #[cfg(feature = "alloc")]
1137 buf.reserve(1);
1138
1139 #[cfg(feature = "alloc")]
1140 buf.push((*mode).into());
1141 #[cfg(not(feature = "alloc"))]
1142 buf.push((*mode).into()).unwrap();
1143 }
1144 Self::GetDevicePowerCycles(cycles) => {
1145 #[cfg(feature = "alloc")]
1146 buf.reserve(4);
1147
1148 buf.extend(cycles.to_be_bytes());
1149 }
1150 Self::GetDisplayInvert(mode) => {
1151 #[cfg(feature = "alloc")]
1152 buf.reserve(1);
1153
1154 #[cfg(feature = "alloc")]
1155 buf.push(*mode as u8);
1156 #[cfg(not(feature = "alloc"))]
1157 buf.push(*mode as u8).unwrap();
1158 }
1159 Self::GetDisplayLevel(level) => {
1160 #[cfg(feature = "alloc")]
1161 buf.reserve(1);
1162
1163 #[cfg(feature = "alloc")]
1164 buf.push(*level);
1165 #[cfg(not(feature = "alloc"))]
1166 buf.push(*level).unwrap();
1167 }
1168 Self::GetPanInvert(invert) => {
1169 #[cfg(feature = "alloc")]
1170 buf.reserve(1);
1171
1172 #[cfg(feature = "alloc")]
1173 buf.push(*invert as u8);
1174 #[cfg(not(feature = "alloc"))]
1175 buf.push(*invert as u8).unwrap();
1176 }
1177 Self::GetTiltInvert(invert) => {
1178 #[cfg(feature = "alloc")]
1179 buf.reserve(1);
1180
1181 #[cfg(feature = "alloc")]
1182 buf.push(*invert as u8);
1183 #[cfg(not(feature = "alloc"))]
1184 buf.push(*invert as u8).unwrap();
1185 }
1186 Self::GetPanTiltSwap(swap) => {
1187 #[cfg(feature = "alloc")]
1188 buf.reserve(1);
1189
1190 #[cfg(feature = "alloc")]
1191 buf.push(*swap as u8);
1192 #[cfg(not(feature = "alloc"))]
1193 buf.push(*swap as u8).unwrap();
1194 }
1195 Self::GetRealTimeClock {
1196 year,
1197 month,
1198 day,
1199 hour,
1200 minute,
1201 second,
1202 } => {
1203 #[cfg(feature = "alloc")]
1204 buf.reserve(0x07);
1205
1206 buf.extend((*year).to_be_bytes());
1207
1208 #[cfg(feature = "alloc")]
1209 buf.push(*month);
1210 #[cfg(not(feature = "alloc"))]
1211 buf.push(*month).unwrap();
1212
1213 #[cfg(feature = "alloc")]
1214 buf.push(*day);
1215 #[cfg(not(feature = "alloc"))]
1216 buf.push(*day).unwrap();
1217
1218 #[cfg(feature = "alloc")]
1219 buf.push(*hour);
1220 #[cfg(not(feature = "alloc"))]
1221 buf.push(*hour).unwrap();
1222
1223 #[cfg(feature = "alloc")]
1224 buf.push(*minute);
1225 #[cfg(not(feature = "alloc"))]
1226 buf.push(*minute).unwrap();
1227
1228 #[cfg(feature = "alloc")]
1229 buf.push(*second);
1230 #[cfg(not(feature = "alloc"))]
1231 buf.push(*second).unwrap();
1232 }
1233 Self::GetIdentifyDevice(identifying) => {
1234 #[cfg(feature = "alloc")]
1235 buf.reserve(1);
1236
1237 #[cfg(feature = "alloc")]
1238 buf.push(*identifying as u8);
1239 #[cfg(not(feature = "alloc"))]
1240 buf.push(*identifying as u8).unwrap();
1241 }
1242 Self::GetPowerState(state) => {
1243 #[cfg(feature = "alloc")]
1244 buf.reserve(1);
1245
1246 #[cfg(feature = "alloc")]
1247 buf.push(*state as u8);
1248 #[cfg(not(feature = "alloc"))]
1249 buf.push(*state as u8).unwrap();
1250 }
1251 Self::GetPerformSelfTest(test) => {
1252 #[cfg(feature = "alloc")]
1253 buf.reserve(1);
1254
1255 #[cfg(feature = "alloc")]
1256 buf.push(*test as u8);
1257 #[cfg(not(feature = "alloc"))]
1258 buf.push(*test as u8).unwrap();
1259 }
1260 Self::GetSelfTestDescription {
1261 self_test_id,
1262 description,
1263 } => {
1264 #[cfg(feature = "alloc")]
1265 buf.reserve(1 + description.len());
1266
1267 #[cfg(feature = "alloc")]
1268 buf.push((*self_test_id).into());
1269 #[cfg(not(feature = "alloc"))]
1270 buf.push((*self_test_id).into()).unwrap();
1271
1272 buf.extend(description.bytes());
1273 }
1274 Self::GetPresetPlayback { mode, level } => {
1275 #[cfg(feature = "alloc")]
1276 buf.reserve(3);
1277
1278 buf.extend(u16::from(*mode).to_be_bytes());
1279
1280 #[cfg(feature = "alloc")]
1281 buf.push(*level);
1282 #[cfg(not(feature = "alloc"))]
1283 buf.push(*level).unwrap();
1284 }
1285 Self::GetDmxBlockAddress {
1286 total_sub_device_footprint,
1287 base_dmx_address,
1288 } => {
1289 #[cfg(feature = "alloc")]
1290 buf.reserve(4);
1291
1292 buf.extend(total_sub_device_footprint.to_be_bytes());
1293 buf.extend(base_dmx_address.to_be_bytes());
1294 }
1295 Self::GetDmxFailMode {
1296 scene_id,
1297 loss_of_signal_delay,
1298 hold_time,
1299 level,
1300 } => {
1301 #[cfg(feature = "alloc")]
1302 buf.reserve(7);
1303
1304 buf.extend(u16::from(*scene_id).to_be_bytes());
1305 buf.extend(u16::from(*loss_of_signal_delay).to_be_bytes());
1306 buf.extend(u16::from(*hold_time).to_be_bytes());
1307
1308 #[cfg(feature = "alloc")]
1309 buf.push(*level);
1310 #[cfg(not(feature = "alloc"))]
1311 buf.push(*level).unwrap();
1312 }
1313 Self::GetDmxStartupMode {
1314 scene_id,
1315 startup_delay,
1316 hold_time,
1317 level,
1318 } => {
1319 #[cfg(feature = "alloc")]
1320 buf.reserve(7);
1321
1322 buf.extend(u16::from(*scene_id).to_be_bytes());
1323 buf.extend(u16::from(*startup_delay).to_be_bytes());
1324 buf.extend(u16::from(*hold_time).to_be_bytes());
1325
1326 #[cfg(feature = "alloc")]
1327 buf.push(*level);
1328 #[cfg(not(feature = "alloc"))]
1329 buf.push(*level).unwrap();
1330 }
1331 Self::GetPowerOnSelfTest(test) => {
1332 #[cfg(feature = "alloc")]
1333 buf.reserve(1);
1334
1335 #[cfg(feature = "alloc")]
1336 buf.push(*test as u8);
1337 #[cfg(not(feature = "alloc"))]
1338 buf.push(*test as u8).unwrap();
1339 }
1340 Self::GetLockState {
1341 lock_state_id,
1342 lock_state_count,
1343 } => {
1344 #[cfg(feature = "alloc")]
1345 buf.reserve(2);
1346
1347 #[cfg(feature = "alloc")]
1348 buf.push(*lock_state_id);
1349 #[cfg(not(feature = "alloc"))]
1350 buf.push(*lock_state_id).unwrap();
1351
1352 #[cfg(feature = "alloc")]
1353 buf.push(*lock_state_count);
1354 #[cfg(not(feature = "alloc"))]
1355 buf.push(*lock_state_count).unwrap();
1356 }
1357 Self::GetLockStateDescription {
1358 lock_state_id,
1359 description,
1360 } => {
1361 #[cfg(feature = "alloc")]
1362 buf.reserve(1 + description.len());
1363
1364 #[cfg(feature = "alloc")]
1365 buf.push(*lock_state_id);
1366 #[cfg(not(feature = "alloc"))]
1367 buf.push(*lock_state_id).unwrap();
1368
1369 buf.extend(description.bytes());
1370 }
1371 Self::GetLockPin(pin) => {
1372 #[cfg(feature = "alloc")]
1373 buf.reserve(4);
1374
1375 buf.extend(pin.0.to_be_bytes());
1376 }
1377 Self::GetBurnIn(hours) => {
1378 #[cfg(feature = "alloc")]
1379 buf.reserve(1);
1380
1381 #[cfg(feature = "alloc")]
1382 buf.push(*hours);
1383 #[cfg(not(feature = "alloc"))]
1384 buf.push(*hours).unwrap();
1385 }
1386 Self::GetDimmerInfo {
1387 minimum_level_lower_limit,
1388 minimum_level_upper_limit,
1389 maximum_level_lower_limit,
1390 maximum_level_upper_limit,
1391 number_of_supported_curves,
1392 levels_resolution,
1393 minimum_level_split_levels_supported,
1394 } => {
1395 #[cfg(feature = "alloc")]
1396 buf.reserve(11);
1397
1398 buf.extend(minimum_level_lower_limit.to_be_bytes());
1399 buf.extend(minimum_level_upper_limit.to_be_bytes());
1400 buf.extend(maximum_level_lower_limit.to_be_bytes());
1401 buf.extend(maximum_level_upper_limit.to_be_bytes());
1402
1403 #[cfg(feature = "alloc")]
1404 buf.push(*number_of_supported_curves);
1405 #[cfg(not(feature = "alloc"))]
1406 buf.push(*number_of_supported_curves).unwrap();
1407
1408 #[cfg(feature = "alloc")]
1409 buf.push(*levels_resolution);
1410 #[cfg(not(feature = "alloc"))]
1411 buf.push(*levels_resolution).unwrap();
1412
1413 #[cfg(feature = "alloc")]
1414 buf.push(*minimum_level_split_levels_supported as u8);
1415 #[cfg(not(feature = "alloc"))]
1416 buf.push(*minimum_level_split_levels_supported as u8)
1417 .unwrap();
1418 }
1419 Self::GetMinimumLevel {
1420 minimum_level_increasing,
1421 minimum_level_decreasing,
1422 on_below_minimum,
1423 } => {
1424 #[cfg(feature = "alloc")]
1425 buf.reserve(5);
1426
1427 buf.extend(minimum_level_increasing.to_be_bytes());
1428 buf.extend(minimum_level_decreasing.to_be_bytes());
1429
1430 #[cfg(feature = "alloc")]
1431 buf.push(*on_below_minimum as u8);
1432 #[cfg(not(feature = "alloc"))]
1433 buf.push(*on_below_minimum as u8).unwrap();
1434 }
1435 Self::GetMaximumLevel(level) => {
1436 #[cfg(feature = "alloc")]
1437 buf.reserve(2);
1438
1439 buf.extend(level.to_be_bytes());
1440 }
1441 Self::GetCurve {
1442 curve_id,
1443 curve_count,
1444 } => {
1445 #[cfg(feature = "alloc")]
1446 buf.reserve(2);
1447
1448 #[cfg(feature = "alloc")]
1449 buf.push(*curve_id);
1450 #[cfg(not(feature = "alloc"))]
1451 buf.push(*curve_id).unwrap();
1452
1453 #[cfg(feature = "alloc")]
1454 buf.push(*curve_count);
1455 #[cfg(not(feature = "alloc"))]
1456 buf.push(*curve_count).unwrap();
1457 }
1458 Self::GetCurveDescription {
1459 curve_id,
1460 description,
1461 } => {
1462 #[cfg(feature = "alloc")]
1463 buf.reserve(1 + description.len());
1464
1465 #[cfg(feature = "alloc")]
1466 buf.push(*curve_id);
1467 #[cfg(not(feature = "alloc"))]
1468 buf.push(*curve_id).unwrap();
1469
1470 buf.extend(description.bytes());
1471 }
1472 Self::GetOutputResponseTime {
1473 response_time_id,
1474 response_time_count,
1475 } => {
1476 #[cfg(feature = "alloc")]
1477 buf.reserve(2);
1478
1479 #[cfg(feature = "alloc")]
1480 buf.push(*response_time_id);
1481 #[cfg(not(feature = "alloc"))]
1482 buf.push(*response_time_id).unwrap();
1483
1484 #[cfg(feature = "alloc")]
1485 buf.push(*response_time_count);
1486 #[cfg(not(feature = "alloc"))]
1487 buf.push(*response_time_count).unwrap();
1488 }
1489 Self::GetOutputResponseTimeDescription {
1490 response_time_id,
1491 description,
1492 } => {
1493 #[cfg(feature = "alloc")]
1494 buf.reserve(1 + description.len());
1495
1496 #[cfg(feature = "alloc")]
1497 buf.push(*response_time_id);
1498 #[cfg(not(feature = "alloc"))]
1499 buf.push(*response_time_id).unwrap();
1500
1501 buf.extend(description.bytes());
1502 }
1503 Self::GetModulationFrequency {
1504 modulation_frequency_id,
1505 modulation_frequency_count,
1506 } => {
1507 #[cfg(feature = "alloc")]
1508 buf.reserve(2);
1509
1510 #[cfg(feature = "alloc")]
1511 buf.push(*modulation_frequency_id);
1512 #[cfg(not(feature = "alloc"))]
1513 buf.push(*modulation_frequency_id).unwrap();
1514
1515 #[cfg(feature = "alloc")]
1516 buf.push(*modulation_frequency_count);
1517 #[cfg(not(feature = "alloc"))]
1518 buf.push(*modulation_frequency_count).unwrap();
1519 }
1520 Self::GetModulationFrequencyDescription {
1521 modulation_frequency_id,
1522 frequency,
1523 description,
1524 } => {
1525 #[cfg(feature = "alloc")]
1526 buf.reserve(5 + description.len());
1527
1528 #[cfg(feature = "alloc")]
1529 buf.push(*modulation_frequency_id);
1530 #[cfg(not(feature = "alloc"))]
1531 buf.push(*modulation_frequency_id).unwrap();
1532
1533 buf.extend(frequency.to_be_bytes());
1534 buf.extend(description.bytes());
1535 }
1536 Self::GetPresetInfo {
1537 level_field_supported,
1538 preset_sequence_supported,
1539 split_times_supported,
1540 dmx_fail_infinite_delay_time_supported,
1541 dmx_fail_infinite_hold_time_supported,
1542 startup_infinite_hold_time_supported,
1543 maximum_scene_number,
1544 minimum_preset_fade_time_supported,
1545 maximum_preset_fade_time_supported,
1546 minimum_preset_wait_time_supported,
1547 maximum_preset_wait_time_supported,
1548 minimum_dmx_fail_delay_time_supported,
1549 maximum_dmx_fail_delay_time_supported,
1550 minimum_dmx_fail_hold_time_supported,
1551 maximum_dmx_fail_hold_time_supported,
1552 minimum_startup_delay_time_supported,
1553 maximum_startup_delay_time_supported,
1554 minimum_startup_hold_time_supported,
1555 maximum_startup_hold_time_supported,
1556 } => {
1557 #[cfg(feature = "alloc")]
1558 buf.reserve(38);
1559
1560 #[cfg(feature = "alloc")]
1561 buf.push(*level_field_supported as u8);
1562 #[cfg(not(feature = "alloc"))]
1563 buf.push(*level_field_supported as u8).unwrap();
1564
1565 #[cfg(feature = "alloc")]
1566 buf.push(*preset_sequence_supported as u8);
1567 #[cfg(not(feature = "alloc"))]
1568 buf.push(*preset_sequence_supported as u8).unwrap();
1569
1570 #[cfg(feature = "alloc")]
1571 buf.push(*split_times_supported as u8);
1572 #[cfg(not(feature = "alloc"))]
1573 buf.push(*split_times_supported as u8).unwrap();
1574
1575 #[cfg(feature = "alloc")]
1576 buf.push(*dmx_fail_infinite_delay_time_supported as u8);
1577 #[cfg(not(feature = "alloc"))]
1578 buf.push(*dmx_fail_infinite_delay_time_supported as u8)
1579 .unwrap();
1580
1581 #[cfg(feature = "alloc")]
1582 buf.push(*dmx_fail_infinite_hold_time_supported as u8);
1583 #[cfg(not(feature = "alloc"))]
1584 buf.push(*dmx_fail_infinite_hold_time_supported as u8)
1585 .unwrap();
1586
1587 #[cfg(feature = "alloc")]
1588 buf.push(*startup_infinite_hold_time_supported as u8);
1589 #[cfg(not(feature = "alloc"))]
1590 buf.push(*startup_infinite_hold_time_supported as u8)
1591 .unwrap();
1592
1593 buf.extend(maximum_scene_number.to_be_bytes());
1594 buf.extend(minimum_preset_fade_time_supported.to_be_bytes());
1595 buf.extend(maximum_preset_fade_time_supported.to_be_bytes());
1596 buf.extend(minimum_preset_wait_time_supported.to_be_bytes());
1597 buf.extend(maximum_preset_wait_time_supported.to_be_bytes());
1598
1599 buf.extend(u16::from(*minimum_dmx_fail_delay_time_supported).to_be_bytes());
1600 buf.extend(u16::from(*maximum_dmx_fail_delay_time_supported).to_be_bytes());
1601 buf.extend(u16::from(*minimum_dmx_fail_hold_time_supported).to_be_bytes());
1602 buf.extend(u16::from(*maximum_dmx_fail_hold_time_supported).to_be_bytes());
1603 buf.extend(u16::from(*minimum_startup_delay_time_supported).to_be_bytes());
1604 buf.extend(u16::from(*maximum_startup_delay_time_supported).to_be_bytes());
1605 buf.extend(u16::from(*minimum_startup_hold_time_supported).to_be_bytes());
1606 buf.extend(u16::from(*maximum_startup_hold_time_supported).to_be_bytes());
1607 }
1608 Self::GetPresetStatus {
1609 scene_id,
1610 up_fade_time,
1611 down_fade_time,
1612 wait_time,
1613 programmed,
1614 } => {
1615 #[cfg(feature = "alloc")]
1616 buf.reserve(9);
1617
1618 buf.extend(scene_id.to_be_bytes());
1619 buf.extend(up_fade_time.to_be_bytes());
1620 buf.extend(down_fade_time.to_be_bytes());
1621 buf.extend(wait_time.to_be_bytes());
1622
1623 #[cfg(feature = "alloc")]
1624 buf.push(*programmed as u8);
1625 #[cfg(not(feature = "alloc"))]
1626 buf.push(*programmed as u8).unwrap();
1627 }
1628 Self::GetPresetMergeMode(mode) => {
1629 #[cfg(feature = "alloc")]
1630 buf.reserve(1);
1631
1632 #[cfg(feature = "alloc")]
1633 buf.push(*mode as u8);
1634 #[cfg(not(feature = "alloc"))]
1635 buf.push(*mode as u8).unwrap();
1636 }
1637 Self::GetListInterfaces(interfaces) => {
1638 #[cfg(feature = "alloc")]
1639 buf.reserve(interfaces.len() * 6);
1640
1641 for interface in interfaces {
1642 buf.extend(interface.interface_id.to_be_bytes());
1643 buf.extend(u16::from(interface.hardware_type).to_be_bytes());
1644 }
1645 }
1646 Self::GetInterfaceLabel {
1647 interface_id,
1648 interface_label,
1649 } => {
1650 #[cfg(feature = "alloc")]
1651 buf.reserve(4 + interface_label.len());
1652
1653 buf.extend(interface_id.to_be_bytes());
1654 buf.extend(interface_label.bytes());
1655 }
1656 Self::GetInterfaceHardwareAddressType1 {
1657 interface_id,
1658 hardware_address,
1659 } => {
1660 #[cfg(feature = "alloc")]
1661 buf.reserve(10);
1662
1663 buf.extend(interface_id.to_be_bytes());
1664 buf.extend(hardware_address.into_array());
1665 }
1666 Self::GetIpV4DhcpMode {
1667 interface_id,
1668 dhcp_mode,
1669 } => {
1670 #[cfg(feature = "alloc")]
1671 buf.reserve(5);
1672
1673 buf.extend(interface_id.to_be_bytes());
1674
1675 #[cfg(feature = "alloc")]
1676 buf.push(*dhcp_mode as u8);
1677 #[cfg(not(feature = "alloc"))]
1678 buf.push(*dhcp_mode as u8).unwrap();
1679 }
1680 Self::GetIpV4ZeroConfMode {
1681 interface_id,
1682 zero_conf_mode,
1683 } => {
1684 #[cfg(feature = "alloc")]
1685 buf.reserve(5);
1686
1687 buf.extend(interface_id.to_be_bytes());
1688
1689 #[cfg(feature = "alloc")]
1690 buf.push(*zero_conf_mode as u8);
1691 #[cfg(not(feature = "alloc"))]
1692 buf.push(*zero_conf_mode as u8).unwrap();
1693 }
1694 Self::GetIpV4CurrentAddress {
1695 interface_id,
1696 address,
1697 netmask,
1698 dhcp_status,
1699 } => {
1700 #[cfg(feature = "alloc")]
1701 buf.reserve(13);
1702
1703 buf.extend(interface_id.to_be_bytes());
1704 buf.extend(<[u8; 4]>::from(*address));
1705
1706 #[cfg(feature = "alloc")]
1707 buf.push(*netmask);
1708 #[cfg(not(feature = "alloc"))]
1709 buf.push(*netmask).unwrap();
1710
1711 #[cfg(feature = "alloc")]
1712 buf.push(*dhcp_status as u8);
1713 #[cfg(not(feature = "alloc"))]
1714 buf.push(*dhcp_status as u8).unwrap();
1715 }
1716 Self::GetIpV4StaticAddress {
1717 interface_id,
1718 address,
1719 netmask,
1720 } => {
1721 #[cfg(feature = "alloc")]
1722 buf.reserve(10);
1723
1724 buf.extend(interface_id.to_be_bytes());
1725 buf.extend(<[u8; 4]>::from(*address));
1726
1727 #[cfg(feature = "alloc")]
1728 buf.push(*netmask);
1729 #[cfg(not(feature = "alloc"))]
1730 buf.push(*netmask).unwrap();
1731 }
1732 Self::GetIpV4DefaultRoute {
1733 interface_id,
1734 address,
1735 } => {
1736 #[cfg(feature = "alloc")]
1737 buf.reserve(6);
1738
1739 buf.extend(interface_id.to_be_bytes());
1740 buf.extend(<[u8; 4]>::from(*address));
1741 }
1742 Self::GetDnsIpV4NameServer {
1743 name_server_index,
1744 address,
1745 } => {
1746 #[cfg(feature = "alloc")]
1747 buf.reserve(5);
1748
1749 buf.extend(name_server_index.to_be_bytes());
1750 buf.extend(<[u8; 4]>::from(*address));
1751 }
1752 Self::GetDnsHostName(host_name) => {
1753 #[cfg(feature = "alloc")]
1754 buf.reserve(host_name.len());
1755
1756 buf.extend(host_name.bytes());
1757 }
1758 Self::GetDnsDomainName(domain_name) => {
1759 #[cfg(feature = "alloc")]
1760 buf.reserve(domain_name.len());
1761
1762 buf.extend(domain_name.bytes());
1763 }
1764 Self::GetEndpointList {
1766 list_change_number,
1767 endpoint_list,
1768 } => {
1769 #[cfg(feature = "alloc")]
1770 buf.reserve(4 + (endpoint_list.len() * 3));
1771
1772 buf.extend(list_change_number.to_be_bytes());
1773
1774 for (endpoint_id, endpoint_type) in endpoint_list {
1775 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1776
1777 #[cfg(feature = "alloc")]
1778 buf.push(*endpoint_type as u8);
1779 #[cfg(not(feature = "alloc"))]
1780 buf.push(*endpoint_type as u8).unwrap();
1781 }
1782 }
1783 Self::GetEndpointListChange { list_change_number } => {
1784 #[cfg(feature = "alloc")]
1785 buf.reserve(4);
1786
1787 buf.extend(list_change_number.to_be_bytes());
1788 }
1789 Self::GetIdentifyEndpoint {
1790 endpoint_id,
1791 identify,
1792 } => {
1793 #[cfg(feature = "alloc")]
1794 buf.reserve(3);
1795
1796 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1797
1798 #[cfg(feature = "alloc")]
1799 buf.push(*identify as u8);
1800 #[cfg(not(feature = "alloc"))]
1801 buf.push(*identify as u8).unwrap();
1802 }
1803 Self::SetIdentifyEndpoint { endpoint_id } => {
1804 #[cfg(feature = "alloc")]
1805 buf.reserve(2);
1806
1807 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1808 }
1809 Self::GetEndpointToUniverse {
1810 endpoint_id,
1811 universe,
1812 } => {
1813 #[cfg(feature = "alloc")]
1814 buf.reserve(4);
1815
1816 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1817 buf.extend(universe.to_be_bytes());
1818 }
1819 Self::SetEndpointToUniverse { endpoint_id } => {
1820 #[cfg(feature = "alloc")]
1821 buf.reserve(2);
1822
1823 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1824 }
1825 Self::GetEndpointMode { endpoint_id, mode } => {
1826 #[cfg(feature = "alloc")]
1827 buf.reserve(3);
1828
1829 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1830
1831 #[cfg(feature = "alloc")]
1832 buf.push(*mode as u8);
1833 #[cfg(not(feature = "alloc"))]
1834 buf.push(*mode as u8).unwrap();
1835 }
1836 Self::SetEndpointMode { endpoint_id } => {
1837 #[cfg(feature = "alloc")]
1838 buf.reserve(2);
1839
1840 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1841 }
1842 Self::GetEndpointLabel { endpoint_id, label } => {
1843 #[cfg(feature = "alloc")]
1844 buf.reserve(3 + label.len());
1845
1846 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1847 buf.extend(label.bytes());
1848 }
1849 Self::SetEndpointLabel { endpoint_id } => {
1850 #[cfg(feature = "alloc")]
1851 buf.reserve(2);
1852
1853 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1854 }
1855 Self::GetRdmTrafficEnable {
1856 endpoint_id,
1857 enable,
1858 } => {
1859 #[cfg(feature = "alloc")]
1860 buf.reserve(3);
1861
1862 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1863
1864 #[cfg(feature = "alloc")]
1865 buf.push(*enable as u8);
1866 #[cfg(not(feature = "alloc"))]
1867 buf.push(*enable as u8).unwrap();
1868 }
1869 Self::SetRdmTrafficEnable { endpoint_id } => {
1870 #[cfg(feature = "alloc")]
1871 buf.reserve(2);
1872
1873 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1874 }
1875 Self::GetDiscoveryState {
1876 endpoint_id,
1877 device_count,
1878 discovery_state,
1879 } => {
1880 #[cfg(feature = "alloc")]
1881 buf.reserve(5);
1882
1883 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1884 buf.extend(u16::from(*device_count).to_be_bytes());
1885
1886 #[cfg(feature = "alloc")]
1887 buf.push((*discovery_state).into());
1888 #[cfg(not(feature = "alloc"))]
1889 buf.push((*discovery_state).into()).unwrap();
1890 }
1891 Self::SetDiscoveryState { endpoint_id } => {
1892 #[cfg(feature = "alloc")]
1893 buf.reserve(2);
1894
1895 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1896 }
1897 Self::GetBackgroundDiscovery {
1898 endpoint_id,
1899 enabled,
1900 } => {
1901 #[cfg(feature = "alloc")]
1902 buf.reserve(3);
1903
1904 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1905
1906 #[cfg(feature = "alloc")]
1907 buf.push(*enabled as u8);
1908 #[cfg(not(feature = "alloc"))]
1909 buf.push(*enabled as u8).unwrap();
1910 }
1911 Self::SetBackgroundDiscovery { endpoint_id } => {
1912 #[cfg(feature = "alloc")]
1913 buf.reserve(2);
1914
1915 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1916 }
1917 Self::GetEndpointTiming {
1918 endpoint_id,
1919 current_setting_id,
1920 setting_count,
1921 } => {
1922 #[cfg(feature = "alloc")]
1923 buf.reserve(4);
1924
1925 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1926
1927 #[cfg(feature = "alloc")]
1928 buf.push(*current_setting_id);
1929 #[cfg(not(feature = "alloc"))]
1930 buf.push(*current_setting_id).unwrap();
1931
1932 #[cfg(feature = "alloc")]
1933 buf.push(*setting_count);
1934 #[cfg(not(feature = "alloc"))]
1935 buf.push(*setting_count).unwrap();
1936 }
1937 Self::SetEndpointTiming { endpoint_id } => {
1938 #[cfg(feature = "alloc")]
1939 buf.reserve(2);
1940
1941 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1942 }
1943 Self::GetEndpointTimingDescription {
1944 setting_id,
1945 description,
1946 } => {
1947 #[cfg(feature = "alloc")]
1948 buf.reserve(1 + description.len());
1949
1950 #[cfg(feature = "alloc")]
1951 buf.push(*setting_id);
1952 #[cfg(not(feature = "alloc"))]
1953 buf.push(*setting_id).unwrap();
1954
1955 buf.extend(description.bytes());
1956 }
1957 Self::GetEndpointResponders {
1958 endpoint_id,
1959 list_change_number,
1960 responders,
1961 } => {
1962 #[cfg(feature = "alloc")]
1963 buf.reserve(6 + (responders.len() * 6));
1964
1965 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1966 buf.extend(list_change_number.to_be_bytes());
1967
1968 for responder in responders {
1969 buf.extend(<[u8; 6]>::from(*responder));
1970 }
1971 }
1972 Self::GetEndpointResponderListChange {
1973 endpoint_id,
1974 list_change_number,
1975 } => {
1976 #[cfg(feature = "alloc")]
1977 buf.reserve(6);
1978
1979 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1980 buf.extend(list_change_number.to_be_bytes());
1981 }
1982 Self::GetBindingControlFields {
1983 endpoint_id,
1984 uid,
1985 control_field,
1986 binding_uid,
1987 } => {
1988 #[cfg(feature = "alloc")]
1989 buf.reserve(3);
1990
1991 buf.extend(u16::from(*endpoint_id).to_be_bytes());
1992 buf.extend(<[u8; 6]>::from(*uid));
1993 buf.extend((*control_field).to_be_bytes());
1994 buf.extend(<[u8; 6]>::from(*binding_uid));
1995 }
1996 Self::GetBackgroundQueuedStatusPolicy {
1997 current_policy_id,
1998 policy_count,
1999 } => {
2000 #[cfg(feature = "alloc")]
2001 buf.reserve(2);
2002
2003 #[cfg(feature = "alloc")]
2004 buf.push(*current_policy_id);
2005 #[cfg(not(feature = "alloc"))]
2006 buf.push(*current_policy_id).unwrap();
2007
2008 #[cfg(feature = "alloc")]
2009 buf.push(*policy_count);
2010 #[cfg(not(feature = "alloc"))]
2011 buf.push(*policy_count).unwrap();
2012 }
2013 Self::GetBackgroundQueuedStatusPolicyDescription {
2014 policy_id,
2015 description,
2016 } => {
2017 #[cfg(feature = "alloc")]
2018 buf.reserve(1 + description.len());
2019
2020 #[cfg(feature = "alloc")]
2021 buf.push(*policy_id);
2022 #[cfg(not(feature = "alloc"))]
2023 buf.push(*policy_id).unwrap();
2024
2025 buf.extend(description.bytes());
2026 }
2027 Self::GetComponentScope {
2029 scope_slot,
2030 scope_string,
2031 static_config_type,
2032 static_ipv4_address,
2033 static_ipv6_address,
2034 static_port,
2035 } => {
2036 #[cfg(feature = "alloc")]
2037 buf.reserve(25 + scope_string.len());
2038
2039 buf.extend(scope_slot.to_be_bytes());
2040 buf.extend(scope_string.bytes());
2041
2042 #[cfg(feature = "alloc")]
2043 buf.push(*static_config_type as u8);
2044 #[cfg(not(feature = "alloc"))]
2045 buf.push(*static_config_type as u8).unwrap();
2046
2047 buf.extend(<[u8; 4]>::from(*static_ipv4_address));
2048 buf.extend(<[u8; 16]>::from(*static_ipv6_address));
2049 buf.extend(static_port.to_be_bytes());
2050 }
2051 Self::GetSearchDomain(search_domain) => {
2052 #[cfg(feature = "alloc")]
2053 buf.reserve(25 + search_domain.len());
2054
2055 buf.extend(search_domain.bytes());
2056 }
2057 Self::GetTcpCommsStatus {
2058 scope_string,
2059 broker_ipv4_address,
2060 broker_ipv6_address,
2061 broker_port,
2062 unhealthy_tcp_events,
2063 } => {
2064 #[cfg(feature = "alloc")]
2065 buf.reserve(24 + scope_string.len());
2066
2067 buf.extend(scope_string.bytes());
2068
2069 buf.extend(<[u8; 4]>::from(*broker_ipv4_address));
2070 buf.extend(<[u8; 16]>::from(*broker_ipv6_address));
2071 buf.extend(broker_port.to_be_bytes());
2072 buf.extend(unhealthy_tcp_events.to_be_bytes());
2073 }
2074 Self::GetBrokerStatus {
2075 is_allowing_set_commands,
2076 broker_state,
2077 } => {
2078 #[cfg(feature = "alloc")]
2079 buf.reserve(2);
2080
2081 #[cfg(feature = "alloc")]
2082 buf.push(*is_allowing_set_commands as u8);
2083 #[cfg(not(feature = "alloc"))]
2084 buf.push(*is_allowing_set_commands as u8).unwrap();
2085
2086 #[cfg(feature = "alloc")]
2087 buf.push(*broker_state as u8);
2088 #[cfg(not(feature = "alloc"))]
2089 buf.push(*broker_state as u8).unwrap();
2090 }
2091 Self::ManufacturerSpecific(data) => {
2092 #[cfg(feature = "alloc")]
2093 buf.reserve(data.len());
2094
2095 #[cfg(feature = "alloc")]
2096 buf.extend(data);
2097 #[cfg(not(feature = "alloc"))]
2098 buf.extend_from_slice(data).unwrap();
2099 }
2100 Self::Unsupported(data) => {
2101 #[cfg(feature = "alloc")]
2102 buf.reserve(data.len());
2103
2104 #[cfg(feature = "alloc")]
2105 buf.extend(data);
2106 #[cfg(not(feature = "alloc"))]
2107 buf.extend_from_slice(data).unwrap();
2108 }
2109 }
2110
2111 buf
2112 }
2113
2114 pub fn decode(
2115 command_class: CommandClass,
2116 parameter_id: ParameterId,
2117 bytes: &[u8],
2118 ) -> Result<Self, RdmError> {
2119 match (command_class, parameter_id) {
2120 (CommandClass::DiscoveryCommandResponse, ParameterId::DiscMute) => {
2121 let binding_uid = if bytes.len() > 2 {
2122 Some(DeviceUID::from(<[u8; 6]>::try_from(&bytes[2..=7])?))
2123 } else {
2124 None
2125 };
2126
2127 Ok(Self::DiscMute {
2128 control_field: u16::from_be_bytes(bytes[..=1].try_into()?),
2129 binding_uid,
2130 })
2131 }
2132 (CommandClass::DiscoveryCommandResponse, ParameterId::DiscUnMute) => {
2133 let binding_uid = if bytes.len() > 2 {
2134 Some(DeviceUID::from(<[u8; 6]>::try_from(&bytes[2..=7])?))
2135 } else {
2136 None
2137 };
2138
2139 Ok(Self::DiscUnMute {
2140 control_field: u16::from_be_bytes(bytes[..=1].try_into()?),
2141 binding_uid,
2142 })
2143 }
2144 (CommandClass::GetCommandResponse, ParameterId::ProxiedDeviceCount) => {
2145 Ok(Self::GetProxiedDeviceCount {
2146 device_count: u16::from_be_bytes(bytes[0..=1].try_into()?),
2147 list_change: bytes[2] == 1,
2148 })
2149 }
2150 (CommandClass::GetCommandResponse, ParameterId::ProxiedDevices) => {
2151 Ok(Self::GetProxiedDevices(
2152 #[cfg(feature = "alloc")]
2153 bytes
2154 .chunks(6)
2155 .map(|chunk| Ok(DeviceUID::from(<[u8; 6]>::try_from(&chunk[0..=5])?)))
2156 .collect::<Result<Vec<DeviceUID>, RdmError>>()?,
2157 #[cfg(not(feature = "alloc"))]
2158 bytes
2159 .chunks(6)
2160 .map(|chunk| Ok(DeviceUID::from(<[u8; 6]>::try_from(&chunk[0..=5])?)))
2161 .collect::<Result<Vec<DeviceUID, 38>, RdmError>>()?,
2162 ))
2163 }
2164 (CommandClass::GetCommandResponse, ParameterId::CommsStatus) => {
2165 Ok(Self::GetCommsStatus {
2166 short_message: u16::from_be_bytes(bytes[0..=1].try_into()?),
2167 length_mismatch: u16::from_be_bytes(bytes[2..=3].try_into()?),
2168 checksum_fail: u16::from_be_bytes(bytes[4..=5].try_into()?),
2169 })
2170 }
2171 (CommandClass::GetCommandResponse, ParameterId::StatusMessages) => {
2172 Ok(Self::GetStatusMessages(
2173 #[cfg(feature = "alloc")]
2174 bytes
2175 .chunks(9)
2176 .map(|chunk| {
2177 Ok(StatusMessage::new(
2178 u16::from_be_bytes(chunk[0..=1].try_into()?).into(),
2179 chunk[2].try_into()?,
2180 u16::from_be_bytes(chunk[3..=4].try_into()?),
2181 u16::from_be_bytes(chunk[5..=6].try_into()?),
2182 u16::from_be_bytes(chunk[7..=8].try_into()?),
2183 ))
2184 })
2185 .collect::<Result<Vec<StatusMessage>, RdmError>>()?,
2186 #[cfg(not(feature = "alloc"))]
2187 bytes
2188 .chunks(9)
2189 .map(|chunk| {
2190 Ok(StatusMessage::new(
2191 u16::from_be_bytes(chunk[0..=1].try_into()?).into(),
2192 chunk[2].try_into()?,
2193 u16::from_be_bytes(chunk[3..=4].try_into()?),
2194 u16::from_be_bytes(chunk[5..=6].try_into()?),
2195 u16::from_be_bytes(chunk[7..=8].try_into()?),
2196 ))
2197 })
2198 .collect::<Result<Vec<StatusMessage, 25>, RdmError>>()?,
2199 ))
2200 }
2201 (CommandClass::GetCommandResponse, ParameterId::StatusIdDescription) => {
2202 Ok(Self::GetStatusIdDescription(decode_string_bytes(bytes)?))
2203 }
2204 (CommandClass::GetCommandResponse, ParameterId::SubDeviceIdStatusReportThreshold) => {
2205 Ok(Self::GetSubDeviceIdStatusReportThreshold(
2206 bytes[0].try_into()?,
2207 ))
2208 }
2209 (CommandClass::GetCommandResponse, ParameterId::SupportedParameters) => {
2210 let parameters = bytes
2211 .chunks(2)
2212 .map(|chunk| Ok(u16::from_be_bytes(chunk.try_into()?)))
2213 .filter_map(|parameter_id: Result<u16, RdmError>| parameter_id.ok());
2214
2215 Ok(Self::GetSupportedParameters(
2216 #[cfg(feature = "alloc")]
2217 parameters.collect::<Vec<u16>>(),
2218 #[cfg(not(feature = "alloc"))]
2219 parameters.collect::<Vec<u16, 115>>(),
2220 ))
2221 }
2222 (CommandClass::GetCommandResponse, ParameterId::ParameterDescription) => {
2223 Ok(Self::GetParameterDescription(ParameterDescription {
2224 parameter_id: u16::from_be_bytes(bytes[0..=1].try_into()?),
2225 parameter_data_length: bytes[2],
2226 data_type: bytes[3].try_into()?,
2227 command_class: bytes[4].try_into()?,
2228 unit_type: bytes[6].try_into()?,
2229 prefix: bytes[7].try_into()?,
2230 raw_minimum_valid_value: bytes[8..=11].try_into()?,
2231 raw_maximum_valid_value: bytes[12..=15].try_into()?,
2232 raw_default_value: bytes[16..=19].try_into()?,
2233 description: decode_string_bytes(&bytes[20..])?,
2234 }))
2235 }
2236 (CommandClass::GetCommandResponse, ParameterId::DeviceInfo) => {
2237 Ok(Self::GetDeviceInfo {
2238 protocol_version: ProtocolVersion::new(bytes[0], bytes[1]),
2239 model_id: u16::from_be_bytes(bytes[2..=3].try_into()?),
2240 product_category: u16::from_be_bytes(bytes[4..=5].try_into()?).into(),
2241 software_version_id: u32::from_be_bytes(bytes[6..=9].try_into()?),
2242 footprint: u16::from_be_bytes(bytes[10..=11].try_into()?),
2243 current_personality: bytes[12],
2244 personality_count: bytes[13],
2245 start_address: u16::from_be_bytes(bytes[14..=15].try_into()?),
2246 sub_device_count: u16::from_be_bytes(bytes[16..=17].try_into()?),
2247 sensor_count: u8::from_be(bytes[18]),
2248 })
2249 }
2250 (CommandClass::GetCommandResponse, ParameterId::ProductDetailIdList) => {
2251 Ok(Self::GetProductDetailIdList(
2252 #[cfg(feature = "alloc")]
2253 bytes
2254 .chunks(2)
2255 .map(|chunk| Ok(u16::from_be_bytes(chunk.try_into()?).into()))
2256 .collect::<Result<Vec<ProductDetail>, RdmError>>()?,
2257 #[cfg(not(feature = "alloc"))]
2258 bytes
2259 .chunks(2)
2260 .map(|chunk| Ok(u16::from_be_bytes(chunk.try_into()?).into()))
2261 .collect::<Result<Vec<ProductDetail, 115>, RdmError>>()?,
2262 ))
2263 }
2264 (CommandClass::GetCommandResponse, ParameterId::DeviceModelDescription) => {
2265 Ok(Self::GetDeviceModelDescription(decode_string_bytes(bytes)?))
2266 }
2267 (CommandClass::GetCommandResponse, ParameterId::ManufacturerLabel) => {
2268 Ok(Self::GetManufacturerLabel(decode_string_bytes(bytes)?))
2269 }
2270 (CommandClass::GetCommandResponse, ParameterId::DeviceLabel) => {
2271 Ok(Self::GetDeviceLabel(decode_string_bytes(bytes)?))
2272 }
2273 (CommandClass::GetCommandResponse, ParameterId::FactoryDefaults) => {
2274 Ok(Self::GetFactoryDefaults(bytes[0] == 1))
2275 }
2276 (CommandClass::GetCommandResponse, ParameterId::LanguageCapabilities) => {
2277 Ok(Self::GetLanguageCapabilities(
2278 #[cfg(feature = "alloc")]
2279 bytes
2280 .chunks(2)
2281 .map(|chunk| Ok(core::str::from_utf8(chunk)?.to_string()))
2282 .collect::<Result<Vec<String>, RdmError>>()?,
2283 #[cfg(not(feature = "alloc"))]
2284 bytes
2285 .chunks(2)
2286 .map(|chunk| {
2287 Ok(String::from_utf8(Vec::<u8, 2>::from_slice(chunk).unwrap())?)
2288 })
2289 .collect::<Result<Vec<String<2>, 115>, RdmError>>()?,
2290 ))
2291 }
2292 (CommandClass::GetCommandResponse, ParameterId::Language) => Ok(Self::GetLanguage(
2293 #[cfg(feature = "alloc")]
2294 core::str::from_utf8(&bytes[0..=1])?.to_string(),
2295 #[cfg(not(feature = "alloc"))]
2296 String::from_utf8(Vec::<u8, 2>::from_slice(&bytes[0..=1]).unwrap())?,
2297 )),
2298 (CommandClass::GetCommandResponse, ParameterId::SoftwareVersionLabel) => {
2299 Ok(Self::GetSoftwareVersionLabel(decode_string_bytes(bytes)?))
2300 }
2301 (CommandClass::GetCommandResponse, ParameterId::BootSoftwareVersionId) => Ok(
2302 Self::GetBootSoftwareVersionId(u32::from_be_bytes(bytes.try_into()?)),
2303 ),
2304 (CommandClass::GetCommandResponse, ParameterId::BootSoftwareVersionLabel) => Ok(
2305 Self::GetBootSoftwareVersionLabel(decode_string_bytes(bytes)?),
2306 ),
2307 (CommandClass::GetCommandResponse, ParameterId::DmxPersonality) => {
2308 Ok(Self::GetDmxPersonality {
2309 current_personality: bytes[0],
2310 personality_count: bytes[1],
2311 })
2312 }
2313 (CommandClass::GetCommandResponse, ParameterId::DmxPersonalityDescription) => {
2314 Ok(Self::GetDmxPersonalityDescription {
2315 id: bytes[0],
2316 dmx_slots_required: u16::from_be_bytes(bytes[1..=2].try_into()?),
2317 description: decode_string_bytes(&bytes[3..])?,
2318 })
2319 }
2320 (CommandClass::GetCommandResponse, ParameterId::DmxStartAddress) => Ok(
2321 Self::GetDmxStartAddress(u16::from_be_bytes(bytes[0..=1].try_into()?)),
2322 ),
2323 (CommandClass::GetCommandResponse, ParameterId::SlotInfo) => Ok(Self::GetSlotInfo(
2324 #[cfg(feature = "alloc")]
2325 bytes
2326 .chunks(5)
2327 .map(|chunk| {
2328 Ok(SlotInfo::new(
2329 u16::from_be_bytes(chunk[0..=1].try_into()?),
2330 chunk[2].into(),
2331 u16::from_be_bytes(chunk[3..=4].try_into()?),
2332 ))
2333 })
2334 .collect::<Result<Vec<SlotInfo>, RdmError>>()?,
2335 #[cfg(not(feature = "alloc"))]
2336 bytes
2337 .chunks(5)
2338 .map(|chunk| {
2339 Ok(SlotInfo::new(
2340 u16::from_be_bytes(chunk[0..=1].try_into()?),
2341 chunk[2].into(),
2342 u16::from_be_bytes(chunk[3..=4].try_into()?),
2343 ))
2344 })
2345 .collect::<Result<Vec<SlotInfo, 46>, RdmError>>()?,
2346 )),
2347 (CommandClass::GetCommandResponse, ParameterId::SlotDescription) => {
2348 Ok(Self::GetSlotDescription {
2349 slot_id: u16::from_be_bytes(bytes[0..=1].try_into()?),
2350 description: decode_string_bytes(&bytes[2..])?,
2351 })
2352 }
2353 (CommandClass::GetCommandResponse, ParameterId::DefaultSlotValue) => {
2354 Ok(Self::GetDefaultSlotValue(
2355 #[cfg(feature = "alloc")]
2356 bytes
2357 .chunks(3)
2358 .map(|chunk| {
2359 Ok(DefaultSlotValue::new(
2360 u16::from_be_bytes(chunk[0..=1].try_into()?),
2361 chunk[2],
2362 ))
2363 })
2364 .collect::<Result<Vec<DefaultSlotValue>, RdmError>>()?,
2365 #[cfg(not(feature = "alloc"))]
2366 bytes
2367 .chunks(3)
2368 .map(|chunk| {
2369 Ok(DefaultSlotValue::new(
2370 u16::from_be_bytes(chunk[0..=1].try_into()?),
2371 chunk[2],
2372 ))
2373 })
2374 .collect::<Result<Vec<DefaultSlotValue, 77>, RdmError>>()?,
2375 ))
2376 }
2377 (CommandClass::GetCommandResponse, ParameterId::SensorDefinition) => {
2378 Ok(Self::GetSensorDefinition(SensorDefinition {
2379 id: bytes[0],
2380 kind: bytes[1].try_into()?,
2381 unit: bytes[2].try_into()?,
2382 prefix: bytes[3].try_into()?,
2383 range_minimum_value: i16::from_be_bytes(bytes[4..=5].try_into()?),
2384 range_maximum_value: i16::from_be_bytes(bytes[6..=7].try_into()?),
2385 normal_minimum_value: i16::from_be_bytes(bytes[8..=9].try_into()?),
2386 normal_maximum_value: i16::from_be_bytes(bytes[10..=11].try_into()?),
2387 is_lowest_highest_detected_value_supported: bytes[12] >> 1 & 1 == 1,
2388 is_recorded_value_supported: bytes[12] & 1 == 1,
2389 description: decode_string_bytes(&bytes[13..])?,
2390 }))
2391 }
2392 (CommandClass::GetCommandResponse, ParameterId::SensorValue) => {
2393 Ok(Self::GetSensorValue(SensorValue::new(
2394 bytes[0],
2395 i16::from_be_bytes(bytes[1..=2].try_into()?),
2396 i16::from_be_bytes(bytes[3..=4].try_into()?),
2397 i16::from_be_bytes(bytes[5..=6].try_into()?),
2398 i16::from_be_bytes(bytes[7..=8].try_into()?),
2399 )))
2400 }
2401 (CommandClass::SetCommandResponse, ParameterId::SensorValue) => {
2402 Ok(Self::SetSensorValue(SensorValue::new(
2403 bytes[0],
2404 i16::from_be_bytes(bytes[1..=2].try_into()?),
2405 i16::from_be_bytes(bytes[3..=4].try_into()?),
2406 i16::from_be_bytes(bytes[5..=6].try_into()?),
2407 i16::from_be_bytes(bytes[7..=8].try_into()?),
2408 )))
2409 }
2410 (CommandClass::GetCommandResponse, ParameterId::DeviceHours) => Ok(
2411 Self::GetDeviceHours(u32::from_be_bytes(bytes[0..=3].try_into()?)),
2412 ),
2413 (CommandClass::GetCommandResponse, ParameterId::LampHours) => Ok(Self::GetLampHours(
2414 u32::from_be_bytes(bytes[0..=3].try_into()?),
2415 )),
2416 (CommandClass::GetCommandResponse, ParameterId::LampStrikes) => Ok(
2417 Self::GetLampStrikes(u32::from_be_bytes(bytes[0..=3].try_into()?)),
2418 ),
2419 (CommandClass::GetCommandResponse, ParameterId::LampState) => {
2420 Ok(Self::GetLampState(bytes[0].try_into()?))
2421 }
2422 (CommandClass::GetCommandResponse, ParameterId::LampOnMode) => {
2423 Ok(Self::GetLampOnMode(bytes[0].try_into()?))
2424 }
2425 (CommandClass::GetCommandResponse, ParameterId::DevicePowerCycles) => Ok(
2426 Self::GetDevicePowerCycles(u32::from_be_bytes(bytes[0..=3].try_into()?)),
2427 ),
2428 (CommandClass::GetCommandResponse, ParameterId::DisplayInvert) => {
2429 Ok(Self::GetDisplayInvert(bytes[0].try_into()?))
2430 }
2431 (CommandClass::GetCommandResponse, ParameterId::DisplayLevel) => {
2432 Ok(Self::GetDisplayLevel(bytes[0]))
2433 }
2434 (CommandClass::GetCommandResponse, ParameterId::PanInvert) => {
2435 Ok(Self::GetPanInvert(bytes[0] == 1))
2436 }
2437 (CommandClass::GetCommandResponse, ParameterId::TiltInvert) => {
2438 Ok(Self::GetTiltInvert(bytes[0] == 1))
2439 }
2440 (CommandClass::GetCommandResponse, ParameterId::PanTiltSwap) => {
2441 Ok(Self::GetPanTiltSwap(bytes[0] == 1))
2442 }
2443 (CommandClass::GetCommandResponse, ParameterId::RealTimeClock) => {
2444 Ok(Self::GetRealTimeClock {
2445 year: u16::from_be_bytes(bytes[0..=1].try_into()?),
2446 month: bytes[2],
2447 day: bytes[3],
2448 hour: bytes[4],
2449 minute: bytes[5],
2450 second: bytes[6],
2451 })
2452 }
2453 (CommandClass::GetCommandResponse, ParameterId::IdentifyDevice) => {
2454 Ok(Self::GetIdentifyDevice(bytes[0] == 1))
2455 }
2456 (CommandClass::GetCommandResponse, ParameterId::PowerState) => {
2457 Ok(Self::GetPowerState(bytes[0].try_into()?))
2458 }
2459 (CommandClass::GetCommandResponse, ParameterId::PerformSelfTest) => {
2460 Ok(Self::GetPerformSelfTest(bytes[0] == 1))
2461 }
2462 (CommandClass::GetCommandResponse, ParameterId::SelfTestDescription) => {
2463 Ok(Self::GetSelfTestDescription {
2464 self_test_id: bytes[0].into(),
2465 description: decode_string_bytes(&bytes[1..])?,
2466 })
2467 }
2468 (CommandClass::GetCommandResponse, ParameterId::PresetPlayback) => {
2469 Ok(Self::GetPresetPlayback {
2470 mode: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2471 level: bytes[2],
2472 })
2473 }
2474 (CommandClass::GetCommandResponse, ParameterId::DmxBlockAddress) => {
2476 Ok(Self::GetDmxBlockAddress {
2477 total_sub_device_footprint: u16::from_be_bytes(bytes[0..=1].try_into()?),
2478 base_dmx_address: u16::from_be_bytes(bytes[2..=3].try_into()?),
2479 })
2480 }
2481 (CommandClass::GetCommandResponse, ParameterId::DmxFailMode) => {
2482 Ok(Self::GetDmxFailMode {
2483 scene_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2484 loss_of_signal_delay: u16::from_be_bytes(bytes[2..=3].try_into()?).into(),
2485 hold_time: u16::from_be_bytes(bytes[4..=5].try_into()?).into(),
2486 level: bytes[6],
2487 })
2488 }
2489 (CommandClass::GetCommandResponse, ParameterId::DmxStartupMode) => {
2490 Ok(Self::GetDmxStartupMode {
2491 scene_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2492 startup_delay: u16::from_be_bytes(bytes[2..=3].try_into()?).into(),
2493 hold_time: u16::from_be_bytes(bytes[4..=5].try_into()?).into(),
2494 level: bytes[6],
2495 })
2496 }
2497 (CommandClass::GetCommandResponse, ParameterId::PowerOnSelfTest) => {
2498 Ok(Self::GetPowerOnSelfTest(bytes[0] == 1))
2499 }
2500 (CommandClass::GetCommandResponse, ParameterId::LockState) => Ok(Self::GetLockState {
2501 lock_state_id: bytes[0],
2502 lock_state_count: bytes[1],
2503 }),
2504 (CommandClass::GetCommandResponse, ParameterId::LockStateDescription) => {
2505 Ok(Self::GetLockStateDescription {
2506 lock_state_id: bytes[0],
2507 description: decode_string_bytes(&bytes[1..])?,
2508 })
2509 }
2510 (CommandClass::GetCommandResponse, ParameterId::LockPin) => Ok(Self::GetLockPin(
2511 PinCode::try_from(u16::from_be_bytes(bytes[0..=1].try_into()?))?,
2512 )),
2513 (CommandClass::GetCommandResponse, ParameterId::BurnIn) => {
2514 Ok(Self::GetBurnIn(bytes[0]))
2515 }
2516 (CommandClass::GetCommandResponse, ParameterId::DimmerInfo) => {
2517 Ok(Self::GetDimmerInfo {
2518 minimum_level_lower_limit: u16::from_be_bytes(bytes[0..=1].try_into()?),
2519 minimum_level_upper_limit: u16::from_be_bytes(bytes[2..=3].try_into()?),
2520 maximum_level_lower_limit: u16::from_be_bytes(bytes[4..=5].try_into()?),
2521 maximum_level_upper_limit: u16::from_be_bytes(bytes[6..=7].try_into()?),
2522 number_of_supported_curves: bytes[8],
2523 levels_resolution: bytes[9],
2524 minimum_level_split_levels_supported: bytes[10] == 1,
2525 })
2526 }
2527 (CommandClass::GetCommandResponse, ParameterId::MinimumLevel) => {
2528 Ok(Self::GetMinimumLevel {
2529 minimum_level_increasing: u16::from_be_bytes(bytes[0..=1].try_into()?),
2530 minimum_level_decreasing: u16::from_be_bytes(bytes[2..=3].try_into()?),
2531 on_below_minimum: bytes[4] == 1,
2532 })
2533 }
2534 (CommandClass::GetCommandResponse, ParameterId::MaximumLevel) => Ok(
2535 Self::GetMaximumLevel(u16::from_be_bytes(bytes[0..=1].try_into()?)),
2536 ),
2537 (CommandClass::GetCommandResponse, ParameterId::Curve) => Ok(Self::GetCurve {
2538 curve_id: bytes[0],
2539 curve_count: bytes[1],
2540 }),
2541 (CommandClass::GetCommandResponse, ParameterId::CurveDescription) => {
2542 Ok(Self::GetCurveDescription {
2543 curve_id: bytes[0],
2544 description: decode_string_bytes(&bytes[1..])?,
2545 })
2546 }
2547 (CommandClass::GetCommandResponse, ParameterId::OutputResponseTime) => {
2548 Ok(Self::GetOutputResponseTime {
2549 response_time_id: bytes[0],
2550 response_time_count: bytes[1],
2551 })
2552 }
2553 (CommandClass::GetCommandResponse, ParameterId::OutputResponseTimeDescription) => {
2554 Ok(Self::GetOutputResponseTimeDescription {
2555 response_time_id: bytes[0],
2556 description: decode_string_bytes(&bytes[1..])?,
2557 })
2558 }
2559 (CommandClass::GetCommandResponse, ParameterId::ModulationFrequency) => {
2560 Ok(Self::GetModulationFrequency {
2561 modulation_frequency_id: bytes[0],
2562 modulation_frequency_count: bytes[1],
2563 })
2564 }
2565 (CommandClass::GetCommandResponse, ParameterId::ModulationFrequencyDescription) => {
2566 Ok(Self::GetModulationFrequencyDescription {
2567 modulation_frequency_id: bytes[0],
2568 frequency: u32::from_be_bytes(bytes[1..=4].try_into()?),
2569 description: decode_string_bytes(&bytes[5..])?,
2570 })
2571 }
2572 (CommandClass::GetCommandResponse, ParameterId::PresetInfo) => {
2573 Ok(Self::GetPresetInfo {
2574 level_field_supported: bytes[0] == 1,
2575 preset_sequence_supported: bytes[1] == 1,
2576 split_times_supported: bytes[2] == 1,
2577 dmx_fail_infinite_delay_time_supported: bytes[3] == 1,
2578 dmx_fail_infinite_hold_time_supported: bytes[4] == 1,
2579 startup_infinite_hold_time_supported: bytes[5] == 1,
2580 maximum_scene_number: u16::from_be_bytes(bytes[6..=7].try_into()?),
2581 minimum_preset_fade_time_supported: u16::from_be_bytes(
2582 bytes[8..=9].try_into()?,
2583 ),
2584 maximum_preset_fade_time_supported: u16::from_be_bytes(
2585 bytes[10..=11].try_into()?,
2586 ),
2587 minimum_preset_wait_time_supported: u16::from_be_bytes(
2588 bytes[12..=13].try_into()?,
2589 ),
2590 maximum_preset_wait_time_supported: u16::from_be_bytes(
2591 bytes[14..=15].try_into()?,
2592 ),
2593 minimum_dmx_fail_delay_time_supported: SupportedTimes::from(
2594 u16::from_be_bytes(bytes[16..=17].try_into()?),
2595 ),
2596 maximum_dmx_fail_delay_time_supported: SupportedTimes::from(
2597 u16::from_be_bytes(bytes[18..=19].try_into()?),
2598 ),
2599 minimum_dmx_fail_hold_time_supported: SupportedTimes::from(u16::from_be_bytes(
2600 bytes[20..=21].try_into()?,
2601 )),
2602 maximum_dmx_fail_hold_time_supported: SupportedTimes::from(u16::from_be_bytes(
2603 bytes[22..=23].try_into()?,
2604 )),
2605 minimum_startup_delay_time_supported: SupportedTimes::from(u16::from_be_bytes(
2606 bytes[24..=25].try_into()?,
2607 )),
2608 maximum_startup_delay_time_supported: SupportedTimes::from(u16::from_be_bytes(
2609 bytes[26..=27].try_into()?,
2610 )),
2611 minimum_startup_hold_time_supported: SupportedTimes::from(u16::from_be_bytes(
2612 bytes[28..=29].try_into()?,
2613 )),
2614 maximum_startup_hold_time_supported: SupportedTimes::from(u16::from_be_bytes(
2615 bytes[30..=31].try_into()?,
2616 )),
2617 })
2618 }
2619 (CommandClass::GetCommandResponse, ParameterId::PresetStatus) => {
2620 Ok(Self::GetPresetStatus {
2621 scene_id: u16::from_be_bytes(bytes[0..=1].try_into()?),
2622 up_fade_time: u16::from_be_bytes(bytes[2..=3].try_into()?),
2623 down_fade_time: u16::from_be_bytes(bytes[4..=5].try_into()?),
2624 wait_time: u16::from_be_bytes(bytes[6..=7].try_into()?),
2625 programmed: PresetProgrammed::try_from(bytes[8])?,
2626 })
2627 }
2628 (CommandClass::GetCommandResponse, ParameterId::PresetMergeMode) => {
2629 Ok(Self::GetPresetMergeMode(MergeMode::try_from(bytes[0])?))
2630 }
2631 (CommandClass::GetCommandResponse, ParameterId::ListInterfaces) => {
2633 Ok(Self::GetListInterfaces(
2634 #[cfg(feature = "alloc")]
2635 bytes
2636 .chunks(6)
2637 .map(|chunk| {
2638 Ok(NetworkInterface {
2639 interface_id: u32::from_be_bytes(chunk[0..=3].try_into()?),
2640 hardware_type: u16::from_be_bytes(chunk[4..=5].try_into()?).into(),
2641 })
2642 })
2643 .collect::<Result<Vec<NetworkInterface>, RdmError>>()?,
2644 #[cfg(not(feature = "alloc"))]
2645 bytes
2646 .chunks(6)
2647 .map(|chunk| {
2648 Ok(NetworkInterface {
2649 interface_id: u32::from_be_bytes(chunk[0..=3].try_into()?),
2650 hardware_type: u16::from_be_bytes(chunk[4..=5].try_into()?).into(),
2651 })
2652 })
2653 .collect::<Result<Vec<NetworkInterface, 38>, RdmError>>()?,
2654 ))
2655 }
2656 (CommandClass::GetCommandResponse, ParameterId::InterfaceLabel) => {
2657 Ok(Self::GetInterfaceLabel {
2658 interface_id: u32::from_be_bytes(bytes[0..=3].try_into()?),
2659 interface_label: decode_string_bytes(&bytes[4..])?,
2660 })
2661 }
2662 (CommandClass::GetCommandResponse, ParameterId::InterfaceHardwareAddressType1) => {
2663 Ok(Self::GetInterfaceHardwareAddressType1 {
2664 interface_id: u32::from_be_bytes(bytes[0..=3].try_into()?),
2665 hardware_address: <[u8; 6]>::try_from(&bytes[4..=9])?.into(),
2666 })
2667 }
2668 (CommandClass::GetCommandResponse, ParameterId::IpV4DhcpMode) => {
2669 Ok(Self::GetIpV4DhcpMode {
2670 interface_id: u32::from_be_bytes(bytes[0..=3].try_into()?),
2671 dhcp_mode: bytes[4] == 1,
2672 })
2673 }
2674 (CommandClass::GetCommandResponse, ParameterId::IpV4ZeroConfMode) => {
2675 Ok(Self::GetIpV4ZeroConfMode {
2676 interface_id: u32::from_be_bytes(bytes[0..=3].try_into()?),
2677 zero_conf_mode: bytes[4] == 1,
2678 })
2679 }
2680 (CommandClass::GetCommandResponse, ParameterId::IpV4CurrentAddress) => {
2681 Ok(Self::GetIpV4CurrentAddress {
2682 interface_id: u32::from_be_bytes(bytes[0..=3].try_into()?),
2683 address: <[u8; 4]>::try_from(&bytes[4..=7])?.into(),
2684 netmask: bytes[8],
2685 dhcp_status: DhcpMode::try_from(bytes[9])?,
2686 })
2687 }
2688 (CommandClass::GetCommandResponse, ParameterId::IpV4StaticAddress) => {
2689 Ok(Self::GetIpV4StaticAddress {
2690 interface_id: u32::from_be_bytes(bytes[0..=3].try_into()?),
2691 address: <[u8; 4]>::try_from(&bytes[4..=7])?.into(),
2692 netmask: bytes[8],
2693 })
2694 }
2695 (CommandClass::GetCommandResponse, ParameterId::IpV4DefaultRoute) => {
2696 Ok(Self::GetIpV4DefaultRoute {
2697 interface_id: u32::from_be_bytes(bytes[0..=3].try_into()?),
2698 address: <[u8; 4]>::try_from(&bytes[4..=7])?.into(),
2699 })
2700 }
2701 (CommandClass::GetCommandResponse, ParameterId::DnsIpV4NameServer) => {
2702 Ok(Self::GetDnsIpV4NameServer {
2703 name_server_index: bytes[0],
2704 address: <[u8; 4]>::try_from(&bytes[1..=4])?.into(),
2705 })
2706 }
2707 (CommandClass::GetCommand, ParameterId::EndpointList) => Ok(Self::GetEndpointList {
2709 list_change_number: u32::from_be_bytes(bytes[0..=3].try_into()?),
2710 #[cfg(feature = "alloc")]
2711 endpoint_list: bytes[4..]
2712 .chunks(3)
2713 .map(|chunk| {
2714 Ok((
2715 u16::from_be_bytes(chunk[0..=1].try_into()?).into(),
2716 chunk[1].try_into()?,
2717 ))
2718 })
2719 .collect::<Result<Vec<(EndpointId, EndpointType)>, RdmError>>()?,
2720 #[cfg(not(feature = "alloc"))]
2721 endpoint_list: bytes[4..]
2722 .chunks(6)
2723 .map(|chunk| {
2724 Ok((
2725 u16::from_be_bytes(chunk[0..=1].try_into()?).into(),
2726 chunk[1].try_into()?,
2727 ))
2728 })
2729 .collect::<Result<Vec<(EndpointId, EndpointType), 75>, RdmError>>()?,
2730 }),
2731 (CommandClass::GetCommand, ParameterId::EndpointListChange) => {
2732 Ok(Self::GetEndpointListChange {
2733 list_change_number: u32::from_be_bytes(bytes[0..=3].try_into()?),
2734 })
2735 }
2736 (CommandClass::GetCommand, ParameterId::IdentifyEndpoint) => {
2737 Ok(Self::GetIdentifyEndpoint {
2738 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2739 identify: bytes[2] == 1,
2740 })
2741 }
2742 (CommandClass::SetCommand, ParameterId::IdentifyEndpoint) => {
2743 Ok(Self::SetIdentifyEndpoint {
2744 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2745 })
2746 }
2747 (CommandClass::GetCommand, ParameterId::EndpointToUniverse) => {
2748 Ok(Self::GetEndpointToUniverse {
2749 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2750 universe: u16::from_be_bytes(bytes[2..=3].try_into()?),
2751 })
2752 }
2753 (CommandClass::SetCommand, ParameterId::EndpointToUniverse) => {
2754 Ok(Self::SetEndpointToUniverse {
2755 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2756 })
2757 }
2758 (CommandClass::GetCommand, ParameterId::EndpointMode) => Ok(Self::GetEndpointMode {
2759 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2760 mode: bytes[2].try_into()?,
2761 }),
2762 (CommandClass::SetCommand, ParameterId::EndpointMode) => Ok(Self::SetEndpointMode {
2763 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2764 }),
2765 (CommandClass::GetCommand, ParameterId::EndpointLabel) => Ok(Self::GetEndpointLabel {
2766 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2767 label: decode_string_bytes(&bytes[2..])?,
2768 }),
2769 (CommandClass::SetCommand, ParameterId::EndpointLabel) => Ok(Self::SetEndpointLabel {
2770 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2771 }),
2772 (CommandClass::GetCommand, ParameterId::RdmTrafficEnable) => {
2773 Ok(Self::GetRdmTrafficEnable {
2774 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2775 enable: bytes[2] == 1,
2776 })
2777 }
2778 (CommandClass::SetCommand, ParameterId::RdmTrafficEnable) => {
2779 Ok(Self::SetRdmTrafficEnable {
2780 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2781 })
2782 }
2783 (CommandClass::GetCommand, ParameterId::DiscoveryState) => {
2784 Ok(Self::GetDiscoveryState {
2785 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2786 device_count: u16::from_be_bytes(bytes[2..=3].try_into()?).into(),
2787 discovery_state: bytes[4].try_into()?,
2788 })
2789 }
2790 (CommandClass::SetCommand, ParameterId::DiscoveryState) => {
2791 Ok(Self::SetDiscoveryState {
2792 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2793 })
2794 }
2795 (CommandClass::GetCommand, ParameterId::BackgroundDiscovery) => {
2796 Ok(Self::GetBackgroundDiscovery {
2797 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2798 enabled: bytes[2] == 1,
2799 })
2800 }
2801 (CommandClass::SetCommand, ParameterId::BackgroundDiscovery) => {
2802 Ok(Self::SetBackgroundDiscovery {
2803 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2804 })
2805 }
2806 (CommandClass::GetCommand, ParameterId::EndpointTiming) => {
2807 Ok(Self::GetEndpointTiming {
2808 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2809 current_setting_id: bytes[2],
2810 setting_count: bytes[3],
2811 })
2812 }
2813 (CommandClass::SetCommand, ParameterId::EndpointTiming) => {
2814 Ok(Self::SetEndpointTiming {
2815 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2816 })
2817 }
2818 (CommandClass::GetCommand, ParameterId::EndpointTimingDescription) => {
2819 Ok(Self::GetEndpointTimingDescription {
2820 setting_id: bytes[0],
2821 description: decode_string_bytes(&bytes[1..])?,
2822 })
2823 }
2824 (CommandClass::GetCommand, ParameterId::EndpointResponders) => {
2825 Ok(Self::GetEndpointResponders {
2826 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2827 list_change_number: u32::from_be_bytes(bytes[2..=5].try_into()?),
2828 #[cfg(feature = "alloc")]
2829 responders: bytes[6..]
2830 .chunks(6)
2831 .map(|chunk| {
2832 Ok(DeviceUID::new(
2833 u16::from_be_bytes(chunk[0..=1].try_into()?),
2834 u32::from_be_bytes(chunk[2..=5].try_into()?),
2835 ))
2836 })
2837 .collect::<Result<Vec<DeviceUID>, RdmError>>()?,
2838 #[cfg(not(feature = "alloc"))]
2839 responders: bytes[6..]
2840 .chunks(6)
2841 .map(|chunk| {
2842 Ok(DeviceUID::new(
2843 u16::from_be_bytes(chunk[0..=1].try_into()?),
2844 u32::from_be_bytes(chunk[2..=5].try_into()?),
2845 ))
2846 })
2847 .collect::<Result<Vec<DeviceUID, 37>, RdmError>>()?,
2848 })
2849 }
2850 (CommandClass::GetCommand, ParameterId::EndpointResponderListChange) => {
2851 Ok(Self::GetEndpointResponderListChange {
2852 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2853 list_change_number: u32::from_be_bytes(bytes[2..=5].try_into()?),
2854 })
2855 }
2856 (CommandClass::GetCommand, ParameterId::BindingControlFields) => {
2857 Ok(Self::GetBindingControlFields {
2858 endpoint_id: u16::from_be_bytes(bytes[0..=1].try_into()?).into(),
2859 uid: DeviceUID::new(
2860 u16::from_be_bytes(bytes[2..=3].try_into()?),
2861 u32::from_be_bytes(bytes[4..=7].try_into()?),
2862 ),
2863 control_field: u16::from_be_bytes(bytes[8..=9].try_into()?),
2864 binding_uid: DeviceUID::new(
2865 u16::from_be_bytes(bytes[10..=11].try_into()?),
2866 u32::from_be_bytes(bytes[12..=15].try_into()?),
2867 ),
2868 })
2869 }
2870 (CommandClass::GetCommand, ParameterId::BackgroundQueuedStatusPolicy) => {
2871 Ok(Self::GetBackgroundQueuedStatusPolicy {
2872 current_policy_id: bytes[0],
2873 policy_count: bytes[1],
2874 })
2875 }
2876 (CommandClass::GetCommand, ParameterId::BackgroundQueuedStatusPolicyDescription) => {
2877 Ok(Self::GetBackgroundQueuedStatusPolicyDescription {
2878 policy_id: bytes[0],
2879 description: decode_string_bytes(&bytes[1..])?,
2880 })
2881 }
2882 (CommandClass::GetCommandResponse, ParameterId::ComponentScope) => {
2884 Ok(Self::GetComponentScope {
2885 scope_slot: u16::from_be_bytes(bytes[0..=1].try_into()?),
2886 scope_string: decode_string_bytes(&bytes[2..=64])?,
2887 static_config_type: bytes[65].try_into()?,
2888 static_ipv4_address: <[u8; 4]>::try_from(&bytes[66..=69])?.into(),
2889 static_ipv6_address: <[u8; 16]>::try_from(&bytes[70..=85])?.into(),
2890 static_port: u16::from_be_bytes(bytes[2..=3].try_into()?),
2891 })
2892 }
2893 (CommandClass::GetCommandResponse, ParameterId::SearchDomain) => {
2894 Ok(Self::GetSearchDomain(decode_string_bytes(bytes)?))
2895 }
2896 (CommandClass::GetCommandResponse, ParameterId::TcpCommsStatus) => {
2897 Ok(Self::GetTcpCommsStatus {
2898 scope_string: decode_string_bytes(&bytes[0..=62])?,
2899 broker_ipv4_address: <[u8; 4]>::try_from(&bytes[63..=66])?.into(),
2900 broker_ipv6_address: <[u8; 16]>::try_from(&bytes[67..=82])?.into(),
2901 broker_port: u16::from_be_bytes(bytes[83..=84].try_into()?),
2902 unhealthy_tcp_events: u16::from_be_bytes(bytes[85..=86].try_into()?),
2903 })
2904 }
2905 (CommandClass::GetCommandResponse, ParameterId::BrokerStatus) => {
2906 Ok(Self::GetBrokerStatus {
2907 is_allowing_set_commands: bytes[0] == 1,
2908 broker_state: bytes[1].try_into()?,
2909 })
2910 }
2911 (_, ParameterId::ManufacturerSpecific(_)) => Ok(Self::ManufacturerSpecific(
2912 #[cfg(feature = "alloc")]
2913 bytes.to_vec(),
2914 #[cfg(not(feature = "alloc"))]
2915 Vec::<u8, 231>::from_slice(bytes).unwrap(),
2916 )),
2917 (_, _) => Ok(Self::Unsupported(
2918 #[cfg(feature = "alloc")]
2919 bytes.to_vec(),
2920 #[cfg(not(feature = "alloc"))]
2921 Vec::<u8, 231>::from_slice(bytes).unwrap(),
2922 )),
2923 }
2924 }
2925}
2926
2927#[derive(Clone, Debug, PartialEq)]
2928pub struct RdmFrameResponse {
2929 pub destination_uid: DeviceUID,
2930 pub source_uid: DeviceUID,
2931 pub transaction_number: u8,
2932 pub response_type: ResponseType,
2933 pub message_count: u8,
2934 pub sub_device_id: SubDeviceId,
2935 pub command_class: CommandClass,
2936 pub parameter_id: ParameterId,
2937 pub parameter_data: ResponseData,
2938}
2939
2940impl RdmFrameResponse {
2941 pub fn encode(&self) -> EncodedFrame {
2942 let parameter_data = self.parameter_data.encode();
2943
2944 let message_length = 24 + parameter_data.len();
2945
2946 #[cfg(feature = "alloc")]
2947 let mut buf = Vec::with_capacity(message_length + 2);
2948 #[cfg(not(feature = "alloc"))]
2949 let mut buf = Vec::new();
2950
2951 #[cfg(feature = "alloc")]
2952 buf.push(RDM_START_CODE_BYTE);
2953 #[cfg(not(feature = "alloc"))]
2954 buf.push(RDM_START_CODE_BYTE).unwrap();
2955
2956 #[cfg(feature = "alloc")]
2957 buf.push(RDM_SUB_START_CODE_BYTE);
2958 #[cfg(not(feature = "alloc"))]
2959 buf.push(RDM_SUB_START_CODE_BYTE).unwrap();
2960
2961 #[cfg(feature = "alloc")]
2962 buf.push(message_length as u8);
2963 #[cfg(not(feature = "alloc"))]
2964 buf.push(message_length as u8).unwrap();
2965
2966 buf.extend(self.destination_uid.manufacturer_id.to_be_bytes());
2967 buf.extend(self.destination_uid.device_id.to_be_bytes());
2968 buf.extend(self.source_uid.manufacturer_id.to_be_bytes());
2969 buf.extend(self.source_uid.device_id.to_be_bytes());
2970
2971 #[cfg(feature = "alloc")]
2972 buf.push(self.transaction_number);
2973 #[cfg(not(feature = "alloc"))]
2974 buf.push(self.transaction_number).unwrap();
2975
2976 #[cfg(feature = "alloc")]
2977 buf.push(self.response_type as u8);
2978 #[cfg(not(feature = "alloc"))]
2979 buf.push(self.response_type as u8).unwrap();
2980
2981 #[cfg(feature = "alloc")]
2983 buf.push(self.message_count);
2984 #[cfg(not(feature = "alloc"))]
2985 buf.push(self.message_count).unwrap();
2986
2987 buf.extend(u16::from(self.sub_device_id).to_be_bytes());
2988
2989 #[cfg(feature = "alloc")]
2990 buf.push(self.command_class as u8);
2991 #[cfg(not(feature = "alloc"))]
2992 buf.push(self.command_class as u8).unwrap();
2993
2994 buf.extend(u16::from(self.parameter_id).to_be_bytes());
2995
2996 #[cfg(feature = "alloc")]
2997 buf.push(parameter_data.len() as u8);
2998 #[cfg(not(feature = "alloc"))]
2999 buf.push(parameter_data.len() as u8).unwrap();
3000
3001 buf.extend(parameter_data);
3002 buf.extend(bsd_16_crc(&buf[..]).to_be_bytes());
3003
3004 buf
3005 }
3006
3007 pub fn decode(bytes: &[u8]) -> Result<Self, RdmError> {
3008 let message_length = bytes[2];
3009
3010 if message_length < 24 {
3011 return Err(RdmError::InvalidMessageLength(message_length));
3012 }
3013
3014 if bytes.len() < message_length as usize + 2 {
3015 return Err(RdmError::InvalidMessageLength(message_length));
3016 }
3017
3018 let packet_checksum = u16::from_be_bytes(
3019 bytes[message_length as usize..=message_length as usize + 1].try_into()?,
3020 );
3021
3022 let decoded_checksum = bsd_16_crc(&bytes[..message_length as usize]);
3023
3024 if decoded_checksum != packet_checksum {
3025 return Err(RdmError::InvalidChecksum(decoded_checksum, packet_checksum));
3026 }
3027
3028 let destination_uid = DeviceUID::from(<[u8; 6]>::try_from(&bytes[3..=8])?);
3029
3030 let source_uid = DeviceUID::from(<[u8; 6]>::try_from(&bytes[9..=14])?);
3031
3032 let transaction_number = bytes[15];
3033
3034 let response_type = ResponseType::try_from(bytes[16])?;
3035
3036 let message_count = bytes[17];
3037
3038 let sub_device_id = u16::from_be_bytes(bytes[18..=19].try_into()?).into();
3039
3040 let command_class = CommandClass::try_from(bytes[20])?;
3041
3042 let parameter_id = u16::from_be_bytes(bytes[21..=22].try_into()?).into();
3043
3044 let parameter_data_length = bytes[23];
3045
3046 if parameter_data_length > 231 {
3047 return Err(RdmError::InvalidParameterDataLength(parameter_data_length));
3048 }
3049
3050 let parameter_data = ResponseData::decode(
3051 response_type,
3052 command_class,
3053 parameter_data_length,
3054 parameter_id,
3055 &bytes[24..=(24 + parameter_data_length as usize - 1)],
3056 )?;
3057
3058 Ok(Self {
3059 destination_uid,
3060 source_uid,
3061 transaction_number,
3062 response_type,
3063 message_count,
3064 sub_device_id,
3065 command_class,
3066 parameter_id,
3067 parameter_data,
3068 })
3069 }
3070}
3071
3072impl TryFrom<&[u8]> for RdmFrameResponse {
3073 type Error = RdmError;
3074
3075 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
3076 RdmFrameResponse::decode(bytes)
3077 }
3078}
3079
3080#[derive(Copy, Clone, Debug, PartialEq)]
3081pub struct DiscoveryUniqueBranchFrameResponse(pub DeviceUID);
3082
3083impl DiscoveryUniqueBranchFrameResponse {
3084 pub fn encode(&self) -> EncodedFrame {
3085 #[cfg(feature = "alloc")]
3086 let mut buf = Vec::with_capacity(24);
3087 #[cfg(not(feature = "alloc"))]
3088 let mut buf = Vec::new();
3089
3090 buf.extend(iter::repeat(DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE).take(7));
3091
3092 #[cfg(feature = "alloc")]
3093 buf.push(DISCOVERY_UNIQUE_BRANCH_PREAMBLE_SEPARATOR_BYTE);
3094 #[cfg(not(feature = "alloc"))]
3095 buf.push(DISCOVERY_UNIQUE_BRANCH_PREAMBLE_SEPARATOR_BYTE)
3096 .unwrap();
3097
3098 let [manufacturer_id1, manufacturer_id0] = self.0.manufacturer_id.to_be_bytes();
3099
3100 buf.extend([
3101 manufacturer_id1 | 0xaa,
3102 manufacturer_id1 | 0x55,
3103 manufacturer_id0 | 0xaa,
3104 manufacturer_id0 | 0x55,
3105 ]);
3106
3107 let [device_id3, device_id2, device_id1, device_id0] = self.0.device_id.to_be_bytes();
3108
3109 buf.extend([
3110 device_id3 | 0xaa,
3111 device_id3 | 0x55,
3112 device_id2 | 0xaa,
3113 device_id2 | 0x55,
3114 device_id1 | 0xaa,
3115 device_id1 | 0x55,
3116 device_id0 | 0xaa,
3117 device_id0 | 0x55,
3118 ]);
3119
3120 let [checksum1, checksum0] = bsd_16_crc(&buf[8..]).to_be_bytes();
3121
3122 buf.extend([
3123 checksum1 | 0xaa,
3124 checksum1 | 0x55,
3125 checksum0 | 0xaa,
3126 checksum0 | 0x55,
3127 ]);
3128
3129 buf
3130 }
3131
3132 pub fn decode(bytes: &[u8]) -> Result<Self, RdmError> {
3133 let Some(frame_start_index) = bytes.iter().position(|&x| x == 0xaa) else {
3134 return Err(RdmError::InvalidDiscoveryUniqueBranchPreamble);
3135 };
3136
3137 let euid = &bytes[(frame_start_index + 1)..=(frame_start_index + 12)];
3138
3139 let ecs = &bytes[(frame_start_index + 13)..=(frame_start_index + 16)];
3140
3141 let decoded_checksum = bsd_16_crc(euid);
3142
3143 let checksum = u16::from_be_bytes([ecs[0] & ecs[1], ecs[2] & ecs[3]]);
3144
3145 if checksum != decoded_checksum {
3146 return Err(RdmError::InvalidChecksum(decoded_checksum, checksum));
3147 }
3148
3149 let manufacturer_id = u16::from_be_bytes([euid[0] & euid[1], euid[2] & euid[3]]);
3150
3151 let device_id = u32::from_be_bytes([
3152 euid[4] & euid[5],
3153 euid[6] & euid[7],
3154 euid[8] & euid[9],
3155 euid[10] & euid[11],
3156 ]);
3157
3158 Ok(Self(DeviceUID::new(manufacturer_id, device_id)))
3159 }
3160}
3161
3162impl TryFrom<&[u8]> for DiscoveryUniqueBranchFrameResponse {
3163 type Error = RdmError;
3164
3165 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
3166 DiscoveryUniqueBranchFrameResponse::decode(bytes)
3167 }
3168}
3169
3170#[allow(clippy::large_enum_variant)]
3171#[derive(Clone, Debug, PartialEq)]
3172pub enum RdmResponse {
3173 RdmFrame(RdmFrameResponse),
3174 DiscoveryUniqueBranchFrame(DiscoveryUniqueBranchFrameResponse),
3175}
3176
3177impl RdmResponse {
3178 pub fn encode(&self) -> EncodedFrame {
3179 match self {
3180 RdmResponse::RdmFrame(frame) => frame.encode(),
3181 RdmResponse::DiscoveryUniqueBranchFrame(frame) => frame.encode(),
3182 }
3183 }
3184
3185 pub fn decode(bytes: &[u8]) -> Result<Self, RdmError> {
3186 if bytes[0] == RDM_START_CODE_BYTE && bytes[1] == RDM_SUB_START_CODE_BYTE {
3187 if bytes.len() < 25 {
3188 return Err(RdmError::InvalidFrameLength(bytes.len() as u8));
3189 }
3190
3191 return RdmFrameResponse::decode(bytes).map(RdmResponse::RdmFrame);
3192 }
3193
3194 if bytes[0] == DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE
3195 || bytes[0] == DISCOVERY_UNIQUE_BRANCH_PREAMBLE_SEPARATOR_BYTE
3196 {
3197 if bytes.len() < 17 {
3198 return Err(RdmError::InvalidFrameLength(bytes.len() as u8));
3199 }
3200
3201 return DiscoveryUniqueBranchFrameResponse::decode(bytes)
3202 .map(RdmResponse::DiscoveryUniqueBranchFrame);
3203 }
3204
3205 Err(RdmError::InvalidStartCode)
3206 }
3207}
3208
3209impl TryFrom<&[u8]> for RdmResponse {
3210 type Error = RdmError;
3211
3212 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
3213 RdmResponse::decode(bytes)
3214 }
3215}
3216
3217#[cfg(test)]
3218mod tests {
3219 use super::*;
3220
3221 #[test]
3222 fn should_decode_valid_rdm_ack_response() {
3223 let decoded = RdmResponse::decode(&[
3224 0xcc, 0x01, 25, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x10, 0x00, 0x01, 0x01, 0x01, 0x43, ]);
3239
3240 let expected = Ok(RdmResponse::RdmFrame(RdmFrameResponse {
3241 destination_uid: DeviceUID::new(0x0102, 0x03040506),
3242 source_uid: DeviceUID::new(0x0605, 0x04030201),
3243 transaction_number: 0x00,
3244 response_type: ResponseType::Ack,
3245 message_count: 0x00,
3246 sub_device_id: SubDeviceId::RootDevice,
3247 command_class: CommandClass::GetCommandResponse,
3248 parameter_id: ParameterId::IdentifyDevice,
3249 parameter_data: ResponseData::ParameterData(Some(
3250 ResponseParameterData::GetIdentifyDevice(true),
3251 )),
3252 }));
3253
3254 assert_eq!(decoded, expected);
3255 }
3256
3257 #[test]
3258 fn should_encode_valid_rdm_ack_response() {
3259 let encoded = RdmResponse::RdmFrame(RdmFrameResponse {
3260 destination_uid: DeviceUID::new(0x0102, 0x03040506),
3261 source_uid: DeviceUID::new(0x0605, 0x04030201),
3262 transaction_number: 0x00,
3263 response_type: ResponseType::Ack,
3264 message_count: 0x00,
3265 sub_device_id: SubDeviceId::RootDevice,
3266 command_class: CommandClass::GetCommandResponse,
3267 parameter_id: ParameterId::IdentifyDevice,
3268 parameter_data: ResponseData::ParameterData(Some(
3269 ResponseParameterData::GetIdentifyDevice(true),
3270 )),
3271 })
3272 .encode();
3273
3274 let expected = &[
3275 0xcc, 0x01, 25, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x10, 0x00, 0x01, 0x01, 0x01, 0x43, ];
3290
3291 assert_eq!(encoded, expected);
3292 }
3293
3294 #[test]
3295 fn should_decode_valid_rdm_ack_manufacturer_specific_response() {
3296 let decoded = RdmResponse::decode(&[
3297 0xcc, 0x01, 28, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x80, 0x80, 0x04, 0x04, 0x03, 0x02, 0x01, 0x02, 0x52, ]);
3312
3313 let expected = Ok(RdmResponse::RdmFrame(RdmFrameResponse {
3314 destination_uid: DeviceUID::new(0x0102, 0x03040506),
3315 source_uid: DeviceUID::new(0x0605, 0x04030201),
3316 transaction_number: 0x00,
3317 response_type: ResponseType::Ack,
3318 message_count: 0x00,
3319 sub_device_id: SubDeviceId::RootDevice,
3320 command_class: CommandClass::SetCommandResponse,
3321 parameter_id: ParameterId::ManufacturerSpecific(0x8080),
3322 #[cfg(feature = "alloc")]
3323 parameter_data: ResponseData::ParameterData(Some(
3324 ResponseParameterData::ManufacturerSpecific(vec![0x04, 0x03, 0x02, 0x01]),
3325 )),
3326 #[cfg(not(feature = "alloc"))]
3327 parameter_data: ResponseData::ParameterData(Some(
3328 ResponseParameterData::ManufacturerSpecific(
3329 Vec::<u8, 231>::from_slice(&[0x04, 0x03, 0x02, 0x01]).unwrap(),
3330 ),
3331 )),
3332 }));
3333
3334 assert_eq!(decoded, expected);
3335 }
3336
3337 #[test]
3338 fn should_encode_valid_rdm_ack_manufacturer_specific_response() {
3339 let encoded = RdmResponse::RdmFrame(RdmFrameResponse {
3340 destination_uid: DeviceUID::new(0x0102, 0x03040506),
3341 source_uid: DeviceUID::new(0x0605, 0x04030201),
3342 transaction_number: 0x00,
3343 response_type: ResponseType::Ack,
3344 message_count: 0x00,
3345 sub_device_id: SubDeviceId::RootDevice,
3346 command_class: CommandClass::SetCommandResponse,
3347 parameter_id: ParameterId::ManufacturerSpecific(0x8080),
3348 #[cfg(feature = "alloc")]
3349 parameter_data: ResponseData::ParameterData(Some(
3350 ResponseParameterData::ManufacturerSpecific(vec![0x04, 0x03, 0x02, 0x01]),
3351 )),
3352 #[cfg(not(feature = "alloc"))]
3353 parameter_data: ResponseData::ParameterData(Some(
3354 ResponseParameterData::ManufacturerSpecific(
3355 Vec::<u8, 231>::from_slice(&[0x04, 0x03, 0x02, 0x01]).unwrap(),
3356 ),
3357 )),
3358 })
3359 .encode();
3360
3361 let expected = &[
3362 0xcc, 0x01, 28, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x80, 0x80, 0x04, 0x04, 0x03, 0x02, 0x01, 0x02, 0x52, ];
3377
3378 assert_eq!(encoded, expected);
3379 }
3380
3381 #[test]
3382 fn should_decode_valid_rdm_ack_timer_response() {
3383 let decoded = RdmResponse::decode(&[
3384 0xcc, 0x01, 26, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x21, 0x10, 0x00, 0x02, 0x00, 0x0a, 0x01, 0x4f, ]);
3399
3400 let expected = Ok(RdmResponse::RdmFrame(RdmFrameResponse {
3401 destination_uid: DeviceUID::new(0x0102, 0x03040506),
3402 source_uid: DeviceUID::new(0x0605, 0x04030201),
3403 transaction_number: 0x00,
3404 response_type: ResponseType::AckTimer,
3405 message_count: 0x00,
3406 sub_device_id: SubDeviceId::RootDevice,
3407 command_class: CommandClass::GetCommandResponse,
3408 parameter_id: ParameterId::IdentifyDevice,
3409 parameter_data: ResponseData::EstimateResponseTime(0x0a),
3410 }));
3411
3412 assert_eq!(decoded, expected);
3413 }
3414
3415 #[test]
3416 fn should_encode_valid_rdm_ack_timer_response() {
3417 let encoded = RdmResponse::RdmFrame(RdmFrameResponse {
3418 destination_uid: DeviceUID::new(0x0102, 0x03040506),
3419 source_uid: DeviceUID::new(0x0605, 0x04030201),
3420 transaction_number: 0x00,
3421 response_type: ResponseType::AckTimer,
3422 message_count: 0x00,
3423 sub_device_id: SubDeviceId::RootDevice,
3424 command_class: CommandClass::GetCommandResponse,
3425 parameter_id: ParameterId::IdentifyDevice,
3426 parameter_data: ResponseData::EstimateResponseTime(0x0a),
3427 })
3428 .encode();
3429
3430 let expected = &[
3431 0xcc, 0x01, 26, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x21, 0x10, 0x00, 0x02, 0x00, 0x0a, 0x01, 0x4f, ];
3446
3447 assert_eq!(encoded, expected);
3448 }
3449
3450 #[test]
3451 fn should_decode_valid_rdm_nack_reason_response() {
3452 let decoded = RdmResponse::decode(&[
3453 0xcc, 0x01, 26, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x10, 0x00, 0x02, 0x00, 0x01, 0x01, 0x47, ]);
3468
3469 let expected = Ok(RdmResponse::RdmFrame(RdmFrameResponse {
3470 destination_uid: DeviceUID::new(0x0102, 0x03040506),
3471 source_uid: DeviceUID::new(0x0605, 0x04030201),
3472 transaction_number: 0x00,
3473 response_type: ResponseType::NackReason,
3474 message_count: 0x00,
3475 sub_device_id: SubDeviceId::RootDevice,
3476 command_class: CommandClass::GetCommandResponse,
3477 parameter_id: ParameterId::IdentifyDevice,
3478 parameter_data: ResponseData::NackReason(ResponseNackReasonCode::FormatError),
3479 }));
3480
3481 assert_eq!(decoded, expected);
3482 }
3483
3484 #[test]
3485 fn should_encode_valid_rdm_nack_reason_response() {
3486 let encoded = RdmResponse::RdmFrame(RdmFrameResponse {
3487 destination_uid: DeviceUID::new(0x0102, 0x03040506),
3488 source_uid: DeviceUID::new(0x0605, 0x04030201),
3489 transaction_number: 0x00,
3490 response_type: ResponseType::NackReason,
3491 message_count: 0x00,
3492 sub_device_id: SubDeviceId::RootDevice,
3493 command_class: CommandClass::GetCommandResponse,
3494 parameter_id: ParameterId::IdentifyDevice,
3495 parameter_data: ResponseData::NackReason(ResponseNackReasonCode::FormatError),
3496 })
3497 .encode();
3498
3499 let expected = &[
3500 0xcc, 0x01, 26, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x21, 0x10, 0x00, 0x02, 0x00, 0x01, 0x01, 0x47, ];
3515
3516 assert_eq!(encoded, expected);
3517 }
3518
3519 #[test]
3520 fn should_decode_valid_rdm_ack_overflow_response() {
3521 let decoded = RdmResponse::decode(&[
3522 0xcc, 0x01, 25, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x21, 0x10, 0x00, 0x01, 0x01, 0x01, 0x46, ]);
3537
3538 let expected = Ok(RdmResponse::RdmFrame(RdmFrameResponse {
3539 destination_uid: DeviceUID::new(0x0102, 0x03040506),
3540 source_uid: DeviceUID::new(0x0605, 0x04030201),
3541 transaction_number: 0x00,
3542 response_type: ResponseType::AckOverflow,
3543 message_count: 0x00,
3544 sub_device_id: SubDeviceId::RootDevice,
3545 command_class: CommandClass::GetCommandResponse,
3546 parameter_id: ParameterId::IdentifyDevice,
3547 parameter_data: ResponseData::ParameterData(Some(
3548 ResponseParameterData::GetIdentifyDevice(true),
3549 )),
3550 }));
3551
3552 assert_eq!(decoded, expected);
3553 }
3554
3555 #[test]
3556 fn should_encode_valid_rdm_ack_overflow_response() {
3557 let encoded = RdmResponse::RdmFrame(RdmFrameResponse {
3558 destination_uid: DeviceUID::new(0x0102, 0x03040506),
3559 source_uid: DeviceUID::new(0x0605, 0x04030201),
3560 transaction_number: 0x00,
3561 response_type: ResponseType::AckOverflow,
3562 message_count: 0x00,
3563 sub_device_id: SubDeviceId::RootDevice,
3564 command_class: CommandClass::GetCommandResponse,
3565 parameter_id: ParameterId::IdentifyDevice,
3566 parameter_data: ResponseData::ParameterData(Some(
3567 ResponseParameterData::GetIdentifyDevice(true),
3568 )),
3569 })
3570 .encode();
3571
3572 let expected = &[
3573 0xcc, 0x01, 25, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x21, 0x10, 0x00, 0x01, 0x01, 0x01, 0x46, ];
3588
3589 assert_eq!(encoded, expected);
3590 }
3591
3592 #[test]
3593 fn should_decode_valid_discovery_unique_branch_response() {
3594 let decoded = RdmResponse::decode(&[
3596 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE,
3597 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE,
3598 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE,
3599 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE,
3600 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE,
3601 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE,
3602 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE,
3603 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_SEPARATOR_BYTE,
3604 0xab, 0x55, 0xaa, 0x57, 0xab, 0x57, 0xae, 0x55, 0xaf, 0x55, 0xae, 0x57, 0xae, 0x57, 0xaf, 0x5f, ]);
3621
3622 let expected = Ok(RdmResponse::DiscoveryUniqueBranchFrame(
3623 DiscoveryUniqueBranchFrameResponse(DeviceUID::new(0x0102, 0x03040506)),
3624 ));
3625
3626 assert_eq!(decoded, expected);
3627
3628 let decoded = RdmResponse::decode(&[
3630 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_SEPARATOR_BYTE,
3631 0xab, 0x55, 0xaa, 0x57, 0xab, 0x57, 0xae, 0x55, 0xaf, 0x55, 0xae, 0x57, 0xae, 0x57, 0xaf, 0x5f, ]);
3648
3649 let expected = Ok(RdmResponse::DiscoveryUniqueBranchFrame(
3650 DiscoveryUniqueBranchFrameResponse(DeviceUID::new(0x0102, 0x03040506)),
3651 ));
3652
3653 assert_eq!(decoded, expected);
3654 }
3655
3656 #[test]
3657 fn should_encode_valid_discovery_unique_branch_response() {
3658 let encoded = RdmResponse::DiscoveryUniqueBranchFrame(DiscoveryUniqueBranchFrameResponse(
3659 DeviceUID::new(0x0102, 0x03040506),
3660 ))
3661 .encode();
3662
3663 let expected = &[
3664 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE,
3665 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE,
3666 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE,
3667 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE,
3668 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE,
3669 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE,
3670 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_BYTE,
3671 DISCOVERY_UNIQUE_BRANCH_PREAMBLE_SEPARATOR_BYTE,
3672 0xab, 0x55, 0xaa, 0x57, 0xab, 0x57, 0xae, 0x55, 0xaf, 0x55, 0xae, 0x57, 0xae, 0x57, 0xaf, 0x5f, ];
3689
3690 assert_eq!(encoded, expected);
3691 }
3692}