1use byteorder::{ReadBytesExt, WriteBytesExt, LE};
4use std::io;
5
6pub use self::command::Command;
7
8pub const COMMUNICATION_PORT: u16 = 7765;
10
11pub const BROADCAST_PORT: u16 = 7654;
16
17pub trait WriteBytes {
21 fn write_bytes<P: WriteToBytes>(&mut self, protocol: P) -> io::Result<()>;
22}
23
24pub trait ReadBytes {
28 fn read_bytes<P: ReadFromBytes>(&mut self) -> io::Result<P>;
29}
30
31pub trait WriteToBytes {
33 fn write_to_bytes<W: WriteBytesExt>(&self, writer: W) -> io::Result<()>;
35}
36
37pub trait ReadFromBytes: Sized {
39 fn read_from_bytes<R: ReadBytesExt>(reader: R) -> io::Result<Self>;
41}
42
43pub trait SizeBytes {
45 const SIZE_BYTES: usize;
46}
47
48#[repr(C)]
51#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
52pub struct DacStatus {
53 pub protocol: u8,
57 pub light_engine_state: u8,
59 pub playback_state: u8,
61 pub source: u8,
67 pub light_engine_flags: u16,
80 pub playback_flags: u16,
90 pub source_flags: u16,
105 pub buffer_fullness: u16,
107 pub point_rate: u32,
112 pub point_count: u32,
117}
118
119#[repr(C)]
122#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
123pub struct DacBroadcast {
124 pub mac_address: [u8; 6],
126 pub hw_revision: u16,
129 pub sw_revision: u16,
133 pub buffer_capacity: u16,
138 pub max_point_rate: u32,
142 pub dac_status: DacStatus,
144}
145
146#[repr(C)]
150#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
151pub struct DacPoint {
152 pub control: u16,
160 pub x: i16,
163 pub y: i16,
166 pub r: u16,
168 pub g: u16,
170 pub b: u16,
172 pub i: u16,
173 pub u1: u16,
174 pub u2: u16,
175}
176
177#[repr(C)]
179#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
180pub struct DacResponse {
181 pub response: u8,
183 pub command: u8,
189 pub dac_status: DacStatus,
191}
192
193impl DacStatus {
194 pub const LIGHT_ENGINE_READY: u8 = 0;
196 pub const LIGHT_ENGINE_WARMUP: u8 = 1;
199 pub const LIGHT_ENGINE_COOLDOWN: u8 = 2;
201 pub const LIGHT_ENGINE_EMERGENCY_STOP: u8 = 3;
204
205 pub const PLAYBACK_IDLE: u8 = 0;
212 pub const PLAYBACK_PREPARED: u8 = 1;
216 pub const PLAYBACK_PLAYING: u8 = 2;
218
219 pub const SOURCE_NETWORK_STREAMING: u8 = 0;
221 pub const SOURCE_ILDA_PLAYBACK_SD: u8 = 1;
223 pub const SOURCE_INTERNAL_ABSTRACT_GENERATOR: u8 = 2;
225}
226
227impl DacResponse {
228 pub const ACK: u8 = 0x61;
230 pub const NAK_FULL: u8 = 0x46;
233 pub const NAK_INVALID: u8 = 0x49;
235 pub const NAK_STOP_CONDITION: u8 = 0x21;
237}
238
239impl WriteToBytes for DacStatus {
240 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
241 writer.write_u8(self.protocol)?;
242 writer.write_u8(self.light_engine_state)?;
243 writer.write_u8(self.playback_state)?;
244 writer.write_u8(self.source)?;
245 writer.write_u16::<LE>(self.light_engine_flags)?;
246 writer.write_u16::<LE>(self.playback_flags)?;
247 writer.write_u16::<LE>(self.source_flags)?;
248 writer.write_u16::<LE>(self.buffer_fullness)?;
249 writer.write_u32::<LE>(self.point_rate)?;
250 writer.write_u32::<LE>(self.point_count)?;
251 Ok(())
252 }
253}
254
255impl WriteToBytes for DacBroadcast {
256 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
257 for &byte in &self.mac_address {
258 writer.write_u8(byte)?;
259 }
260 writer.write_u16::<LE>(self.hw_revision)?;
261 writer.write_u16::<LE>(self.sw_revision)?;
262 writer.write_u16::<LE>(self.buffer_capacity)?;
263 writer.write_u32::<LE>(self.max_point_rate)?;
264 writer.write_bytes(&self.dac_status)?;
265 Ok(())
266 }
267}
268
269impl WriteToBytes for DacPoint {
270 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
271 writer.write_u16::<LE>(self.control)?;
272 writer.write_i16::<LE>(self.x)?;
273 writer.write_i16::<LE>(self.y)?;
274 writer.write_u16::<LE>(self.r)?;
275 writer.write_u16::<LE>(self.g)?;
276 writer.write_u16::<LE>(self.b)?;
277 writer.write_u16::<LE>(self.i)?;
278 writer.write_u16::<LE>(self.u1)?;
279 writer.write_u16::<LE>(self.u2)?;
280 Ok(())
281 }
282}
283
284impl WriteToBytes for DacResponse {
285 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
286 writer.write_u8(self.response)?;
287 writer.write_u8(self.command)?;
288 writer.write_bytes(&self.dac_status)?;
289 Ok(())
290 }
291}
292
293impl ReadFromBytes for DacStatus {
294 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
295 let protocol = reader.read_u8()?;
296 let light_engine_state = reader.read_u8()?;
297 let playback_state = reader.read_u8()?;
298 let source = reader.read_u8()?;
299 let light_engine_flags = reader.read_u16::<LE>()?;
300 let playback_flags = reader.read_u16::<LE>()?;
301 let source_flags = reader.read_u16::<LE>()?;
302 let buffer_fullness = reader.read_u16::<LE>()?;
303 let point_rate = reader.read_u32::<LE>()?;
304 let point_count = reader.read_u32::<LE>()?;
305 let dac_status = DacStatus {
306 protocol,
307 light_engine_state,
308 playback_state,
309 source,
310 light_engine_flags,
311 playback_flags,
312 source_flags,
313 buffer_fullness,
314 point_rate,
315 point_count,
316 };
317 Ok(dac_status)
318 }
319}
320
321impl ReadFromBytes for DacBroadcast {
322 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
323 let mac_address = [
324 reader.read_u8()?,
325 reader.read_u8()?,
326 reader.read_u8()?,
327 reader.read_u8()?,
328 reader.read_u8()?,
329 reader.read_u8()?,
330 ];
331 let hw_revision = reader.read_u16::<LE>()?;
332 let sw_revision = reader.read_u16::<LE>()?;
333 let buffer_capacity = reader.read_u16::<LE>()?;
334 let max_point_rate = reader.read_u32::<LE>()?;
335 let dac_status = reader.read_bytes::<DacStatus>()?;
336 let dac_broadcast = DacBroadcast {
337 mac_address,
338 hw_revision,
339 sw_revision,
340 buffer_capacity,
341 max_point_rate,
342 dac_status,
343 };
344 Ok(dac_broadcast)
345 }
346}
347
348impl ReadFromBytes for DacPoint {
349 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
350 let control = reader.read_u16::<LE>()?;
351 let x = reader.read_i16::<LE>()?;
352 let y = reader.read_i16::<LE>()?;
353 let r = reader.read_u16::<LE>()?;
354 let g = reader.read_u16::<LE>()?;
355 let b = reader.read_u16::<LE>()?;
356 let i = reader.read_u16::<LE>()?;
357 let u1 = reader.read_u16::<LE>()?;
358 let u2 = reader.read_u16::<LE>()?;
359 let dac_point = DacPoint {
360 control,
361 x,
362 y,
363 i,
364 r,
365 g,
366 b,
367 u1,
368 u2,
369 };
370 Ok(dac_point)
371 }
372}
373
374impl ReadFromBytes for DacResponse {
375 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
376 let response = reader.read_u8()?;
377 let command = reader.read_u8()?;
378 let dac_status = reader.read_bytes::<DacStatus>()?;
379 let dac_response = DacResponse {
380 response,
381 command,
382 dac_status,
383 };
384 Ok(dac_response)
385 }
386}
387
388impl SizeBytes for DacStatus {
389 const SIZE_BYTES: usize = 20;
390}
391
392impl SizeBytes for DacBroadcast {
393 const SIZE_BYTES: usize = DacStatus::SIZE_BYTES + 16;
394}
395
396impl SizeBytes for DacPoint {
397 const SIZE_BYTES: usize = 18;
398}
399
400impl SizeBytes for DacResponse {
401 const SIZE_BYTES: usize = DacStatus::SIZE_BYTES + 2;
402}
403
404impl<'a, P> WriteToBytes for &'a P
405where
406 P: WriteToBytes,
407{
408 fn write_to_bytes<W: WriteBytesExt>(&self, writer: W) -> io::Result<()> {
409 (*self).write_to_bytes(writer)
410 }
411}
412
413impl<W> WriteBytes for W
414where
415 W: WriteBytesExt,
416{
417 fn write_bytes<P: WriteToBytes>(&mut self, protocol: P) -> io::Result<()> {
418 protocol.write_to_bytes(self)
419 }
420}
421
422impl<R> ReadBytes for R
423where
424 R: ReadBytesExt,
425{
426 fn read_bytes<P: ReadFromBytes>(&mut self) -> io::Result<P> {
427 P::read_from_bytes(self)
428 }
429}
430
431pub mod command {
435 use super::{DacPoint, ReadBytes, ReadFromBytes, SizeBytes, WriteBytes, WriteToBytes};
436 use byteorder::{ReadBytesExt, WriteBytesExt, LE};
437 use std::borrow::Cow;
438 use std::{self, io};
439
440 pub trait Command {
442 const START_BYTE: u8;
444 fn start_byte(&self) -> u8 {
446 Self::START_BYTE
447 }
448 }
449
450 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
456 pub struct PrepareStream;
457
458 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
465 pub struct Begin {
466 pub low_water_mark: u16,
468 pub point_rate: u32,
470 }
471
472 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
483 pub struct PointRate(pub u32);
484
485 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
493 pub struct Data<'a> {
494 pub points: Cow<'a, [DacPoint]>,
495 }
496
497 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
503 pub struct Stop;
504
505 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
512 pub struct EmergencyStop;
513
514 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
521 pub struct EmergencyStopAlt;
522
523 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
533 pub struct ClearEmergencyStop;
534
535 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
539 pub struct Ping;
540
541 impl Begin {
542 pub fn read_fields<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
547 let low_water_mark = reader.read_u16::<LE>()?;
548 let point_rate = reader.read_u32::<LE>()?;
549 let begin = Begin {
550 low_water_mark,
551 point_rate,
552 };
553 Ok(begin)
554 }
555 }
556
557 impl PointRate {
558 pub fn read_fields<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
563 let point_rate = PointRate(reader.read_u32::<LE>()?);
564 Ok(point_rate)
565 }
566 }
567
568 impl<'a> Data<'a> {
569 pub fn read_n_points<R>(mut reader: R) -> io::Result<u16>
577 where
578 R: ReadBytesExt,
579 {
580 reader.read_u16::<LE>()
581 }
582
583 pub fn read_points<R>(
592 mut reader: R,
593 mut n_points: u16,
594 points: &mut Vec<DacPoint>,
595 ) -> io::Result<()>
596 where
597 R: ReadBytesExt,
598 {
599 while n_points > 0 {
600 let dac_point = reader.read_bytes::<DacPoint>()?;
601 points.push(dac_point);
602 n_points -= 1;
603 }
604 Ok(())
605 }
606 }
607
608 impl Data<'static> {
609 pub fn read_fields<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
614 let n_points = Self::read_n_points(&mut reader)?;
615 let mut data = Vec::with_capacity(n_points as _);
616 Self::read_points(reader, n_points, &mut data)?;
617 let data = Data {
618 points: Cow::Owned(data),
619 };
620 Ok(data)
621 }
622 }
623
624 impl<'a, C> Command for &'a C
625 where
626 C: Command,
627 {
628 const START_BYTE: u8 = C::START_BYTE;
629 }
630
631 impl Command for PrepareStream {
632 const START_BYTE: u8 = 0x70;
633 }
634
635 impl Command for Begin {
636 const START_BYTE: u8 = 0x62;
637 }
638
639 impl Command for PointRate {
640 const START_BYTE: u8 = 0x74;
641 }
642
643 impl<'a> Command for Data<'a> {
644 const START_BYTE: u8 = 0x64;
645 }
646
647 impl Command for Stop {
648 const START_BYTE: u8 = 0x73;
649 }
650
651 impl Command for EmergencyStop {
652 const START_BYTE: u8 = 0x00;
653 }
654
655 impl Command for EmergencyStopAlt {
656 const START_BYTE: u8 = 0xff;
657 }
658
659 impl Command for ClearEmergencyStop {
660 const START_BYTE: u8 = 0x63;
661 }
662
663 impl Command for Ping {
664 const START_BYTE: u8 = 0x3f;
665 }
666
667 impl SizeBytes for PrepareStream {
668 const SIZE_BYTES: usize = 1;
669 }
670
671 impl SizeBytes for Begin {
672 const SIZE_BYTES: usize = 7;
673 }
674
675 impl SizeBytes for PointRate {
676 const SIZE_BYTES: usize = 5;
677 }
678
679 impl SizeBytes for Stop {
680 const SIZE_BYTES: usize = 1;
681 }
682
683 impl SizeBytes for EmergencyStop {
684 const SIZE_BYTES: usize = 1;
685 }
686
687 impl SizeBytes for ClearEmergencyStop {
688 const SIZE_BYTES: usize = 1;
689 }
690
691 impl SizeBytes for Ping {
692 const SIZE_BYTES: usize = 1;
693 }
694
695 impl WriteToBytes for PrepareStream {
696 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
697 writer.write_u8(Self::START_BYTE)?;
698 Ok(())
699 }
700 }
701
702 impl WriteToBytes for Begin {
703 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
704 writer.write_u8(Self::START_BYTE)?;
705 writer.write_u16::<LE>(self.low_water_mark)?;
706 writer.write_u32::<LE>(self.point_rate)?;
707 Ok(())
708 }
709 }
710
711 impl WriteToBytes for PointRate {
712 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
713 writer.write_u8(Self::START_BYTE)?;
714 writer.write_u32::<LE>(self.0)?;
715 Ok(())
716 }
717 }
718
719 impl<'a> WriteToBytes for Data<'a> {
720 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
721 if self.points.len() > std::u16::MAX as usize {
722 let err_msg = "the number of points exceeds the maximum possible `u16` value";
723 return Err(io::Error::new(io::ErrorKind::InvalidData, err_msg));
724 }
725 writer.write_u8(Self::START_BYTE)?;
726 writer.write_u16::<LE>(self.points.len() as u16)?;
727 for point in self.points.iter() {
728 writer.write_bytes(point)?;
729 }
730 Ok(())
731 }
732 }
733
734 impl WriteToBytes for Stop {
735 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
736 writer.write_u8(Self::START_BYTE)?;
737 Ok(())
738 }
739 }
740
741 impl WriteToBytes for EmergencyStop {
742 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
743 writer.write_u8(Self::START_BYTE)?;
744 Ok(())
745 }
746 }
747
748 impl WriteToBytes for EmergencyStopAlt {
749 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
750 writer.write_u8(Self::START_BYTE)?;
751 Ok(())
752 }
753 }
754
755 impl WriteToBytes for ClearEmergencyStop {
756 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
757 writer.write_u8(Self::START_BYTE)?;
758 Ok(())
759 }
760 }
761
762 impl WriteToBytes for Ping {
763 fn write_to_bytes<W: WriteBytesExt>(&self, mut writer: W) -> io::Result<()> {
764 writer.write_u8(Self::START_BYTE)?;
765 Ok(())
766 }
767 }
768
769 impl ReadFromBytes for PrepareStream {
770 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
771 let command = reader.read_u8()?;
772 if command != Self::START_BYTE {
773 let err_msg = "invalid \"prepare stream\" command byte";
774 return Err(io::Error::new(io::ErrorKind::InvalidData, err_msg));
775 }
776 Ok(PrepareStream)
777 }
778 }
779
780 impl ReadFromBytes for Begin {
781 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
782 if reader.read_u8()? != Self::START_BYTE {
783 let err_msg = "invalid \"begin\" command byte";
784 return Err(io::Error::new(io::ErrorKind::InvalidData, err_msg));
785 }
786 Self::read_fields(reader)
787 }
788 }
789
790 impl ReadFromBytes for PointRate {
791 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
792 if reader.read_u8()? != Self::START_BYTE {
793 let err_msg = "invalid \"queue change\" command byte";
794 return Err(io::Error::new(io::ErrorKind::InvalidData, err_msg));
795 }
796 Self::read_fields(reader)
797 }
798 }
799
800 impl ReadFromBytes for Data<'static> {
801 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
802 if reader.read_u8()? != Self::START_BYTE {
803 let err_msg = "invalid \"data\" command byte";
804 return Err(io::Error::new(io::ErrorKind::InvalidData, err_msg));
805 }
806 Self::read_fields(reader)
807 }
808 }
809
810 impl ReadFromBytes for Stop {
811 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
812 let command = reader.read_u8()?;
813 if command != Self::START_BYTE {
814 let err_msg = "invalid \"stop\" command byte";
815 return Err(io::Error::new(io::ErrorKind::InvalidData, err_msg));
816 }
817 Ok(Stop)
818 }
819 }
820
821 impl ReadFromBytes for EmergencyStop {
822 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
823 let command = reader.read_u8()?;
824 if command != Self::START_BYTE && command != EmergencyStopAlt::START_BYTE {
825 let err_msg = "invalid \"emergency stop\" command byte";
826 return Err(io::Error::new(io::ErrorKind::InvalidData, err_msg));
827 }
828 Ok(EmergencyStop)
829 }
830 }
831
832 impl ReadFromBytes for ClearEmergencyStop {
833 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
834 let command = reader.read_u8()?;
835 if command != Self::START_BYTE {
836 let err_msg = "invalid \"clear emergency stop\" command byte";
837 return Err(io::Error::new(io::ErrorKind::InvalidData, err_msg));
838 }
839 Ok(ClearEmergencyStop)
840 }
841 }
842
843 impl ReadFromBytes for Ping {
844 fn read_from_bytes<R: ReadBytesExt>(mut reader: R) -> io::Result<Self> {
845 let command = reader.read_u8()?;
846 if command != Self::START_BYTE {
847 let err_msg = "invalid \"ping\" command byte";
848 return Err(io::Error::new(io::ErrorKind::InvalidData, err_msg));
849 }
850 Ok(Ping)
851 }
852 }
853}