1use super::{RdmError, SubDeviceId};
2use core::{
3 fmt,
4 net::{Ipv4Addr, Ipv6Addr},
5 result::Result,
6};
7
8#[cfg(not(feature = "alloc"))]
9use core::str::FromStr;
10#[cfg(not(feature = "alloc"))]
11use heapless::{String, Vec};
12
13#[cfg(feature = "alloc")]
14pub fn decode_string_bytes(bytes: &[u8]) -> Result<String, RdmError> {
15 let utf8 = String::from_utf8_lossy(bytes);
16
17 if utf8.contains(char::from(0)) {
18 Ok(utf8.split_once(char::from(0)).unwrap().0.to_string())
19 } else {
20 Ok(utf8.to_string())
21 }
22}
23
24#[cfg(not(feature = "alloc"))]
25pub fn decode_string_bytes<const N: usize>(bytes: &[u8]) -> Result<String<N>, RdmError> {
26 let utf8 = String::<N>::from_utf8(Vec::<u8, N>::from_slice(bytes).unwrap())?;
27
28 if utf8.contains(char::from(0)) {
29 Ok(String::<N>::from_str(utf8.split_once(char::from(0)).unwrap().0).unwrap())
30 } else {
31 Ok(utf8)
32 }
33}
34
35#[non_exhaustive]
36#[derive(Copy, Clone, Debug, PartialEq)]
37pub enum ParameterId {
38 DiscUniqueBranch,
40 DiscMute,
41 DiscUnMute,
42 ProxiedDevices,
43 ProxiedDeviceCount,
44 CommsStatus,
45 QueuedMessage,
46 StatusMessages,
47 StatusIdDescription,
48 ClearStatusId,
49 SubDeviceIdStatusReportThreshold,
50 SupportedParameters,
51 ParameterDescription,
52 DeviceInfo,
53 ProductDetailIdList,
54 DeviceModelDescription,
55 ManufacturerLabel,
56 DeviceLabel,
57 FactoryDefaults,
58 LanguageCapabilities,
59 Language,
60 SoftwareVersionLabel,
61 BootSoftwareVersionId,
62 BootSoftwareVersionLabel,
63 DmxPersonality,
64 DmxPersonalityDescription,
65 DmxStartAddress,
66 SlotInfo,
67 SlotDescription,
68 DefaultSlotValue,
69 SensorDefinition,
70 SensorValue,
71 RecordSensors,
72 DeviceHours,
73 LampHours,
74 LampStrikes,
75 LampState,
76 LampOnMode,
77 DevicePowerCycles,
78 DisplayInvert,
79 DisplayLevel,
80 PanInvert,
81 TiltInvert,
82 PanTiltSwap,
83 RealTimeClock,
84 IdentifyDevice,
85 ResetDevice,
86 PowerState,
87 PerformSelfTest,
88 SelfTestDescription,
89 CapturePreset,
90 PresetPlayback,
91 DmxBlockAddress,
93 DmxFailMode,
94 DmxStartupMode,
95 DimmerInfo,
96 MinimumLevel,
97 MaximumLevel,
98 Curve,
99 CurveDescription,
100 OutputResponseTime,
101 OutputResponseTimeDescription,
102 ModulationFrequency,
103 ModulationFrequencyDescription,
104 BurnIn,
105 LockPin,
106 LockState,
107 LockStateDescription,
108 IdentifyMode,
109 PresetInfo,
110 PresetStatus,
111 PresetMergeMode,
112 PowerOnSelfTest,
113 ListInterfaces,
115 InterfaceLabel,
116 InterfaceHardwareAddressType1,
117 IpV4DhcpMode,
118 IpV4ZeroConfMode,
119 IpV4CurrentAddress,
120 IpV4StaticAddress,
121 InterfaceRenewDhcp,
122 InterfaceReleaseDhcp,
123 InterfaceApplyConfiguration,
124 IpV4DefaultRoute,
125 DnsIpV4NameServer,
126 DnsHostName,
127 DnsDomainName,
128 EndpointList,
130 EndpointListChange,
131 IdentifyEndpoint,
132 EndpointToUniverse,
133 EndpointMode,
134 EndpointLabel,
135 RdmTrafficEnable,
136 DiscoveryState,
137 BackgroundDiscovery,
138 EndpointTiming,
139 EndpointTimingDescription,
140 EndpointResponders,
141 EndpointResponderListChange,
142 BindingControlFields,
143 BackgroundQueuedStatusPolicy,
144 BackgroundQueuedStatusPolicyDescription,
145 ComponentScope,
147 SearchDomain,
148 TcpCommsStatus,
149 BrokerStatus,
150 ManufacturerSpecific(u16),
151 Unsupported(u16),
152}
153
154impl From<u16> for ParameterId {
155 fn from(value: u16) -> Self {
156 match value {
157 0x0001 => Self::DiscUniqueBranch,
159 0x0002 => Self::DiscMute,
160 0x0003 => Self::DiscUnMute,
161 0x0010 => Self::ProxiedDevices,
162 0x0011 => Self::ProxiedDeviceCount,
163 0x0015 => Self::CommsStatus,
164 0x0020 => Self::QueuedMessage,
165 0x0030 => Self::StatusMessages,
166 0x0031 => Self::StatusIdDescription,
167 0x0032 => Self::ClearStatusId,
168 0x0033 => Self::SubDeviceIdStatusReportThreshold,
169 0x0050 => Self::SupportedParameters,
170 0x0051 => Self::ParameterDescription,
171 0x0060 => Self::DeviceInfo,
172 0x0070 => Self::ProductDetailIdList,
173 0x0080 => Self::DeviceModelDescription,
174 0x0081 => Self::ManufacturerLabel,
175 0x0082 => Self::DeviceLabel,
176 0x0090 => Self::FactoryDefaults,
177 0x00a0 => Self::LanguageCapabilities,
178 0x00b0 => Self::Language,
179 0x00c0 => Self::SoftwareVersionLabel,
180 0x00c1 => Self::BootSoftwareVersionId,
181 0x00c2 => Self::BootSoftwareVersionLabel,
182 0x00e0 => Self::DmxPersonality,
183 0x00e1 => Self::DmxPersonalityDescription,
184 0x00f0 => Self::DmxStartAddress,
185 0x0120 => Self::SlotInfo,
186 0x0121 => Self::SlotDescription,
187 0x0122 => Self::DefaultSlotValue,
188 0x0200 => Self::SensorDefinition,
189 0x0201 => Self::SensorValue,
190 0x0202 => Self::RecordSensors,
191 0x0400 => Self::DeviceHours,
192 0x0401 => Self::LampHours,
193 0x0402 => Self::LampStrikes,
194 0x0403 => Self::LampState,
195 0x0404 => Self::LampOnMode,
196 0x0405 => Self::DevicePowerCycles,
197 0x0500 => Self::DisplayInvert,
198 0x0501 => Self::DisplayLevel,
199 0x0600 => Self::PanInvert,
200 0x0601 => Self::TiltInvert,
201 0x0602 => Self::PanTiltSwap,
202 0x0603 => Self::RealTimeClock,
203 0x1000 => Self::IdentifyDevice,
204 0x1001 => Self::ResetDevice,
205 0x1010 => Self::PowerState,
206 0x1020 => Self::PerformSelfTest,
207 0x1021 => Self::SelfTestDescription,
208 0x1030 => Self::CapturePreset,
209 0x1031 => Self::PresetPlayback,
210 0x0140 => Self::DmxBlockAddress,
212 0x0141 => Self::DmxFailMode,
213 0x0142 => Self::DmxStartupMode,
214 0x0340 => Self::DimmerInfo,
215 0x0341 => Self::MinimumLevel,
216 0x0342 => Self::MaximumLevel,
217 0x0343 => Self::Curve,
218 0x0344 => Self::CurveDescription,
219 0x0345 => Self::OutputResponseTime,
220 0x0346 => Self::OutputResponseTimeDescription,
221 0x0347 => Self::ModulationFrequency,
222 0x0348 => Self::ModulationFrequencyDescription,
223 0x0440 => Self::BurnIn,
224 0x0640 => Self::LockPin,
225 0x0641 => Self::LockState,
226 0x0642 => Self::LockStateDescription,
227 0x1040 => Self::IdentifyMode,
228 0x1041 => Self::PresetInfo,
229 0x1042 => Self::PresetStatus,
230 0x1043 => Self::PresetMergeMode,
231 0x1044 => Self::PowerOnSelfTest,
232 0x0700 => Self::ListInterfaces,
234 0x0701 => Self::InterfaceLabel,
235 0x0702 => Self::InterfaceHardwareAddressType1,
236 0x0703 => Self::IpV4DhcpMode,
237 0x0704 => Self::IpV4ZeroConfMode,
238 0x0705 => Self::IpV4CurrentAddress,
239 0x0706 => Self::IpV4StaticAddress,
240 0x0707 => Self::InterfaceRenewDhcp,
241 0x0708 => Self::InterfaceReleaseDhcp,
242 0x0709 => Self::InterfaceApplyConfiguration,
243 0x070a => Self::IpV4DefaultRoute,
244 0x070b => Self::DnsIpV4NameServer,
245 0x070c => Self::DnsHostName,
246 0x070d => Self::DnsDomainName,
247 0x0900 => Self::EndpointList,
249 0x0901 => Self::EndpointListChange,
250 0x0902 => Self::IdentifyEndpoint,
251 0x0903 => Self::EndpointToUniverse,
252 0x0904 => Self::EndpointMode,
253 0x0905 => Self::EndpointLabel,
254 0x0906 => Self::RdmTrafficEnable,
255 0x0907 => Self::DiscoveryState,
256 0x0908 => Self::BackgroundDiscovery,
257 0x0909 => Self::EndpointTiming,
258 0x090a => Self::EndpointTimingDescription,
259 0x090b => Self::EndpointResponders,
260 0x090c => Self::EndpointResponderListChange,
261 0x090d => Self::BindingControlFields,
262 0x090e => Self::BackgroundQueuedStatusPolicy,
263 0x090f => Self::BackgroundQueuedStatusPolicyDescription,
264 0x8000 => Self::ComponentScope,
266 0x8001 => Self::SearchDomain,
267 0x8002 => Self::TcpCommsStatus,
268 0x8003 => Self::BrokerStatus,
269 n if (0x8000..=0xffdf).contains(&n) => Self::ManufacturerSpecific(n),
270 n => Self::Unsupported(n),
271 }
272 }
273}
274
275impl From<ParameterId> for u16 {
276 fn from(value: ParameterId) -> Self {
277 match value {
278 ParameterId::DiscUniqueBranch => 0x0001,
280 ParameterId::DiscMute => 0x0002,
281 ParameterId::DiscUnMute => 0x0003,
282 ParameterId::ProxiedDevices => 0x0010,
283 ParameterId::ProxiedDeviceCount => 0x0011,
284 ParameterId::CommsStatus => 0x0015,
285 ParameterId::QueuedMessage => 0x0020,
286 ParameterId::StatusMessages => 0x0030,
287 ParameterId::StatusIdDescription => 0x0031,
288 ParameterId::ClearStatusId => 0x0032,
289 ParameterId::SubDeviceIdStatusReportThreshold => 0x0033,
290 ParameterId::SupportedParameters => 0x0050,
291 ParameterId::ParameterDescription => 0x0051,
292 ParameterId::DeviceInfo => 0x0060,
293 ParameterId::ProductDetailIdList => 0x0070,
294 ParameterId::DeviceModelDescription => 0x0080,
295 ParameterId::ManufacturerLabel => 0x0081,
296 ParameterId::DeviceLabel => 0x0082,
297 ParameterId::FactoryDefaults => 0x0090,
298 ParameterId::LanguageCapabilities => 0x00a0,
299 ParameterId::Language => 0x00b0,
300 ParameterId::SoftwareVersionLabel => 0x00c0,
301 ParameterId::BootSoftwareVersionId => 0x00c1,
302 ParameterId::BootSoftwareVersionLabel => 0x00c2,
303 ParameterId::DmxPersonality => 0x00e0,
304 ParameterId::DmxPersonalityDescription => 0x00e1,
305 ParameterId::DmxStartAddress => 0x00f0,
306 ParameterId::SlotInfo => 0x0120,
307 ParameterId::SlotDescription => 0x0121,
308 ParameterId::DefaultSlotValue => 0x0122,
309 ParameterId::SensorDefinition => 0x0200,
310 ParameterId::SensorValue => 0x0201,
311 ParameterId::RecordSensors => 0x0202,
312 ParameterId::DeviceHours => 0x0400,
313 ParameterId::LampHours => 0x0401,
314 ParameterId::LampStrikes => 0x0402,
315 ParameterId::LampState => 0x0403,
316 ParameterId::LampOnMode => 0x0404,
317 ParameterId::DevicePowerCycles => 0x0405,
318 ParameterId::DisplayInvert => 0x0500,
319 ParameterId::DisplayLevel => 0x0501,
320 ParameterId::PanInvert => 0x0600,
321 ParameterId::TiltInvert => 0x0601,
322 ParameterId::PanTiltSwap => 0x0602,
323 ParameterId::RealTimeClock => 0x0603,
324 ParameterId::IdentifyDevice => 0x1000,
325 ParameterId::ResetDevice => 0x1001,
326 ParameterId::PowerState => 0x1010,
327 ParameterId::PerformSelfTest => 0x1020,
328 ParameterId::SelfTestDescription => 0x1021,
329 ParameterId::CapturePreset => 0x1030,
330 ParameterId::PresetPlayback => 0x1031,
331 ParameterId::DmxBlockAddress => 0x0140,
333 ParameterId::DmxFailMode => 0x0141,
334 ParameterId::DmxStartupMode => 0x0142,
335 ParameterId::DimmerInfo => 0x0340,
336 ParameterId::MinimumLevel => 0x0341,
337 ParameterId::MaximumLevel => 0x0342,
338 ParameterId::Curve => 0x0343,
339 ParameterId::CurveDescription => 0x0344,
340 ParameterId::OutputResponseTime => 0x0345,
341 ParameterId::OutputResponseTimeDescription => 0x0346,
342 ParameterId::ModulationFrequency => 0x0347,
343 ParameterId::ModulationFrequencyDescription => 0x0348,
344 ParameterId::BurnIn => 0x0440,
345 ParameterId::LockPin => 0x0640,
346 ParameterId::LockState => 0x0641,
347 ParameterId::LockStateDescription => 0x0642,
348 ParameterId::IdentifyMode => 0x1040,
349 ParameterId::PresetInfo => 0x1041,
350 ParameterId::PresetStatus => 0x1042,
351 ParameterId::PresetMergeMode => 0x1043,
352 ParameterId::PowerOnSelfTest => 0x1044,
353 ParameterId::ListInterfaces => 0x0700,
355 ParameterId::InterfaceLabel => 0x0701,
356 ParameterId::InterfaceHardwareAddressType1 => 0x0702,
357 ParameterId::IpV4DhcpMode => 0x0703,
358 ParameterId::IpV4ZeroConfMode => 0x0704,
359 ParameterId::IpV4CurrentAddress => 0x0705,
360 ParameterId::IpV4StaticAddress => 0x0706,
361 ParameterId::InterfaceRenewDhcp => 0x0707,
362 ParameterId::InterfaceReleaseDhcp => 0x0708,
363 ParameterId::InterfaceApplyConfiguration => 0x0709,
364 ParameterId::IpV4DefaultRoute => 0x070a,
365 ParameterId::DnsIpV4NameServer => 0x070b,
366 ParameterId::DnsHostName => 0x070c,
367 ParameterId::DnsDomainName => 0x070d,
368 ParameterId::EndpointList => 0x0900,
370 ParameterId::EndpointListChange => 0x0901,
371 ParameterId::IdentifyEndpoint => 0x0902,
372 ParameterId::EndpointToUniverse => 0x0903,
373 ParameterId::EndpointMode => 0x0904,
374 ParameterId::EndpointLabel => 0x0905,
375 ParameterId::RdmTrafficEnable => 0x0906,
376 ParameterId::DiscoveryState => 0x0907,
377 ParameterId::BackgroundDiscovery => 0x0908,
378 ParameterId::EndpointTiming => 0x0909,
379 ParameterId::EndpointTimingDescription => 0x090a,
380 ParameterId::EndpointResponders => 0x090b,
381 ParameterId::EndpointResponderListChange => 0x090c,
382 ParameterId::BindingControlFields => 0x090d,
383 ParameterId::BackgroundQueuedStatusPolicy => 0x090e,
384 ParameterId::BackgroundQueuedStatusPolicyDescription => 0x090f,
385 ParameterId::ComponentScope => 0x0800,
387 ParameterId::SearchDomain => 0x0801,
388 ParameterId::TcpCommsStatus => 0x0802,
389 ParameterId::BrokerStatus => 0x0803,
390 ParameterId::ManufacturerSpecific(pid) => pid,
391 ParameterId::Unsupported(pid) => pid,
392 }
393 }
394}
395
396#[derive(Copy, Clone, Debug, PartialEq, Eq)]
397pub struct ProtocolVersion {
398 major: u8,
399 minor: u8,
400}
401
402impl ProtocolVersion {
403 pub fn new(major: u8, minor: u8) -> Self {
404 Self { major, minor }
405 }
406}
407
408impl From<ProtocolVersion> for u16 {
409 fn from(value: ProtocolVersion) -> Self {
410 u16::from_be_bytes([value.major, value.minor])
411 }
412}
413
414impl fmt::Display for ProtocolVersion {
415 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416 write!(f, "{}.{}", self.major, self.minor)
417 }
418}
419
420#[derive(Copy, Clone, Debug, PartialEq)]
421pub enum ProductDetail {
422 NotDeclared,
423 Arc,
424 MetalHalide,
425 Incandescent,
426 Led,
427 Fluorescent,
428 ColdCathode,
429 ElectroLuminescent,
430 Laser,
431 FlashTube,
432 ColorScroller,
433 ColorWheel,
434 ColorChange,
435 IrisDouser,
436 DimmingShutter,
437 ProfileShutter,
438 BarnDoorShutter,
439 EffectsDisc,
440 GoboRotator,
441 Video,
442 Slide,
443 Film,
444 OilWheel,
445 LcdGate,
446 FoggerGlycol,
447 FoggerMineralOil,
448 FoggerWater,
449 CO2,
450 LN2,
451 Bubble,
452 FlamePropane,
453 FlameOther,
454 OlefactoryStimulator,
455 Snow,
456 WaterJet,
457 Wind,
458 Confetti,
459 Hazard,
460 PhaseControl,
461 ReversePhaseControl,
462 Sine,
463 Pwm,
464 Dc,
465 HfBallast,
466 HfHvNeonBallast,
467 HfHvEl,
468 MhrBallast,
469 BitangleModulation,
470 FrequencyModulation,
471 HighFrequency12V,
472 RelayMechanical,
473 RelayElectronic,
474 SwitchElectronic,
475 Contactor,
476 MirrorBallRotator,
477 OtherRotator,
478 KabukiDrop,
479 Curtain,
480 LineSet,
481 MotorControl,
482 DamperControl,
483 Splitter,
484 EthernetNode,
485 Merge,
486 DataPatch,
487 WirelessLink,
488 ProtocolConvertor,
489 AnalogDemultiplex,
490 AnalogMultiplex,
491 SwitchPanel,
492 Router,
493 Fader,
494 Mixer,
495 ChangeOverManual,
496 ChangeOverAuto,
497 Test,
498 GfiRcd,
499 Battery,
500 ControllableBreaker,
501 Other,
502 ManufacturerSpecific(u16),
503 Unknown(u16),
504}
505
506impl From<u16> for ProductDetail {
507 fn from(value: u16) -> Self {
508 match value {
509 0x0000 => Self::NotDeclared,
510 0x0001 => Self::Arc,
511 0x0002 => Self::MetalHalide,
512 0x0003 => Self::Incandescent,
513 0x0004 => Self::Led,
514 0x0005 => Self::Fluorescent,
515 0x0006 => Self::ColdCathode,
516 0x0007 => Self::ElectroLuminescent,
517 0x0008 => Self::Laser,
518 0x0009 => Self::FlashTube,
519 0x0100 => Self::ColorScroller,
520 0x0101 => Self::ColorWheel,
521 0x0102 => Self::ColorChange,
522 0x0103 => Self::IrisDouser,
523 0x0104 => Self::DimmingShutter,
524 0x0105 => Self::ProfileShutter,
525 0x0106 => Self::BarnDoorShutter,
526 0x0107 => Self::EffectsDisc,
527 0x0108 => Self::GoboRotator,
528 0x0200 => Self::Video,
529 0x0201 => Self::Slide,
530 0x0202 => Self::Film,
531 0x0203 => Self::OilWheel,
532 0x0204 => Self::LcdGate,
533 0x0300 => Self::FoggerGlycol,
534 0x0301 => Self::FoggerMineralOil,
535 0x0302 => Self::FoggerWater,
536 0x0303 => Self::CO2,
537 0x0304 => Self::LN2,
538 0x0305 => Self::Bubble,
539 0x0306 => Self::FlamePropane,
540 0x0307 => Self::FlameOther,
541 0x0308 => Self::OlefactoryStimulator,
542 0x0309 => Self::Snow,
543 0x030a => Self::WaterJet,
544 0x030b => Self::Wind,
545 0x030c => Self::Confetti,
546 0x030d => Self::Hazard,
547 0x0400 => Self::PhaseControl,
548 0x0401 => Self::ReversePhaseControl,
549 0x0402 => Self::Sine,
550 0x0403 => Self::Pwm,
551 0x0404 => Self::Dc,
552 0x0405 => Self::HfBallast,
553 0x0406 => Self::HfHvNeonBallast,
554 0x0407 => Self::HfHvEl,
555 0x0408 => Self::MhrBallast,
556 0x0409 => Self::BitangleModulation,
557 0x040a => Self::FrequencyModulation,
558 0x040b => Self::HighFrequency12V,
559 0x040c => Self::RelayMechanical,
560 0x040d => Self::RelayElectronic,
561 0x040e => Self::SwitchElectronic,
562 0x040f => Self::Contactor,
563 0x0500 => Self::MirrorBallRotator,
564 0x0501 => Self::OtherRotator,
565 0x0502 => Self::KabukiDrop,
566 0x0503 => Self::Curtain,
567 0x0504 => Self::LineSet,
568 0x0505 => Self::MotorControl,
569 0x0506 => Self::DamperControl,
570 0x0600 => Self::Splitter,
571 0x0601 => Self::EthernetNode,
572 0x0602 => Self::Merge,
573 0x0603 => Self::DataPatch,
574 0x0604 => Self::WirelessLink,
575 0x0701 => Self::ProtocolConvertor,
576 0x0702 => Self::AnalogDemultiplex,
577 0x0703 => Self::AnalogMultiplex,
578 0x0704 => Self::SwitchPanel,
579 0x0800 => Self::Router,
580 0x0801 => Self::Fader,
581 0x0802 => Self::Mixer,
582 0x0900 => Self::ChangeOverManual,
583 0x0901 => Self::ChangeOverAuto,
584 0x0902 => Self::Test,
585 0x0a00 => Self::GfiRcd,
586 0x0a01 => Self::Battery,
587 0x0a02 => Self::ControllableBreaker,
588 0x7fff => Self::Other,
589 value if (0x8000..=0xdfff).contains(&value) => Self::ManufacturerSpecific(value),
590 value => Self::Unknown(value),
591 }
592 }
593}
594
595impl From<ProductDetail> for u16 {
596 fn from(value: ProductDetail) -> Self {
597 match value {
598 ProductDetail::NotDeclared => 0x0000,
599 ProductDetail::Arc => 0x0001,
600 ProductDetail::MetalHalide => 0x0002,
601 ProductDetail::Incandescent => 0x0003,
602 ProductDetail::Led => 0x0004,
603 ProductDetail::Fluorescent => 0x0005,
604 ProductDetail::ColdCathode => 0x0006,
605 ProductDetail::ElectroLuminescent => 0x0007,
606 ProductDetail::Laser => 0x0008,
607 ProductDetail::FlashTube => 0x0009,
608 ProductDetail::ColorScroller => 0x0100,
609 ProductDetail::ColorWheel => 0x0101,
610 ProductDetail::ColorChange => 0x0102,
611 ProductDetail::IrisDouser => 0x0103,
612 ProductDetail::DimmingShutter => 0x0104,
613 ProductDetail::ProfileShutter => 0x0105,
614 ProductDetail::BarnDoorShutter => 0x0106,
615 ProductDetail::EffectsDisc => 0x0107,
616 ProductDetail::GoboRotator => 0x0108,
617 ProductDetail::Video => 0x0200,
618 ProductDetail::Slide => 0x0201,
619 ProductDetail::Film => 0x0202,
620 ProductDetail::OilWheel => 0x0203,
621 ProductDetail::LcdGate => 0x0204,
622 ProductDetail::FoggerGlycol => 0x0300,
623 ProductDetail::FoggerMineralOil => 0x0301,
624 ProductDetail::FoggerWater => 0x0302,
625 ProductDetail::CO2 => 0x0303,
626 ProductDetail::LN2 => 0x0304,
627 ProductDetail::Bubble => 0x0305,
628 ProductDetail::FlamePropane => 0x0306,
629 ProductDetail::FlameOther => 0x0307,
630 ProductDetail::OlefactoryStimulator => 0x0308,
631 ProductDetail::Snow => 0x0309,
632 ProductDetail::WaterJet => 0x030a,
633 ProductDetail::Wind => 0x030b,
634 ProductDetail::Confetti => 0x030c,
635 ProductDetail::Hazard => 0x030d,
636 ProductDetail::PhaseControl => 0x0400,
637 ProductDetail::ReversePhaseControl => 0x0401,
638 ProductDetail::Sine => 0x0402,
639 ProductDetail::Pwm => 0x0403,
640 ProductDetail::Dc => 0x0404,
641 ProductDetail::HfBallast => 0x0405,
642 ProductDetail::HfHvNeonBallast => 0x0406,
643 ProductDetail::HfHvEl => 0x0407,
644 ProductDetail::MhrBallast => 0x0408,
645 ProductDetail::BitangleModulation => 0x0409,
646 ProductDetail::FrequencyModulation => 0x040a,
647 ProductDetail::HighFrequency12V => 0x040b,
648 ProductDetail::RelayMechanical => 0x040c,
649 ProductDetail::RelayElectronic => 0x040d,
650 ProductDetail::SwitchElectronic => 0x040e,
651 ProductDetail::Contactor => 0x040f,
652 ProductDetail::MirrorBallRotator => 0x0500,
653 ProductDetail::OtherRotator => 0x0501,
654 ProductDetail::KabukiDrop => 0x0502,
655 ProductDetail::Curtain => 0x0503,
656 ProductDetail::LineSet => 0x0504,
657 ProductDetail::MotorControl => 0x0505,
658 ProductDetail::DamperControl => 0x0506,
659 ProductDetail::Splitter => 0x0600,
660 ProductDetail::EthernetNode => 0x0601,
661 ProductDetail::Merge => 0x0602,
662 ProductDetail::DataPatch => 0x0603,
663 ProductDetail::WirelessLink => 0x0604,
664 ProductDetail::ProtocolConvertor => 0x0701,
665 ProductDetail::AnalogDemultiplex => 0x0702,
666 ProductDetail::AnalogMultiplex => 0x0703,
667 ProductDetail::SwitchPanel => 0x0704,
668 ProductDetail::Router => 0x0800,
669 ProductDetail::Fader => 0x0801,
670 ProductDetail::Mixer => 0x0802,
671 ProductDetail::ChangeOverManual => 0x0900,
672 ProductDetail::ChangeOverAuto => 0x0901,
673 ProductDetail::Test => 0x0902,
674 ProductDetail::GfiRcd => 0x0a00,
675 ProductDetail::Battery => 0x0a01,
676 ProductDetail::ControllableBreaker => 0x0a02,
677 ProductDetail::Other => 0x7fff,
678 ProductDetail::ManufacturerSpecific(value) => value,
679 ProductDetail::Unknown(value) => value,
680 }
681 }
682}
683
684#[derive(Copy, Clone, Debug, PartialEq)]
685pub enum ImplementedCommandClass {
686 Get = 0x01,
687 Set = 0x02,
688 GetSet = 0x03,
689}
690
691impl TryFrom<u8> for ImplementedCommandClass {
692 type Error = RdmError;
693
694 fn try_from(value: u8) -> Result<Self, Self::Error> {
695 match value {
696 0x01 => Ok(Self::Get),
697 0x02 => Ok(Self::Set),
698 0x03 => Ok(Self::GetSet),
699 _ => Err(RdmError::InvalidCommandClassImplementation(value)),
700 }
701 }
702}
703
704#[derive(Copy, Clone, Debug, PartialEq)]
705pub enum ParameterDataType {
706 NotDefined,
707 BitField,
708 Ascii,
709 UnsignedByte,
710 SignedByte,
711 UnsignedWord,
712 SignedWord,
713 UnsignedDWord,
714 SignedDWord,
715 ManufacturerSpecific(u8),
716}
717
718impl TryFrom<u8> for ParameterDataType {
719 type Error = RdmError;
720
721 fn try_from(value: u8) -> Result<Self, RdmError> {
722 match value {
723 0x00 => Ok(Self::NotDefined),
724 0x01 => Ok(Self::BitField),
725 0x02 => Ok(Self::Ascii),
726 0x03 => Ok(Self::UnsignedByte),
727 0x04 => Ok(Self::SignedByte),
728 0x05 => Ok(Self::UnsignedWord),
729 0x06 => Ok(Self::SignedWord),
730 0x07 => Ok(Self::UnsignedDWord),
731 0x08 => Ok(Self::SignedDWord),
732 n if (0x80..=0xdf).contains(&n) => Ok(Self::ManufacturerSpecific(n)),
733 _ => Err(RdmError::InvalidParameterDataType(value)),
734 }
735 }
736}
737
738impl From<ParameterDataType> for u8 {
739 fn from(value: ParameterDataType) -> Self {
740 match value {
741 ParameterDataType::NotDefined => 0x00,
742 ParameterDataType::BitField => 0x01,
743 ParameterDataType::Ascii => 0x02,
744 ParameterDataType::UnsignedByte => 0x03,
745 ParameterDataType::SignedByte => 0x04,
746 ParameterDataType::UnsignedWord => 0x05,
747 ParameterDataType::SignedWord => 0x06,
748 ParameterDataType::UnsignedDWord => 0x07,
749 ParameterDataType::SignedDWord => 0x08,
750 ParameterDataType::ManufacturerSpecific(n) => n,
751 }
752 }
753}
754
755pub enum ConvertedParameterValue {
756 BitField(u8),
757 Ascii(
758 #[cfg(feature = "alloc")] String,
759 #[cfg(not(feature = "alloc"))] String<4>,
760 ),
761 UnsignedByte(u8),
762 SignedByte(i8),
763 UnsignedWord(u16),
764 SignedWord(i16),
765 UnsignedDWord(u32),
766 SignedDWord(i32),
767 Raw([u8; 4]),
768}
769
770#[derive(Clone, Debug, PartialEq)]
771pub struct ParameterDescription {
772 pub parameter_id: u16,
773 pub parameter_data_length: u8,
774 pub data_type: ParameterDataType,
775 pub command_class: ImplementedCommandClass,
776 pub unit_type: SensorUnit,
777 pub prefix: SensorUnitPrefix,
778 pub raw_minimum_valid_value: [u8; 4],
779 pub raw_maximum_valid_value: [u8; 4],
780 pub raw_default_value: [u8; 4],
781 #[cfg(feature = "alloc")]
782 pub description: String,
783 #[cfg(not(feature = "alloc"))]
784 pub description: String<32>,
785}
786
787impl ParameterDescription {
788 fn convert_parameter_value(
789 parameter_data_type: ParameterDataType,
790 value: [u8; 4],
791 ) -> Result<ConvertedParameterValue, RdmError> {
792 match parameter_data_type {
793 ParameterDataType::BitField => Ok(ConvertedParameterValue::BitField(value[3])),
794 ParameterDataType::Ascii => {
795 Ok(ConvertedParameterValue::Ascii(decode_string_bytes(&value)?))
796 }
797 ParameterDataType::UnsignedByte => Ok(ConvertedParameterValue::UnsignedByte(value[3])),
798 ParameterDataType::SignedByte => {
799 Ok(ConvertedParameterValue::SignedByte(value[3] as i8))
800 }
801 ParameterDataType::UnsignedWord => {
802 Ok(ConvertedParameterValue::UnsignedWord(u16::from_be_bytes([
803 value[2], value[3],
804 ])))
805 }
806 ParameterDataType::SignedWord => {
807 Ok(ConvertedParameterValue::SignedWord(i16::from_be_bytes([
808 value[2], value[3],
809 ])))
810 }
811 ParameterDataType::UnsignedDWord => Ok(ConvertedParameterValue::UnsignedDWord(
812 u32::from_be_bytes(value),
813 )),
814 ParameterDataType::SignedDWord => Ok(ConvertedParameterValue::SignedDWord(
815 i32::from_be_bytes(value),
816 )),
817 ParameterDataType::NotDefined | ParameterDataType::ManufacturerSpecific(..) => {
818 Ok(ConvertedParameterValue::Raw(value))
819 }
820 }
821 }
822
823 pub fn minimum_valid_value(&self) -> Result<ConvertedParameterValue, RdmError> {
824 Self::convert_parameter_value(self.data_type, self.raw_minimum_valid_value)
825 }
826 pub fn maximum_valid_value(&self) -> Result<ConvertedParameterValue, RdmError> {
827 Self::convert_parameter_value(self.data_type, self.raw_maximum_valid_value)
828 }
829 pub fn default_value(&self) -> Result<ConvertedParameterValue, RdmError> {
830 Self::convert_parameter_value(self.data_type, self.raw_default_value)
831 }
832}
833
834#[derive(Copy, Clone, Debug, PartialEq)]
835pub enum StatusType {
836 None = 0x00,
837 GetLastMessage = 0x01,
838 Advisory = 0x02,
839 Warning = 0x03,
840 Error = 0x04,
841 AdvisoryCleared = 0x12,
842 WarningCleared = 0x13,
843 ErrorCleared = 0x14,
844}
845
846impl TryFrom<u8> for StatusType {
847 type Error = RdmError;
848
849 fn try_from(value: u8) -> Result<Self, RdmError> {
850 match value {
851 0x00 => Ok(Self::None),
852 0x01 => Ok(Self::GetLastMessage),
853 0x02 => Ok(Self::Advisory),
854 0x03 => Ok(Self::Warning),
855 0x04 => Ok(Self::Error),
856 0x12 => Ok(Self::AdvisoryCleared),
857 0x13 => Ok(Self::WarningCleared),
858 0x14 => Ok(Self::ErrorCleared),
859 _ => Err(RdmError::InvalidStatusType(value)),
860 }
861 }
862}
863
864#[derive(Copy, Clone, Debug, PartialEq)]
866pub enum ProductCategory {
867 NotDeclared,
868 Fixture,
869 FixtureFixed,
870 FixtureMovingYoke,
871 FixtureMovingMirror,
872 FixtureOther,
873 FixtureAccessory,
874 FixtureAccessoryColor,
875 FixtureAccessoryYoke,
876 FixtureAccessoryMirror,
877 FixtureAccessoryEffect,
878 FixtureAccessoryBeam,
879 AccessoryOther,
880 Projector,
881 ProjectorFixed,
882 ProjectorMovingYoke,
883 ProjectorMovingMirror,
884 ProjectorOther,
885 Atmospheric,
886 AtmosphericEffect,
887 AtmosphericPyro,
888 AtmosphericOther,
889 Dimmer,
890 DimmerACIncandescent,
891 DimmerACFlourescent,
892 DimmerACColdCathode,
893 DimmerACNonDimModule,
894 DimmerACLowVoltage,
895 DimmerControllableAC,
896 DimmerDCLevelOutput,
897 DimmerDCPWMOutput,
898 DimmerSpecialisedLED,
899 DimmerOther,
900 Power,
901 PowerControl,
902 PowerSource,
903 PowerOther,
904 Scenic,
905 ScenicDrive,
906 ScenicOther,
907 Data,
908 DataDistribution,
909 DataConversion,
910 DataOther,
911 AV,
912 AVAudio,
913 AVVideo,
914 AVOther,
915 Monitor,
916 MonitorACLinePower,
917 MonitorDCPower,
918 MonitorEnvironmental,
919 MonitorOther,
920 Control,
921 ControlController,
922 ControlBackupDevice,
923 ControlOther,
924 Test,
925 TestEquipment,
926 TestEquipmentOther,
927 Other,
928 ManufacturerSpecific(u16),
929 Unknown(u16),
930}
931
932impl From<u16> for ProductCategory {
933 fn from(value: u16) -> Self {
934 match value {
935 0x0000 => Self::NotDeclared,
936 0x0100 => Self::Fixture,
937 0x0101 => Self::FixtureFixed,
938 0x0102 => Self::FixtureMovingYoke,
939 0x0103 => Self::FixtureMovingMirror,
940 0x01ff => Self::FixtureOther,
941 0x0200 => Self::FixtureAccessory,
942 0x0201 => Self::FixtureAccessoryColor,
943 0x0202 => Self::FixtureAccessoryYoke,
944 0x0203 => Self::FixtureAccessoryMirror,
945 0x0204 => Self::FixtureAccessoryEffect,
946 0x0205 => Self::FixtureAccessoryBeam,
947 0x02ff => Self::AccessoryOther,
948 0x0300 => Self::Projector,
949 0x0301 => Self::ProjectorFixed,
950 0x0302 => Self::ProjectorMovingYoke,
951 0x0303 => Self::ProjectorMovingMirror,
952 0x03ff => Self::ProjectorOther,
953 0x0400 => Self::Atmospheric,
954 0x0401 => Self::AtmosphericEffect,
955 0x0402 => Self::AtmosphericPyro,
956 0x04ff => Self::AtmosphericOther,
957 0x0500 => Self::Dimmer,
958 0x0501 => Self::DimmerACIncandescent,
959 0x0502 => Self::DimmerACFlourescent,
960 0x0503 => Self::DimmerACColdCathode,
961 0x0504 => Self::DimmerACNonDimModule,
962 0x0505 => Self::DimmerACLowVoltage,
963 0x0506 => Self::DimmerControllableAC,
964 0x0507 => Self::DimmerDCLevelOutput,
965 0x0508 => Self::DimmerDCPWMOutput,
966 0x0509 => Self::DimmerSpecialisedLED,
967 0x05ff => Self::DimmerOther,
968 0x0600 => Self::Power,
969 0x0601 => Self::PowerControl,
970 0x0602 => Self::PowerSource,
971 0x06ff => Self::PowerOther,
972 0x0700 => Self::Scenic,
973 0x0701 => Self::ScenicDrive,
974 0x07ff => Self::ScenicOther,
975 0x0800 => Self::Data,
976 0x0801 => Self::DataDistribution,
977 0x0802 => Self::DataConversion,
978 0x08ff => Self::DataOther,
979 0x0900 => Self::AV,
980 0x0901 => Self::AVAudio,
981 0x0902 => Self::AVVideo,
982 0x09ff => Self::AVOther,
983 0x0a00 => Self::Monitor,
984 0x0a01 => Self::MonitorACLinePower,
985 0x0a02 => Self::MonitorDCPower,
986 0x0a03 => Self::MonitorEnvironmental,
987 0x0aff => Self::MonitorOther,
988 0x7000 => Self::Control,
989 0x7001 => Self::ControlController,
990 0x7002 => Self::ControlBackupDevice,
991 0x70ff => Self::ControlOther,
992 0x7100 => Self::Test,
993 0x7101 => Self::TestEquipment,
994 0x71ff => Self::TestEquipmentOther,
995 0x7fff => Self::Other,
996 value if (0x8000..=0xdfff).contains(&value) => Self::ManufacturerSpecific(value),
997 value => Self::Unknown(value),
998 }
999 }
1000}
1001
1002impl From<ProductCategory> for u16 {
1003 fn from(value: ProductCategory) -> Self {
1004 match value {
1005 ProductCategory::NotDeclared => 0x0000,
1006 ProductCategory::Fixture => 0x0100,
1007 ProductCategory::FixtureFixed => 0x0101,
1008 ProductCategory::FixtureMovingYoke => 0x0102,
1009 ProductCategory::FixtureMovingMirror => 0x0103,
1010 ProductCategory::FixtureOther => 0x01ff,
1011 ProductCategory::FixtureAccessory => 0x0200,
1012 ProductCategory::FixtureAccessoryColor => 0x0201,
1013 ProductCategory::FixtureAccessoryYoke => 0x0202,
1014 ProductCategory::FixtureAccessoryMirror => 0x0203,
1015 ProductCategory::FixtureAccessoryEffect => 0x0204,
1016 ProductCategory::FixtureAccessoryBeam => 0x0205,
1017 ProductCategory::AccessoryOther => 0x02ff,
1018 ProductCategory::Projector => 0x0300,
1019 ProductCategory::ProjectorFixed => 0x0301,
1020 ProductCategory::ProjectorMovingYoke => 0x0302,
1021 ProductCategory::ProjectorMovingMirror => 0x0303,
1022 ProductCategory::ProjectorOther => 0x03ff,
1023 ProductCategory::Atmospheric => 0x0400,
1024 ProductCategory::AtmosphericEffect => 0x0401,
1025 ProductCategory::AtmosphericPyro => 0x0402,
1026 ProductCategory::AtmosphericOther => 0x04ff,
1027 ProductCategory::Dimmer => 0x0500,
1028 ProductCategory::DimmerACIncandescent => 0x0501,
1029 ProductCategory::DimmerACFlourescent => 0x0502,
1030 ProductCategory::DimmerACColdCathode => 0x0503,
1031 ProductCategory::DimmerACNonDimModule => 0x0504,
1032 ProductCategory::DimmerACLowVoltage => 0x0505,
1033 ProductCategory::DimmerControllableAC => 0x0506,
1034 ProductCategory::DimmerDCLevelOutput => 0x0507,
1035 ProductCategory::DimmerDCPWMOutput => 0x0508,
1036 ProductCategory::DimmerSpecialisedLED => 0x0509,
1037 ProductCategory::DimmerOther => 0x05ff,
1038 ProductCategory::Power => 0x0600,
1039 ProductCategory::PowerControl => 0x0601,
1040 ProductCategory::PowerSource => 0x0602,
1041 ProductCategory::PowerOther => 0x06ff,
1042 ProductCategory::Scenic => 0x0700,
1043 ProductCategory::ScenicDrive => 0x0701,
1044 ProductCategory::ScenicOther => 0x07ff,
1045 ProductCategory::Data => 0x0800,
1046 ProductCategory::DataDistribution => 0x0801,
1047 ProductCategory::DataConversion => 0x0802,
1048 ProductCategory::DataOther => 0x08ff,
1049 ProductCategory::AV => 0x0900,
1050 ProductCategory::AVAudio => 0x0901,
1051 ProductCategory::AVVideo => 0x0902,
1052 ProductCategory::AVOther => 0x09ff,
1053 ProductCategory::Monitor => 0x0a00,
1054 ProductCategory::MonitorACLinePower => 0x0a01,
1055 ProductCategory::MonitorDCPower => 0x0a02,
1056 ProductCategory::MonitorEnvironmental => 0x0a03,
1057 ProductCategory::MonitorOther => 0x0aff,
1058 ProductCategory::Control => 0x7000,
1059 ProductCategory::ControlController => 0x7001,
1060 ProductCategory::ControlBackupDevice => 0x7002,
1061 ProductCategory::ControlOther => 0x70ff,
1062 ProductCategory::Test => 0x7100,
1063 ProductCategory::TestEquipment => 0x7101,
1064 ProductCategory::TestEquipmentOther => 0x71ff,
1065 ProductCategory::Other => 0x7fff,
1066 ProductCategory::ManufacturerSpecific(value) => value,
1067 ProductCategory::Unknown(value) => value,
1068 }
1069 }
1070}
1071
1072#[derive(Copy, Clone, Debug, PartialEq)]
1073pub enum LampState {
1074 LampOff,
1075 LampOn,
1076 LampStrike,
1077 LampStandby,
1078 LampNotPresent,
1079 LampError,
1080 ManufacturerSpecific(u8),
1081}
1082
1083impl TryFrom<u8> for LampState {
1084 type Error = RdmError;
1085
1086 fn try_from(value: u8) -> Result<Self, Self::Error> {
1087 match value {
1088 0x00 => Ok(Self::LampOff),
1089 0x01 => Ok(Self::LampOn),
1090 0x02 => Ok(Self::LampStrike),
1091 0x03 => Ok(Self::LampStandby),
1092 0x04 => Ok(Self::LampNotPresent),
1093 0x05 => Ok(Self::LampError),
1094 n if (0x80..=0xdf).contains(&n) => Ok(Self::ManufacturerSpecific(n)),
1095 _ => Err(RdmError::InvalidLampState(value)),
1096 }
1097 }
1098}
1099
1100impl From<LampState> for u8 {
1101 fn from(value: LampState) -> u8 {
1102 match value {
1103 LampState::LampOff => 0x00,
1104 LampState::LampOn => 0x01,
1105 LampState::LampStrike => 0x02,
1106 LampState::LampStandby => 0x03,
1107 LampState::LampNotPresent => 0x04,
1108 LampState::LampError => 0x05,
1109 LampState::ManufacturerSpecific(n) => n,
1110 }
1111 }
1112}
1113
1114#[derive(Copy, Clone, Debug, PartialEq)]
1115pub enum LampOnMode {
1116 OffMode,
1117 DmxMode,
1118 OnMode,
1119 AfterCal,
1120 ManufacturerSpecific(u8),
1121}
1122
1123impl TryFrom<u8> for LampOnMode {
1124 type Error = RdmError;
1125
1126 fn try_from(value: u8) -> Result<Self, Self::Error> {
1127 match value {
1128 0x00 => Ok(Self::OffMode),
1129 0x01 => Ok(Self::DmxMode),
1130 0x02 => Ok(Self::OnMode),
1131 0x03 => Ok(Self::AfterCal),
1132 n if (0x80..=0xdf).contains(&n) => Ok(Self::ManufacturerSpecific(n)),
1133 _ => Err(RdmError::InvalidLampOnMode(value)),
1134 }
1135 }
1136}
1137
1138impl From<LampOnMode> for u8 {
1139 fn from(value: LampOnMode) -> u8 {
1140 match value {
1141 LampOnMode::OffMode => 0x00,
1142 LampOnMode::DmxMode => 0x01,
1143 LampOnMode::OnMode => 0x02,
1144 LampOnMode::AfterCal => 0x03,
1145 LampOnMode::ManufacturerSpecific(n) => n,
1146 }
1147 }
1148}
1149
1150#[derive(Copy, Clone, Debug, PartialEq)]
1151pub enum PowerState {
1152 FullOff = 0x00,
1153 Shutdown = 0x01,
1154 Standby = 0x02,
1155 Normal = 0xff,
1156}
1157
1158impl TryFrom<u8> for PowerState {
1159 type Error = RdmError;
1160
1161 fn try_from(value: u8) -> Result<Self, Self::Error> {
1162 match value {
1163 0x00 => Ok(Self::FullOff),
1164 0x01 => Ok(Self::Shutdown),
1165 0x02 => Ok(Self::Standby),
1166 0x03 => Ok(Self::Normal),
1167 _ => Err(RdmError::InvalidPowerState(value)),
1168 }
1169 }
1170}
1171
1172#[derive(Copy, Clone, Debug, PartialEq)]
1173pub enum OnOffStates {
1174 Off = 0x00,
1175 On = 0x01,
1176}
1177
1178impl TryFrom<u8> for OnOffStates {
1179 type Error = RdmError;
1180
1181 fn try_from(value: u8) -> Result<Self, Self::Error> {
1182 match value {
1183 0x00 => Ok(Self::Off),
1184 0x01 => Ok(Self::On),
1185 _ => Err(RdmError::InvalidOnOffStates(value)),
1186 }
1187 }
1188}
1189
1190#[derive(Copy, Clone, Debug, PartialEq)]
1191pub enum DisplayInvertMode {
1192 Off = 0x00,
1193 On = 0x01,
1194 Auto = 0x02,
1195}
1196
1197impl TryFrom<u8> for DisplayInvertMode {
1198 type Error = RdmError;
1199
1200 fn try_from(value: u8) -> Result<Self, Self::Error> {
1201 match value {
1202 0x00 => Ok(Self::Off),
1203 0x01 => Ok(Self::On),
1204 0x02 => Ok(Self::Auto),
1205 _ => Err(RdmError::InvalidDisplayInvertMode(value)),
1206 }
1207 }
1208}
1209
1210#[derive(Copy, Clone, Debug, PartialEq)]
1211pub enum ResetDeviceMode {
1212 Warm = 0x01,
1213 Cold = 0xff,
1214}
1215
1216impl TryFrom<u8> for ResetDeviceMode {
1217 type Error = RdmError;
1218
1219 fn try_from(value: u8) -> Result<Self, Self::Error> {
1220 match value {
1221 0x01 => Ok(Self::Warm),
1222 0xff => Ok(Self::Cold),
1223 _ => Err(RdmError::InvalidResetDeviceMode(value)),
1224 }
1225 }
1226}
1227
1228#[derive(Copy, Clone, Debug, PartialEq)]
1229pub enum SelfTest {
1230 Off,
1231 All,
1232 ManufacturerId(u8),
1233}
1234
1235impl From<u8> for SelfTest {
1236 fn from(value: u8) -> Self {
1237 match value {
1238 0x00 => Self::Off,
1239 0xff => Self::All,
1240 value => Self::ManufacturerId(value),
1241 }
1242 }
1243}
1244
1245impl From<SelfTest> for u8 {
1246 fn from(value: SelfTest) -> u8 {
1247 match value {
1248 SelfTest::Off => 0x00,
1249 SelfTest::All => 0xff,
1250 SelfTest::ManufacturerId(value) => value,
1251 }
1252 }
1253}
1254
1255#[derive(Copy, Clone, Debug, PartialEq)]
1256pub enum PresetPlaybackMode {
1257 Off,
1258 All,
1259 Scene(u16),
1260}
1261
1262impl From<u16> for PresetPlaybackMode {
1263 fn from(value: u16) -> Self {
1264 match value {
1265 0x0000 => Self::Off,
1266 0xffff => Self::All,
1267 value => Self::Scene(value),
1268 }
1269 }
1270}
1271
1272impl From<PresetPlaybackMode> for u16 {
1273 fn from(value: PresetPlaybackMode) -> u16 {
1274 match value {
1275 PresetPlaybackMode::Off => 0x0000,
1276 PresetPlaybackMode::All => 0xffff,
1277 PresetPlaybackMode::Scene(value) => value,
1278 }
1279 }
1280}
1281
1282#[derive(Copy, Clone, Debug, PartialEq)]
1283pub struct FadeTimes {
1284 pub up_fade_time: u16,
1285 pub down_fade_time: u16,
1286 pub wait_time: u16,
1287}
1288
1289#[non_exhaustive]
1290#[derive(Copy, Clone, Debug, PartialEq)]
1291pub enum StatusMessageIdDefinition {
1292 CalibrationFailed = 0x0001,
1293 SensorNotFound = 0x0002,
1294 SensorAlwaysOn = 0x0003,
1295 LampDoused = 0x0011,
1296 LampStrike = 0x0012,
1297 OverTemperature = 0x0021,
1298 UnderTemperature = 0x0022,
1299 SensorOutOfRange = 0x0023,
1300 OverVoltagePhase = 0x0031,
1301 UnderVoltagePhase = 0x0032,
1302 OverCurrent = 0x0033,
1303 UnderCurrent = 0x0034,
1304 Phase = 0x0035,
1305 PhaseError = 0x0036,
1306 Amps = 0x0037,
1307 Volts = 0x0038,
1308 DimSlotOccupied = 0x0041,
1309 BreakerTrip = 0x0042,
1310 Watts = 0x0043,
1311 DimmerFailure = 0x0044,
1312 DimmerPanic = 0x0045,
1313 Ready = 0x0050,
1314 NotReady = 0x0051,
1315 LowFluid = 0x0052,
1316}
1317
1318#[derive(Clone, Debug, PartialEq)]
1319pub struct StatusMessage {
1320 pub sub_device_id: SubDeviceId,
1321 pub status_type: StatusType,
1322 pub status_message_id: u16,
1323 pub data_value1: u16,
1324 pub data_value2: u16,
1325 #[cfg(feature = "alloc")]
1326 pub description: Option<String>,
1327 #[cfg(not(feature = "alloc"))]
1328 pub description: Option<String<32>>,
1329}
1330
1331impl StatusMessage {
1332 pub fn new(
1333 sub_device_id: SubDeviceId,
1334 status_type: StatusType,
1335 status_message_id: u16,
1336 data_value1: u16,
1337 data_value2: u16,
1338 ) -> Self {
1339 let description = if status_message_id < 0x8000 {
1340 match status_message_id {
1341 0x0001 => Some(
1342 #[cfg(feature = "alloc")]
1343 format!("{} failed calibration", SlotIdDefinition::from(data_value1)),
1344 #[cfg(not(feature = "alloc"))]
1345 String::<32>::from_str(
1346 format_args!("{} failed calibration", SlotIdDefinition::from(data_value1))
1347 .as_str()
1348 .unwrap(),
1349 )
1350 .unwrap(),
1351 ),
1352 0x0002 => Some(
1353 #[cfg(feature = "alloc")]
1354 format!("{} sensor not found", SlotIdDefinition::from(data_value1)),
1355 #[cfg(not(feature = "alloc"))]
1356 String::<32>::from_str(
1357 format_args!("{} sensor not found", SlotIdDefinition::from(data_value1))
1358 .as_str()
1359 .unwrap(),
1360 )
1361 .unwrap(),
1362 ),
1363 0x0003 => Some(
1364 #[cfg(feature = "alloc")]
1365 format!("{} sensor always on", SlotIdDefinition::from(data_value1)),
1366 #[cfg(not(feature = "alloc"))]
1367 String::<32>::from_str(
1368 format_args!("{} sensor always on", SlotIdDefinition::from(data_value1))
1369 .as_str()
1370 .unwrap(),
1371 )
1372 .unwrap(),
1373 ),
1374 0x0011 => Some(
1375 #[cfg(feature = "alloc")]
1376 "Lamp Doused".to_string(),
1377 #[cfg(not(feature = "alloc"))]
1378 String::<32>::from_str("Lamp Doused").unwrap(),
1379 ),
1380 0x0012 => Some(
1381 #[cfg(feature = "alloc")]
1382 "Lamp Strike".to_string(),
1383 #[cfg(not(feature = "alloc"))]
1384 String::<32>::from_str("Lamp Strike").unwrap(),
1385 ),
1386 0x0021 => Some(
1387 #[cfg(feature = "alloc")]
1388 format!(
1389 "Sensor {} over temp at {} degrees C",
1390 data_value1, data_value2
1391 ),
1392 #[cfg(not(feature = "alloc"))]
1393 String::<32>::from_str(
1394 format_args!(
1395 "Sensor {} over temp at {} degrees C",
1396 data_value1, data_value2
1397 )
1398 .as_str()
1399 .unwrap(),
1400 )
1401 .unwrap(),
1402 ),
1403 0x0022 => Some(
1404 #[cfg(feature = "alloc")]
1405 format!(
1406 "Sensor {} under temp at {} degrees C",
1407 data_value1, data_value2
1408 ),
1409 #[cfg(not(feature = "alloc"))]
1410 String::<32>::from_str(
1411 format_args!(
1412 "Sensor {} under temp at {} degrees C",
1413 data_value1, data_value2
1414 )
1415 .as_str()
1416 .unwrap(),
1417 )
1418 .unwrap(),
1419 ),
1420 0x0023 => Some(
1421 #[cfg(feature = "alloc")]
1422 format!("Sensor {} out of range", data_value1),
1423 #[cfg(not(feature = "alloc"))]
1424 String::<32>::from_str(
1425 format_args!("Sensor {} out of range", data_value1)
1426 .as_str()
1427 .unwrap(),
1428 )
1429 .unwrap(),
1430 ),
1431 0x0031 => Some(
1432 #[cfg(feature = "alloc")]
1433 format!("Phase {} over voltage at {} V", data_value1, data_value2),
1434 #[cfg(not(feature = "alloc"))]
1435 String::<32>::from_str(
1436 format_args!("Phase {} over voltage at {} V", data_value1, data_value2)
1437 .as_str()
1438 .unwrap(),
1439 )
1440 .unwrap(),
1441 ),
1442 0x0032 => Some(
1443 #[cfg(feature = "alloc")]
1444 format!("Phase {} under voltage at {} V", data_value1, data_value2),
1445 #[cfg(not(feature = "alloc"))]
1446 String::<32>::from_str(
1447 format_args!("Phase {} under voltage at {} V", data_value1, data_value2)
1448 .as_str()
1449 .unwrap(),
1450 )
1451 .unwrap(),
1452 ),
1453 0x0033 => Some(
1454 #[cfg(feature = "alloc")]
1455 format!("Phase {} over current at {} A", data_value1, data_value2),
1456 #[cfg(not(feature = "alloc"))]
1457 String::<32>::from_str(
1458 format_args!("Phase {} over current at {} A", data_value1, data_value2)
1459 .as_str()
1460 .unwrap(),
1461 )
1462 .unwrap(),
1463 ),
1464 0x0034 => Some(
1465 #[cfg(feature = "alloc")]
1466 format!("Phase {} under current at {} A", data_value1, data_value2),
1467 #[cfg(not(feature = "alloc"))]
1468 String::<32>::from_str(
1469 format_args!("Phase {} under current at {} A", data_value1, data_value2)
1470 .as_str()
1471 .unwrap(),
1472 )
1473 .unwrap(),
1474 ),
1475 0x0035 => Some(
1476 #[cfg(feature = "alloc")]
1477 format!("Phase {} is at {} degrees", data_value1, data_value2),
1478 #[cfg(not(feature = "alloc"))]
1479 String::<32>::from_str(
1480 format_args!("Phase {} is at {} degrees", data_value1, data_value2)
1481 .as_str()
1482 .unwrap(),
1483 )
1484 .unwrap(),
1485 ),
1486 0x0036 => Some(
1487 #[cfg(feature = "alloc")]
1488 format!("Phase {} Error", data_value1),
1489 #[cfg(not(feature = "alloc"))]
1490 String::<32>::from_str(
1491 format_args!("Phase {} Error", data_value1)
1492 .as_str()
1493 .unwrap(),
1494 )
1495 .unwrap(),
1496 ),
1497 0x0037 => Some(
1498 #[cfg(feature = "alloc")]
1499 format!("{} Amps", data_value1),
1500 #[cfg(not(feature = "alloc"))]
1501 String::<32>::from_str(format_args!("{} Amps", data_value1).as_str().unwrap())
1502 .unwrap(),
1503 ),
1504 0x0038 => Some(
1505 #[cfg(feature = "alloc")]
1506 format!("{} Volts", data_value1),
1507 #[cfg(not(feature = "alloc"))]
1508 String::<32>::from_str(format_args!("{} Volts", data_value1).as_str().unwrap())
1509 .unwrap(),
1510 ),
1511 0x0041 => Some(
1512 #[cfg(feature = "alloc")]
1513 "No Dimmer".to_string(),
1514 #[cfg(not(feature = "alloc"))]
1515 String::<32>::from_str("No Dimmer").unwrap(),
1516 ),
1517 0x0042 => Some(
1518 #[cfg(feature = "alloc")]
1519 "Tripped Breaker".to_string(),
1520 #[cfg(not(feature = "alloc"))]
1521 String::<32>::from_str("Tripped Breaker").unwrap(),
1522 ),
1523 0x0043 => Some(
1524 #[cfg(feature = "alloc")]
1525 format!("{} Watts", data_value1),
1526 #[cfg(not(feature = "alloc"))]
1527 String::<32>::from_str(format_args!("{} Watts", data_value1).as_str().unwrap())
1528 .unwrap(),
1529 ),
1530 0x0044 => Some(
1531 #[cfg(feature = "alloc")]
1532 "Dimmer Failure".to_string(),
1533 #[cfg(not(feature = "alloc"))]
1534 String::<32>::from_str("Dimmer Failure").unwrap(),
1535 ),
1536 0x0045 => Some(
1537 #[cfg(feature = "alloc")]
1538 "Panic Mode".to_string(),
1539 #[cfg(not(feature = "alloc"))]
1540 String::<32>::from_str("Panic Mode").unwrap(),
1541 ),
1542 0x0050 => Some(
1543 #[cfg(feature = "alloc")]
1544 format!("{} ready", SlotIdDefinition::from(data_value1)),
1545 #[cfg(not(feature = "alloc"))]
1546 String::<32>::from_str(
1547 format_args!("{} ready", SlotIdDefinition::from(data_value1))
1548 .as_str()
1549 .unwrap(),
1550 )
1551 .unwrap(),
1552 ),
1553 0x0051 => Some(
1554 #[cfg(feature = "alloc")]
1555 format!("{} not ready", SlotIdDefinition::from(data_value1)),
1556 #[cfg(not(feature = "alloc"))]
1557 String::<32>::from_str(
1558 format_args!("{} not ready", SlotIdDefinition::from(data_value1))
1559 .as_str()
1560 .unwrap(),
1561 )
1562 .unwrap(),
1563 ),
1564 0x0052 => Some(
1565 #[cfg(feature = "alloc")]
1566 format!("{} low fluid", SlotIdDefinition::from(data_value1)),
1567 #[cfg(not(feature = "alloc"))]
1568 String::<32>::from_str(
1569 format_args!("{} low fluid", SlotIdDefinition::from(data_value1))
1570 .as_str()
1571 .unwrap(),
1572 )
1573 .unwrap(),
1574 ),
1575 _ => None,
1576 }
1577 } else {
1578 None
1579 };
1580
1581 StatusMessage {
1582 sub_device_id,
1583 status_type,
1584 status_message_id,
1585 data_value1,
1586 data_value2,
1587 description,
1588 }
1589 }
1590}
1591
1592#[derive(Copy, Clone, Debug, PartialEq)]
1593#[non_exhaustive]
1594pub enum SlotType {
1595 Primary,
1596 SecondaryFine,
1597 SecondaryTiming,
1598 SecondarySpeed,
1599 SecondaryControl,
1600 SecondaryIndex,
1601 SecondaryRotation,
1602 SecondaryIndexRotate,
1603 SecondaryUndefined,
1604 Unknown(u8),
1605}
1606
1607impl From<u8> for SlotType {
1608 fn from(value: u8) -> Self {
1609 match value {
1610 0x00 => Self::Primary,
1611 0x01 => Self::SecondaryFine,
1612 0x02 => Self::SecondaryTiming,
1613 0x03 => Self::SecondarySpeed,
1614 0x04 => Self::SecondaryControl,
1615 0x05 => Self::SecondaryIndex,
1616 0x06 => Self::SecondaryRotation,
1617 0x07 => Self::SecondaryIndexRotate,
1618 0xff => Self::SecondaryUndefined,
1619 value => Self::Unknown(value),
1620 }
1621 }
1622}
1623
1624impl From<SlotType> for u8 {
1625 fn from(value: SlotType) -> Self {
1626 match value {
1627 SlotType::Primary => 0x00,
1628 SlotType::SecondaryFine => 0x01,
1629 SlotType::SecondaryTiming => 0x02,
1630 SlotType::SecondarySpeed => 0x03,
1631 SlotType::SecondaryControl => 0x04,
1632 SlotType::SecondaryIndex => 0x05,
1633 SlotType::SecondaryRotation => 0x06,
1634 SlotType::SecondaryIndexRotate => 0x07,
1635 SlotType::SecondaryUndefined => 0xff,
1636 SlotType::Unknown(value) => value,
1637 }
1638 }
1639}
1640
1641#[derive(Copy, Clone, Debug, PartialEq)]
1642pub struct SlotInfo {
1643 pub id: u16,
1644 pub r#type: SlotType,
1645 pub label_id: u16,
1646}
1647
1648impl SlotInfo {
1649 pub fn new(id: u16, r#type: SlotType, label_id: u16) -> Self {
1650 Self {
1651 id,
1652 r#type,
1653 label_id,
1654 }
1655 }
1656}
1657
1658#[non_exhaustive]
1659#[derive(Copy, Clone, Debug, PartialEq)]
1660pub enum SlotIdDefinition {
1661 Intensity,
1662 IntensityMaster,
1663 Pan,
1664 Tilt,
1665 ColorWheel,
1666 ColorSubCyan,
1667 ColorSubYellow,
1668 ColorSubMagenta,
1669 ColorAddRed,
1670 ColorAddGreen,
1671 ColorAddBlue,
1672 ColorCorrection,
1673 ColorScroll,
1674 ColorSemaphore,
1675 StaticGoboWheel,
1676 RotoGoboWheel,
1677 PrismWheel,
1678 EffectsWheel,
1679 BeamSizeIris,
1680 Edge,
1681 Frost,
1682 Strobe,
1683 Zoom,
1684 FramingShutter,
1685 ShutterRotate,
1686 Douser,
1687 BarnDoor,
1688 LampControl,
1689 FixtureControl,
1690 FixtureSpeed,
1691 Macro,
1692 Undefined,
1693 ManufacturerSpecific(u16),
1694 Unknown(u16),
1695}
1696
1697impl From<u16> for SlotIdDefinition {
1698 fn from(value: u16) -> Self {
1699 match value {
1700 0x0001 => Self::Intensity,
1701 0x0002 => Self::IntensityMaster,
1702 0x0101 => Self::Pan,
1703 0x0102 => Self::Tilt,
1704 0x0201 => Self::ColorWheel,
1705 0x0202 => Self::ColorSubCyan,
1706 0x0203 => Self::ColorSubYellow,
1707 0x0204 => Self::ColorSubMagenta,
1708 0x0205 => Self::ColorAddRed,
1709 0x0206 => Self::ColorAddGreen,
1710 0x0207 => Self::ColorAddBlue,
1711 0x0208 => Self::ColorCorrection,
1712 0x0209 => Self::ColorScroll,
1713 0x0210 => Self::ColorSemaphore,
1714 0x0301 => Self::StaticGoboWheel,
1715 0x0302 => Self::RotoGoboWheel,
1716 0x0303 => Self::PrismWheel,
1717 0x0304 => Self::EffectsWheel,
1718 0x0401 => Self::BeamSizeIris,
1719 0x0402 => Self::Edge,
1720 0x0403 => Self::Frost,
1721 0x0404 => Self::Strobe,
1722 0x0405 => Self::Zoom,
1723 0x0406 => Self::FramingShutter,
1724 0x0407 => Self::ShutterRotate,
1725 0x0408 => Self::Douser,
1726 0x0409 => Self::BarnDoor,
1727 0x0501 => Self::LampControl,
1728 0x0502 => Self::FixtureControl,
1729 0x0503 => Self::FixtureSpeed,
1730 0x0504 => Self::Macro,
1731 0xffff => Self::Undefined,
1732 value if (0x8000..=0xffdf).contains(&value) => Self::ManufacturerSpecific(value),
1733 value => Self::Unknown(value),
1734 }
1735 }
1736}
1737
1738impl From<SlotIdDefinition> for u16 {
1739 fn from(value: SlotIdDefinition) -> Self {
1740 match value {
1741 SlotIdDefinition::Intensity => 0x0001,
1742 SlotIdDefinition::IntensityMaster => 0x0002,
1743 SlotIdDefinition::Pan => 0x0101,
1744 SlotIdDefinition::Tilt => 0x0102,
1745 SlotIdDefinition::ColorWheel => 0x0201,
1746 SlotIdDefinition::ColorSubCyan => 0x0202,
1747 SlotIdDefinition::ColorSubYellow => 0x0203,
1748 SlotIdDefinition::ColorSubMagenta => 0x0204,
1749 SlotIdDefinition::ColorAddRed => 0x0205,
1750 SlotIdDefinition::ColorAddGreen => 0x0206,
1751 SlotIdDefinition::ColorAddBlue => 0x0207,
1752 SlotIdDefinition::ColorCorrection => 0x0208,
1753 SlotIdDefinition::ColorScroll => 0x0209,
1754 SlotIdDefinition::ColorSemaphore => 0x0210,
1755 SlotIdDefinition::StaticGoboWheel => 0x0301,
1756 SlotIdDefinition::RotoGoboWheel => 0x0302,
1757 SlotIdDefinition::PrismWheel => 0x0303,
1758 SlotIdDefinition::EffectsWheel => 0x0304,
1759 SlotIdDefinition::BeamSizeIris => 0x0401,
1760 SlotIdDefinition::Edge => 0x0402,
1761 SlotIdDefinition::Frost => 0x0403,
1762 SlotIdDefinition::Strobe => 0x0404,
1763 SlotIdDefinition::Zoom => 0x0405,
1764 SlotIdDefinition::FramingShutter => 0x0406,
1765 SlotIdDefinition::ShutterRotate => 0x0407,
1766 SlotIdDefinition::Douser => 0x0408,
1767 SlotIdDefinition::BarnDoor => 0x0409,
1768 SlotIdDefinition::LampControl => 0x0501,
1769 SlotIdDefinition::FixtureControl => 0x0502,
1770 SlotIdDefinition::FixtureSpeed => 0x0503,
1771 SlotIdDefinition::Macro => 0x0504,
1772 SlotIdDefinition::Undefined => 0xffff,
1773 SlotIdDefinition::ManufacturerSpecific(value) => value,
1774 SlotIdDefinition::Unknown(value) => value,
1775 }
1776 }
1777}
1778
1779impl core::fmt::Display for SlotIdDefinition {
1780 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1781 let definition = match self {
1782 Self::Intensity => "Intensity",
1783 Self::IntensityMaster => "Intensity Master",
1784 Self::Pan => "Pan",
1785 Self::Tilt => "Tilt",
1786 Self::ColorWheel => "Color Wheel",
1787 Self::ColorSubCyan => "Color Sub Cyan",
1788 Self::ColorSubYellow => "Color Sub Yellow",
1789 Self::ColorSubMagenta => "Color Sub Magenta",
1790 Self::ColorAddRed => "Color Add Red",
1791 Self::ColorAddGreen => "Color Add Green",
1792 Self::ColorAddBlue => "Color Add Blue",
1793 Self::ColorCorrection => "Color Correction",
1794 Self::ColorScroll => "Color Scroll",
1795 Self::ColorSemaphore => "Color Semaphore",
1796 Self::StaticGoboWheel => "Static Gobo Wheel",
1797 Self::RotoGoboWheel => "Roto Gobo Wheel",
1798 Self::PrismWheel => "Prism Wheel",
1799 Self::EffectsWheel => "Effects Wheel",
1800 Self::BeamSizeIris => "Beam Size Iris",
1801 Self::Edge => "Edge",
1802 Self::Frost => "Frost",
1803 Self::Strobe => "Strobe",
1804 Self::Zoom => "Zoom",
1805 Self::FramingShutter => "Framing Shutter",
1806 Self::ShutterRotate => "Shutter Rotate",
1807 Self::Douser => "Douser",
1808 Self::BarnDoor => "Barn Door",
1809 Self::LampControl => "Lamp Control",
1810 Self::FixtureControl => "Fixture Control",
1811 Self::FixtureSpeed => "Fixture Speed",
1812 Self::Macro => "Macro",
1813 Self::Undefined => "Undefined",
1814 Self::ManufacturerSpecific(value) => {
1815 return write!(f, "Manufacturer Specific: {}", value)
1816 }
1817 Self::Unknown(value) => return write!(f, "Unknown Slot Id Definition: {}", value),
1818 };
1819
1820 f.write_str(definition)
1821 }
1822}
1823
1824#[derive(Copy, Clone, Debug, PartialEq)]
1825pub struct DefaultSlotValue {
1826 pub id: u16,
1827 pub value: u8,
1828}
1829
1830impl DefaultSlotValue {
1831 pub fn new(id: u16, value: u8) -> Self {
1832 Self { id, value }
1833 }
1834}
1835
1836#[derive(Copy, Clone, Debug, PartialEq)]
1837#[non_exhaustive]
1838pub enum SensorType {
1839 Temperature,
1840 Voltage,
1841 Current,
1842 Frequency,
1843 Resistance,
1844 Power,
1845 Mass,
1846 Length,
1847 Area,
1848 Volume,
1849 Density,
1850 Velocity,
1851 Acceleration,
1852 Force,
1853 Energy,
1854 Pressure,
1855 Time,
1856 Angle,
1857 PositionX,
1858 PositionY,
1859 PositionZ,
1860 AngularVelocity,
1861 LuminousIntensity,
1862 LuminousFlux,
1863 Illuminance,
1864 ChrominanceRed,
1865 ChrominanceGreen,
1866 ChrominanceBlue,
1867 Contacts,
1868 Memory,
1869 Items,
1870 Humidity,
1871 Counter16Bit,
1872 Other,
1873 ManufacturerSpecific(u8),
1874}
1875
1876impl TryFrom<u8> for SensorType {
1877 type Error = RdmError;
1878 fn try_from(value: u8) -> Result<Self, RdmError> {
1879 match value {
1880 0x00 => Ok(Self::Temperature),
1881 0x01 => Ok(Self::Voltage),
1882 0x02 => Ok(Self::Current),
1883 0x03 => Ok(Self::Frequency),
1884 0x04 => Ok(Self::Resistance),
1885 0x05 => Ok(Self::Power),
1886 0x06 => Ok(Self::Mass),
1887 0x07 => Ok(Self::Length),
1888 0x08 => Ok(Self::Area),
1889 0x09 => Ok(Self::Volume),
1890 0x0a => Ok(Self::Density),
1891 0x0b => Ok(Self::Velocity),
1892 0x0c => Ok(Self::Acceleration),
1893 0x0d => Ok(Self::Force),
1894 0x0e => Ok(Self::Energy),
1895 0x0f => Ok(Self::Pressure),
1896 0x10 => Ok(Self::Time),
1897 0x11 => Ok(Self::Angle),
1898 0x12 => Ok(Self::PositionX),
1899 0x13 => Ok(Self::PositionY),
1900 0x14 => Ok(Self::PositionZ),
1901 0x15 => Ok(Self::AngularVelocity),
1902 0x16 => Ok(Self::LuminousIntensity),
1903 0x17 => Ok(Self::LuminousFlux),
1904 0x18 => Ok(Self::Illuminance),
1905 0x19 => Ok(Self::ChrominanceRed),
1906 0x1a => Ok(Self::ChrominanceGreen),
1907 0x1b => Ok(Self::ChrominanceBlue),
1908 0x1c => Ok(Self::Contacts),
1909 0x1d => Ok(Self::Memory),
1910 0x1e => Ok(Self::Items),
1911 0x1f => Ok(Self::Humidity),
1912 0x20 => Ok(Self::Counter16Bit),
1913 0x7f => Ok(Self::Other),
1914 value if (0x80..=0xff).contains(&value) => Ok(Self::ManufacturerSpecific(value)),
1915 _ => Err(RdmError::InvalidSensorType(value)),
1916 }
1917 }
1918}
1919
1920impl From<SensorType> for u8 {
1921 fn from(value: SensorType) -> Self {
1922 match value {
1923 SensorType::Temperature => 0x00,
1924 SensorType::Voltage => 0x01,
1925 SensorType::Current => 0x02,
1926 SensorType::Frequency => 0x03,
1927 SensorType::Resistance => 0x04,
1928 SensorType::Power => 0x05,
1929 SensorType::Mass => 0x06,
1930 SensorType::Length => 0x07,
1931 SensorType::Area => 0x08,
1932 SensorType::Volume => 0x09,
1933 SensorType::Density => 0x0a,
1934 SensorType::Velocity => 0x0b,
1935 SensorType::Acceleration => 0x0c,
1936 SensorType::Force => 0x0d,
1937 SensorType::Energy => 0x0e,
1938 SensorType::Pressure => 0x0f,
1939 SensorType::Time => 0x10,
1940 SensorType::Angle => 0x11,
1941 SensorType::PositionX => 0x12,
1942 SensorType::PositionY => 0x13,
1943 SensorType::PositionZ => 0x14,
1944 SensorType::AngularVelocity => 0x15,
1945 SensorType::LuminousIntensity => 0x16,
1946 SensorType::LuminousFlux => 0x17,
1947 SensorType::Illuminance => 0x18,
1948 SensorType::ChrominanceRed => 0x19,
1949 SensorType::ChrominanceGreen => 0x1a,
1950 SensorType::ChrominanceBlue => 0x1b,
1951 SensorType::Contacts => 0x1c,
1952 SensorType::Memory => 0x1d,
1953 SensorType::Items => 0x1e,
1954 SensorType::Humidity => 0x1f,
1955 SensorType::Counter16Bit => 0x20,
1956 SensorType::Other => 0x7f,
1957 SensorType::ManufacturerSpecific(value) => value,
1958 }
1959 }
1960}
1961
1962#[derive(Copy, Clone, Debug, PartialEq)]
1963#[non_exhaustive]
1964pub enum SensorUnit {
1965 None,
1966 Centigrade,
1967 VoltsDc,
1968 VoltsAcPeak,
1969 VoltsAcRms,
1970 AmpsDc,
1971 AmpsAcPeak,
1972 AmpsAcRms,
1973 Hertz,
1974 Ohm,
1975 Watt,
1976 Kilogram,
1977 Meter,
1978 SquareMeter,
1979 CubicMeter,
1980 KilogramPerCubicMeter,
1981 MeterPerSecond,
1982 MeterPerSecondSquared,
1983 Newton,
1984 Joule,
1985 Pascal,
1986 Second,
1987 Degree,
1988 Steradian,
1989 Candela,
1990 Lumen,
1991 Lux,
1992 Ire,
1993 Byte,
1994 ManufacturerSpecific(u8),
1995}
1996
1997impl TryFrom<u8> for SensorUnit {
1998 type Error = RdmError;
1999
2000 fn try_from(value: u8) -> Result<Self, Self::Error> {
2001 match value {
2002 0x00 => Ok(Self::None),
2003 0x01 => Ok(Self::Centigrade),
2004 0x02 => Ok(Self::VoltsDc),
2005 0x03 => Ok(Self::VoltsAcPeak),
2006 0x04 => Ok(Self::VoltsAcRms),
2007 0x05 => Ok(Self::AmpsDc),
2008 0x06 => Ok(Self::AmpsAcPeak),
2009 0x07 => Ok(Self::AmpsAcRms),
2010 0x08 => Ok(Self::Hertz),
2011 0x09 => Ok(Self::Ohm),
2012 0x0a => Ok(Self::Watt),
2013 0x0b => Ok(Self::Kilogram),
2014 0x0c => Ok(Self::Meter),
2015 0x0d => Ok(Self::SquareMeter),
2016 0x0e => Ok(Self::CubicMeter),
2017 0x0f => Ok(Self::KilogramPerCubicMeter),
2018 0x10 => Ok(Self::MeterPerSecond),
2019 0x11 => Ok(Self::MeterPerSecondSquared),
2020 0x12 => Ok(Self::Newton),
2021 0x13 => Ok(Self::Joule),
2022 0x14 => Ok(Self::Pascal),
2023 0x15 => Ok(Self::Second),
2024 0x16 => Ok(Self::Degree),
2025 0x17 => Ok(Self::Steradian),
2026 0x18 => Ok(Self::Candela),
2027 0x19 => Ok(Self::Lumen),
2028 0x1a => Ok(Self::Lux),
2029 0x1b => Ok(Self::Ire),
2030 0x1c => Ok(Self::Byte),
2031 value if (0x80..=0xff).contains(&value) => Ok(Self::ManufacturerSpecific(value)),
2032 _ => Err(RdmError::InvalidSensorUnit(value)),
2033 }
2034 }
2035}
2036
2037impl From<SensorUnit> for u8 {
2038 fn from(value: SensorUnit) -> Self {
2039 match value {
2040 SensorUnit::None => 0x00,
2041 SensorUnit::Centigrade => 0x01,
2042 SensorUnit::VoltsDc => 0x02,
2043 SensorUnit::VoltsAcPeak => 0x03,
2044 SensorUnit::VoltsAcRms => 0x04,
2045 SensorUnit::AmpsDc => 0x05,
2046 SensorUnit::AmpsAcPeak => 0x06,
2047 SensorUnit::AmpsAcRms => 0x07,
2048 SensorUnit::Hertz => 0x08,
2049 SensorUnit::Ohm => 0x09,
2050 SensorUnit::Watt => 0x0a,
2051 SensorUnit::Kilogram => 0x0b,
2052 SensorUnit::Meter => 0x0c,
2053 SensorUnit::SquareMeter => 0x0d,
2054 SensorUnit::CubicMeter => 0x0e,
2055 SensorUnit::KilogramPerCubicMeter => 0x0f,
2056 SensorUnit::MeterPerSecond => 0x10,
2057 SensorUnit::MeterPerSecondSquared => 0x11,
2058 SensorUnit::Newton => 0x12,
2059 SensorUnit::Joule => 0x13,
2060 SensorUnit::Pascal => 0x14,
2061 SensorUnit::Second => 0x15,
2062 SensorUnit::Degree => 0x16,
2063 SensorUnit::Steradian => 0x17,
2064 SensorUnit::Candela => 0x18,
2065 SensorUnit::Lumen => 0x19,
2066 SensorUnit::Lux => 0x1a,
2067 SensorUnit::Ire => 0x1b,
2068 SensorUnit::Byte => 0x1c,
2069 SensorUnit::ManufacturerSpecific(value) => value,
2070 }
2071 }
2072}
2073
2074#[derive(Copy, Clone, Debug, PartialEq)]
2075pub enum SensorUnitPrefix {
2076 None = 0x00,
2077 Deci = 0x01,
2078 Centi = 0x02,
2079 Milli = 0x03,
2080 Micro = 0x04,
2081 Nano = 0x05,
2082 Pico = 0x06,
2083 Femto = 0x07,
2084 Atto = 0x08,
2085 Zepto = 0x09,
2086 Yocto = 0x0a,
2087 Deca = 0x11,
2088 Hecto = 0x12,
2089 Kilo = 0x13,
2090 Mega = 0x14,
2091 Giga = 0x15,
2092 Terra = 0x16,
2093 Peta = 0x17,
2094 Exa = 0x18,
2095 Zetta = 0x19,
2096 Yotta = 0x1a,
2097}
2098
2099impl TryFrom<u8> for SensorUnitPrefix {
2100 type Error = RdmError;
2101
2102 fn try_from(value: u8) -> Result<Self, Self::Error> {
2103 match value {
2104 0x00 => Ok(Self::None),
2105 0x01 => Ok(Self::Deci),
2106 0x02 => Ok(Self::Centi),
2107 0x03 => Ok(Self::Milli),
2108 0x04 => Ok(Self::Micro),
2109 0x05 => Ok(Self::Nano),
2110 0x06 => Ok(Self::Pico),
2111 0x07 => Ok(Self::Femto),
2112 0x08 => Ok(Self::Atto),
2113 0x09 => Ok(Self::Zepto),
2114 0x0a => Ok(Self::Yocto),
2115 0x11 => Ok(Self::Deca),
2116 0x12 => Ok(Self::Hecto),
2117 0x13 => Ok(Self::Kilo),
2118 0x14 => Ok(Self::Mega),
2119 0x15 => Ok(Self::Giga),
2120 0x16 => Ok(Self::Terra),
2121 0x17 => Ok(Self::Peta),
2122 0x18 => Ok(Self::Exa),
2123 0x19 => Ok(Self::Zetta),
2124 0x1a => Ok(Self::Yotta),
2125 _ => Err(RdmError::InvalidSensorUnitPrefix(value)),
2126 }
2127 }
2128}
2129
2130#[derive(Clone, Debug, PartialEq)]
2131pub struct SensorDefinition {
2132 pub id: u8,
2133 pub kind: SensorType,
2134 pub unit: SensorUnit,
2135 pub prefix: SensorUnitPrefix,
2136 pub range_minimum_value: i16,
2137 pub range_maximum_value: i16,
2138 pub normal_minimum_value: i16,
2139 pub normal_maximum_value: i16,
2140 pub is_lowest_highest_detected_value_supported: bool,
2141 pub is_recorded_value_supported: bool,
2142 #[cfg(feature = "alloc")]
2143 pub description: String,
2144 #[cfg(not(feature = "alloc"))]
2145 pub description: String<32>,
2146}
2147
2148#[derive(Copy, Clone, Debug, PartialEq)]
2149pub struct SensorValue {
2150 pub sensor_id: u8,
2151 pub current_value: i16,
2152 pub lowest_detected_value: i16,
2153 pub highest_detected_value: i16,
2154 pub recorded_value: i16,
2155}
2156
2157impl SensorValue {
2158 pub fn new(
2159 sensor_id: u8,
2160 current_value: i16,
2161 lowest_detected_value: i16,
2162 highest_detected_value: i16,
2163 recorded_value: i16,
2164 ) -> Self {
2165 Self {
2166 sensor_id,
2167 current_value,
2168 lowest_detected_value,
2169 highest_detected_value,
2170 recorded_value,
2171 }
2172 }
2173}
2174
2175#[derive(Copy, Clone, Debug, PartialEq)]
2176pub enum IdentifyMode {
2177 Quiet = 0x00,
2178 Loud = 0xff,
2179}
2180
2181impl TryFrom<u8> for IdentifyMode {
2182 type Error = RdmError;
2183
2184 fn try_from(value: u8) -> Result<Self, Self::Error> {
2185 match value {
2186 0x00 => Ok(Self::Quiet),
2187 0xff => Ok(Self::Loud),
2188 value => Err(RdmError::InvalidIdentifyMode(value)),
2189 }
2190 }
2191}
2192
2193#[derive(Copy, Clone, Debug, PartialEq)]
2194pub enum PresetProgrammed {
2195 NotProgrammed = 0x00,
2196 Programmed = 0x01,
2197 ReadOnly = 0x02,
2198}
2199
2200impl TryFrom<u8> for PresetProgrammed {
2201 type Error = RdmError;
2202
2203 fn try_from(value: u8) -> Result<Self, Self::Error> {
2204 match value {
2205 0x00 => Ok(Self::NotProgrammed),
2206 0x01 => Ok(Self::Programmed),
2207 0x02 => Ok(Self::ReadOnly),
2208 value => Err(RdmError::InvalidPresetProgrammed(value)),
2209 }
2210 }
2211}
2212
2213#[derive(Copy, Clone, Debug, PartialEq)]
2214pub enum MergeMode {
2215 Default = 0x00,
2216 Htp = 0x01,
2217 Ltp = 0x02,
2218 DmxOnly = 0x03,
2219 Other = 0xff,
2220}
2221
2222impl TryFrom<u8> for MergeMode {
2223 type Error = RdmError;
2224
2225 fn try_from(value: u8) -> Result<Self, Self::Error> {
2226 match value {
2227 0x00 => Ok(Self::Default),
2228 0x01 => Ok(Self::Htp),
2229 0x02 => Ok(Self::Ltp),
2230 0x03 => Ok(Self::DmxOnly),
2231 0xff => Ok(Self::Other),
2232 value => Err(RdmError::InvalidMergeMode(value)),
2233 }
2234 }
2235}
2236
2237#[derive(Copy, Clone, Debug, PartialEq)]
2238pub struct PinCode(pub u16);
2239
2240impl TryFrom<u16> for PinCode {
2241 type Error = RdmError;
2242
2243 fn try_from(value: u16) -> Result<Self, Self::Error> {
2244 if value > 9999 {
2245 Err(RdmError::InvalidPinCode(value))
2246 } else {
2247 Ok(Self(value))
2248 }
2249 }
2250}
2251
2252#[derive(Copy, Clone, Debug, PartialEq)]
2253pub enum SupportedTimes {
2254 NotSupported,
2255 Time(u16),
2256}
2257
2258impl From<u16> for SupportedTimes {
2259 fn from(value: u16) -> Self {
2260 match value {
2261 0xffff => Self::NotSupported,
2262 value => Self::Time(value),
2263 }
2264 }
2265}
2266
2267impl From<SupportedTimes> for u16 {
2268 fn from(value: SupportedTimes) -> u16 {
2269 match value {
2270 SupportedTimes::NotSupported => 0xffff,
2271 SupportedTimes::Time(value) => value,
2272 }
2273 }
2274}
2275
2276#[derive(Copy, Clone, Debug, PartialEq)]
2277pub enum TimeMode {
2278 Infinite,
2279 TenthOfSeconds(u16),
2280}
2281
2282impl From<u16> for TimeMode {
2283 fn from(value: u16) -> Self {
2284 match value {
2285 0xffff => Self::Infinite,
2286 value => Self::TenthOfSeconds(value),
2287 }
2288 }
2289}
2290
2291impl From<TimeMode> for u16 {
2292 fn from(value: TimeMode) -> u16 {
2293 match value {
2294 TimeMode::Infinite => 0xffff,
2295 TimeMode::TenthOfSeconds(value) => value,
2296 }
2297 }
2298}
2299
2300#[derive(Copy, Clone, Debug, PartialEq)]
2301pub enum DhcpMode {
2302 Inactive = 0x00,
2303 Active = 0x01,
2304 Unknown = 0x02,
2305}
2306
2307impl TryFrom<u8> for DhcpMode {
2308 type Error = RdmError;
2309
2310 fn try_from(value: u8) -> Result<Self, Self::Error> {
2311 match value {
2312 0x00 => Ok(Self::Inactive),
2313 0x01 => Ok(Self::Active),
2314 0x02 => Ok(Self::Unknown),
2315 value => Err(RdmError::InvalidDhcpMode(value)),
2316 }
2317 }
2318}
2319
2320#[derive(Copy, Clone, Debug, PartialEq)]
2321pub enum Ipv4Address {
2322 Unconfigured,
2323 Configured(Ipv4Addr),
2324}
2325
2326impl From<Ipv4Addr> for Ipv4Address {
2327 fn from(value: Ipv4Addr) -> Self {
2328 Self::Configured(value)
2329 }
2330}
2331
2332impl From<u32> for Ipv4Address {
2333 fn from(value: u32) -> Self {
2334 if value == 0 {
2335 Self::Unconfigured
2336 } else {
2337 Self::Configured(Ipv4Addr::from(value))
2338 }
2339 }
2340}
2341
2342impl From<[u8; 4]> for Ipv4Address {
2343 fn from(value: [u8; 4]) -> Self {
2344 if value == [0, 0, 0, 0] {
2345 Self::Unconfigured
2346 } else {
2347 Self::Configured(Ipv4Addr::from(value))
2348 }
2349 }
2350}
2351
2352impl From<Ipv4Address> for [u8; 4] {
2353 fn from(value: Ipv4Address) -> [u8; 4] {
2354 match value {
2355 Ipv4Address::Unconfigured => [0, 0, 0, 0],
2356 Ipv4Address::Configured(ip) => ip.octets(),
2357 }
2358 }
2359}
2360
2361impl From<Ipv4Address> for u32 {
2362 fn from(value: Ipv4Address) -> u32 {
2363 match value {
2364 Ipv4Address::Unconfigured => 0,
2365 Ipv4Address::Configured(ip) => ip.to_bits(),
2366 }
2367 }
2368}
2369
2370#[derive(Copy, Clone, Debug, PartialEq)]
2371pub enum Ipv6Address {
2372 Unconfigured,
2373 Configured(Ipv6Addr),
2374}
2375
2376impl From<Ipv6Addr> for Ipv6Address {
2377 fn from(value: Ipv6Addr) -> Self {
2378 Self::Configured(value)
2379 }
2380}
2381
2382impl From<u128> for Ipv6Address {
2383 fn from(value: u128) -> Self {
2384 if value == 0 {
2385 Self::Unconfigured
2386 } else {
2387 Self::Configured(Ipv6Addr::from(value))
2388 }
2389 }
2390}
2391
2392impl From<[u8; 16]> for Ipv6Address {
2393 fn from(value: [u8; 16]) -> Self {
2394 if value == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] {
2395 Self::Unconfigured
2396 } else {
2397 Self::Configured(Ipv6Addr::from(value))
2398 }
2399 }
2400}
2401
2402impl From<Ipv6Address> for [u8; 16] {
2403 fn from(value: Ipv6Address) -> [u8; 16] {
2404 match value {
2405 Ipv6Address::Unconfigured => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
2406 Ipv6Address::Configured(ip) => ip.octets(),
2407 }
2408 }
2409}
2410
2411impl From<Ipv6Address> for u128 {
2412 fn from(value: Ipv6Address) -> u128 {
2413 match value {
2414 Ipv6Address::Unconfigured => 0,
2415 Ipv6Address::Configured(ip) => ip.to_bits(),
2416 }
2417 }
2418}
2419
2420#[derive(Copy, Clone, Debug, PartialEq)]
2421pub enum Ipv4Route {
2422 NoDefault,
2423 Configured(Ipv4Addr),
2424}
2425
2426impl From<Ipv4Addr> for Ipv4Route {
2427 fn from(value: Ipv4Addr) -> Self {
2428 Self::Configured(value)
2429 }
2430}
2431
2432impl From<u32> for Ipv4Route {
2433 fn from(value: u32) -> Self {
2434 if value == 0 {
2435 Self::NoDefault
2436 } else {
2437 Self::Configured(Ipv4Addr::from(value))
2438 }
2439 }
2440}
2441
2442impl From<[u8; 4]> for Ipv4Route {
2443 fn from(value: [u8; 4]) -> Self {
2444 if value == [0, 0, 0, 0] {
2445 Self::NoDefault
2446 } else {
2447 Self::Configured(Ipv4Addr::from(value))
2448 }
2449 }
2450}
2451
2452impl From<Ipv4Route> for [u8; 4] {
2453 fn from(value: Ipv4Route) -> [u8; 4] {
2454 match value {
2455 Ipv4Route::NoDefault => [0, 0, 0, 0],
2456 Ipv4Route::Configured(ip) => ip.octets(),
2457 }
2458 }
2459}
2460
2461impl From<Ipv4Route> for u32 {
2462 fn from(value: Ipv4Route) -> u32 {
2463 match value {
2464 Ipv4Route::NoDefault => 0,
2465 Ipv4Route::Configured(ip) => ip.to_bits(),
2466 }
2467 }
2468}
2469
2470#[derive(Copy, Clone, Debug, PartialEq)]
2473pub enum HardwareType {
2474 Reserved(u16),
2475 Ethernet,
2476 ExperimentEthernet,
2477 AmateurRadioAx25,
2478 ProteonPronetTokenRing,
2479 Chaos,
2480 Ieee802Networks,
2481 Arcnet,
2482 Hyperchannel,
2483 Lanstar,
2484 AutonetShortAddress,
2485 LocalTalk,
2486 LocalNet,
2487 UltraLink,
2488 SMDS,
2489 FrameRelay,
2490 ATM,
2491 HDLC,
2492 FibreChannel,
2493 ATMLogical,
2494 SerialLine,
2495 ATMPhysical,
2496 MilStd188220,
2497 Metricom,
2498 IEEE1394,
2499 MAPOS,
2500 Twinaxial,
2501 EUI64,
2502 HIPARP,
2503 IPAndARPOverISO,
2504 ARPSec,
2505 IPsecTunnel,
2506 InfiniBand,
2507 TIA102,
2508 Wiegand,
2509 PureIP,
2510 HwExp1,
2511 Hf1,
2512 UnifiedBus,
2513 HwExp2,
2514 AEthernet,
2515 Unknown(u16),
2516}
2517
2518impl From<u16> for HardwareType {
2519 fn from(value: u16) -> Self {
2520 match value {
2521 val @ (0 | 65535) => Self::Reserved(val),
2522 1 => Self::Ethernet,
2523 2 => Self::ExperimentEthernet,
2524 3 => Self::AmateurRadioAx25,
2525 4 => Self::ProteonPronetTokenRing,
2526 5 => Self::Chaos,
2527 6 => Self::Ieee802Networks,
2528 7 => Self::Arcnet,
2529 8 => Self::Hyperchannel,
2530 9 => Self::Lanstar,
2531 10 => Self::AutonetShortAddress,
2532 11 => Self::LocalTalk,
2533 12 => Self::LocalNet,
2534 13 => Self::UltraLink,
2535 14 => Self::SMDS,
2536 15 => Self::FrameRelay,
2537 16 => Self::ATM,
2538 17 => Self::HDLC,
2539 18 => Self::FibreChannel,
2540 19 => Self::ATMLogical,
2541 20 => Self::SerialLine,
2542 21 => Self::ATMPhysical,
2543 22 => Self::MilStd188220,
2544 23 => Self::Metricom,
2545 24 => Self::IEEE1394,
2546 25 => Self::MAPOS,
2547 26 => Self::Twinaxial,
2548 27 => Self::EUI64,
2549 28 => Self::HIPARP,
2550 29 => Self::IPAndARPOverISO,
2551 30 => Self::ARPSec,
2552 31 => Self::IPsecTunnel,
2553 32 => Self::InfiniBand,
2554 33 => Self::TIA102,
2555 34 => Self::Wiegand,
2556 35 => Self::PureIP,
2557 36 => Self::HwExp1,
2558 37 => Self::Hf1,
2559 38 => Self::UnifiedBus,
2560 256 => Self::HwExp2,
2561 257 => Self::AEthernet,
2562 value => Self::Unknown(value),
2563 }
2564 }
2565}
2566
2567impl From<HardwareType> for u16 {
2568 fn from(value: HardwareType) -> Self {
2569 match value {
2570 HardwareType::Reserved(val) => val,
2571 HardwareType::Ethernet => 1,
2572 HardwareType::ExperimentEthernet => 2,
2573 HardwareType::AmateurRadioAx25 => 3,
2574 HardwareType::ProteonPronetTokenRing => 4,
2575 HardwareType::Chaos => 5,
2576 HardwareType::Ieee802Networks => 6,
2577 HardwareType::Arcnet => 7,
2578 HardwareType::Hyperchannel => 8,
2579 HardwareType::Lanstar => 9,
2580 HardwareType::AutonetShortAddress => 10,
2581 HardwareType::LocalTalk => 11,
2582 HardwareType::LocalNet => 12,
2583 HardwareType::UltraLink => 13,
2584 HardwareType::SMDS => 14,
2585 HardwareType::FrameRelay => 15,
2586 HardwareType::ATM => 16,
2587 HardwareType::HDLC => 17,
2588 HardwareType::FibreChannel => 18,
2589 HardwareType::ATMLogical => 19,
2590 HardwareType::SerialLine => 20,
2591 HardwareType::ATMPhysical => 21,
2592 HardwareType::MilStd188220 => 22,
2593 HardwareType::Metricom => 23,
2594 HardwareType::IEEE1394 => 24,
2595 HardwareType::MAPOS => 25,
2596 HardwareType::Twinaxial => 26,
2597 HardwareType::EUI64 => 27,
2598 HardwareType::HIPARP => 28,
2599 HardwareType::IPAndARPOverISO => 29,
2600 HardwareType::ARPSec => 30,
2601 HardwareType::IPsecTunnel => 31,
2602 HardwareType::InfiniBand => 32,
2603 HardwareType::TIA102 => 33,
2604 HardwareType::Wiegand => 34,
2605 HardwareType::PureIP => 35,
2606 HardwareType::HwExp1 => 36,
2607 HardwareType::Hf1 => 37,
2608 HardwareType::UnifiedBus => 38,
2609 HardwareType::HwExp2 => 256,
2610 HardwareType::AEthernet => 257,
2611 HardwareType::Unknown(val) => val,
2612 }
2613 }
2614}
2615
2616#[derive(Copy, Clone, Debug, PartialEq)]
2617pub struct NetworkInterface {
2618 pub interface_id: u32,
2619 pub hardware_type: HardwareType,
2620}
2621
2622#[derive(Copy, Clone, Debug, PartialEq)]
2623pub enum StaticConfigType {
2624 NoStaticConfig = 0x00,
2625 StaticConfigIpv4 = 0x01,
2626 StaticConfigIpv6 = 0x02,
2627}
2628
2629impl TryFrom<u8> for StaticConfigType {
2630 type Error = RdmError;
2631
2632 fn try_from(value: u8) -> Result<Self, Self::Error> {
2633 match value {
2634 0x00 => Ok(Self::NoStaticConfig),
2635 0x01 => Ok(Self::StaticConfigIpv4),
2636 0x02 => Ok(Self::StaticConfigIpv6),
2637 value => Err(RdmError::InvalidStaticConfigType(value)),
2638 }
2639 }
2640}
2641
2642#[derive(Copy, Clone, Debug, PartialEq)]
2643pub enum BrokerState {
2644 Disabled = 0x00,
2645 Active = 0x01,
2646 Standby = 0x02,
2647}
2648
2649impl TryFrom<u8> for BrokerState {
2650 type Error = RdmError;
2651
2652 fn try_from(value: u8) -> Result<Self, Self::Error> {
2653 match value {
2654 0x00 => Ok(Self::Disabled),
2655 0x01 => Ok(Self::Active),
2656 0x02 => Ok(Self::Standby),
2657 value => Err(RdmError::InvalidBrokerState(value)),
2658 }
2659 }
2660}
2661
2662#[derive(Copy, Clone, Debug, PartialEq)]
2663pub enum DiscoveryState {
2664 Incomplete,
2665 Incremental,
2666 Full,
2667 NotActive,
2668 ManufacturerSpecific(u8),
2669}
2670
2671impl TryFrom<u8> for DiscoveryState {
2672 type Error = RdmError;
2673
2674 fn try_from(value: u8) -> Result<Self, Self::Error> {
2675 match value {
2676 0x00 => Ok(Self::Incomplete),
2677 0x01 => Ok(Self::Incremental),
2678 0x02 => Ok(Self::Full),
2679 0x04 => Ok(Self::NotActive),
2680 value if (0x80..=0xff).contains(&value) => Ok(Self::ManufacturerSpecific(value)),
2681 value => Err(RdmError::InvalidDiscoveryState(value)),
2682 }
2683 }
2684}
2685
2686impl From<DiscoveryState> for u8 {
2687 fn from(value: DiscoveryState) -> u8 {
2688 match value {
2689 DiscoveryState::Incomplete => 0x00,
2690 DiscoveryState::Incremental => 0x01,
2691 DiscoveryState::Full => 0x02,
2692 DiscoveryState::NotActive => 0x04,
2693 DiscoveryState::ManufacturerSpecific(value) => value,
2694 }
2695 }
2696}
2697
2698#[derive(Copy, Clone, Debug, PartialEq)]
2699pub enum DiscoveryCountStatus {
2700 Incomplete,
2701 Count(u16),
2702 Unknown
2703}
2704
2705impl From<u16> for DiscoveryCountStatus {
2706 fn from(value: u16) -> Self {
2707 match value {
2708 0x0000 => Self::Incomplete,
2709 0xffff => Self::Unknown,
2710 value => Self::Count(value),
2711 }
2712 }
2713}
2714
2715impl From<DiscoveryCountStatus> for u16 {
2716 fn from(value: DiscoveryCountStatus) -> u16 {
2717 match value {
2718 DiscoveryCountStatus::Incomplete => 0x0000,
2719 DiscoveryCountStatus::Unknown => 0xffff,
2720 DiscoveryCountStatus::Count(value) => value,
2721 }
2722 }
2723}
2724
2725#[derive(Copy, Clone, Debug, PartialEq)]
2726pub enum EndpointMode {
2727 Disabled = 0x00, Input = 0x01, Output = 0x02, }
2731
2732impl TryFrom<u8> for EndpointMode {
2733 type Error = RdmError;
2734
2735 fn try_from(value: u8) -> Result<Self, Self::Error> {
2736 match value {
2737 0x00 => Ok(Self::Disabled),
2738 0x01 => Ok(Self::Input),
2739 0x02 => Ok(Self::Output),
2740 value => Err(RdmError::InvalidEndpointMode(value)),
2741 }
2742 }
2743}
2744
2745#[derive(Copy, Clone, Debug, PartialEq)]
2746pub enum EndpointId {
2747 Null,
2748 Device(u16),
2749 Reserved(u16),
2750 Broadcast,
2751}
2752
2753impl From<u16> for EndpointId {
2754 fn from(value: u16) -> Self {
2755 match value {
2756 0 => EndpointId::Null,
2757 0xffff => EndpointId::Broadcast,
2758 value if (0xfa00..=0xfffe).contains(&value) => EndpointId::Reserved(value),
2759 value => EndpointId::Device(value),
2760 }
2761 }
2762}
2763
2764impl From<EndpointId> for u16 {
2765 fn from(value: EndpointId) -> Self {
2766 match value {
2767 EndpointId::Broadcast => 0xffff,
2768 EndpointId::Null => 0,
2769 EndpointId::Device(value) => value,
2770 EndpointId::Reserved(value) => value,
2771 }
2772 }
2773}
2774
2775#[derive(Copy, Clone, Debug, PartialEq)]
2776pub enum EndpointType {
2777 Virtual = 0x00,
2778 Physical = 0x01
2779}
2780
2781impl TryFrom<u8> for EndpointType {
2782 type Error = RdmError;
2783
2784 fn try_from(value: u8) -> Result<Self, Self::Error> {
2785 match value {
2786 0x00 => Ok(Self::Virtual),
2787 0x01 => Ok(Self::Physical),
2788 value => Err(RdmError::InvalidEndpointType(value)),
2789 }
2790 }
2791}
2792
2793#[cfg(test)]
2794mod tests {
2795 use super::*;
2796
2797 #[test]
2798 #[cfg(feature = "alloc")]
2799 fn should_decode_string_bytes() {
2800 assert_eq!(
2801 decode_string_bytes(&b"null terminated string\0"[..]).unwrap(),
2802 "null terminated string".to_string()
2803 );
2804 assert_eq!(
2805 decode_string_bytes(&b"not null terminated string"[..]).unwrap(),
2806 "not null terminated string".to_string()
2807 );
2808 assert_eq!(
2809 decode_string_bytes(&b"early terminated\0string"[..]).unwrap(),
2810 "early terminated".to_string()
2811 );
2812 }
2813
2814 #[test]
2815 #[cfg(not(feature = "alloc"))]
2816 fn should_decode_string_bytes() {
2817 assert_eq!(
2818 decode_string_bytes::<32>(&b"null terminated string\0"[..]).unwrap(),
2819 String::from_utf8(Vec::<u8, 32>::from_slice(b"null terminated string").unwrap())
2820 .unwrap()
2821 );
2822 assert_eq!(
2823 decode_string_bytes::<32>(&b"not null terminated string"[..]).unwrap(),
2824 String::from_utf8(Vec::<u8, 32>::from_slice(b"not null terminated string").unwrap())
2825 .unwrap()
2826 );
2827 assert_eq!(
2828 decode_string_bytes::<32>(&b"early terminated\0string"[..]).unwrap(),
2829 String::from_utf8(Vec::<u8, 32>::from_slice(b"early terminated").unwrap()).unwrap()
2830 );
2831 }
2832}