1use std::error::Error;
2use std::mem;
3
4use log::{debug, info, warn};
5
6use flipdot_core::{Address, ChunkCount, Message, Offset, Operation, Page, PageFlipStyle, SignBus, SignType, State};
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash)]
43pub struct VirtualSignBus<'a> {
44 signs: Vec<VirtualSign<'a>>,
45}
46
47impl<'a> VirtualSignBus<'a> {
48 pub fn new<I>(signs: I) -> Self
66 where
67 I: IntoIterator<Item = VirtualSign<'a>>,
68 {
69 VirtualSignBus {
70 signs: signs.into_iter().collect(),
71 }
72 }
73
74 pub fn sign(&self, index: usize) -> &VirtualSign<'a> {
89 &self.signs[index]
90 }
91}
92
93impl SignBus for VirtualSignBus<'_> {
94 fn process_message<'a>(&mut self, message: Message<'_>) -> Result<Option<Message<'a>>, Box<dyn Error + Send + Sync>> {
96 debug!("Bus message: {}", message);
97 for sign in &mut self.signs {
98 let response = sign.process_message(&message);
99 if let Some(response_message) = response {
100 debug!(" Vsign {:04X}: {}", sign.address().0, response_message);
101 return Ok(Some(response_message));
102 }
103 }
104 Ok(None)
105 }
106}
107
108#[derive(Debug, Clone, PartialEq, Eq, Hash)]
118pub struct VirtualSign<'a> {
119 address: Address,
120 flip_style: PageFlipStyle,
121 state: State,
122 pages: Vec<Page<'a>>,
123 pending_data: Vec<u8>,
124 data_chunks: u16,
125 width: u32,
126 height: u32,
127 sign_type: Option<SignType>,
128}
129
130impl VirtualSign<'_> {
131 pub fn new(address: Address, flip_style: PageFlipStyle) -> Self {
143 VirtualSign {
144 address,
145 flip_style,
146 state: State::Unconfigured,
147 pages: vec![],
148 pending_data: vec![],
149 data_chunks: 0,
150 width: 0,
151 height: 0,
152 sign_type: None,
153 }
154 }
155
156 pub fn address(&self) -> Address {
167 self.address
168 }
169
170 pub fn state(&self) -> State {
182 self.state
183 }
184
185 pub fn sign_type(&self) -> Option<SignType> {
200 self.sign_type
201 }
202
203 pub fn pages(&self) -> &[Page<'_>] {
216 &self.pages
217 }
218
219 pub fn process_message<'a>(&mut self, message: &Message<'_>) -> Option<Message<'a>> {
232 match *message {
233 Message::Hello(address) | Message::QueryState(address) if address == self.address => Some(self.query_state()),
234 Message::RequestOperation(address, Operation::ReceiveConfig) if address == self.address => self.receive_config(),
235 Message::SendData(offset, ref data) => self.send_data(offset, data.get()),
236 Message::DataChunksSent(chunks) => self.data_chunks_sent(chunks),
237 Message::RequestOperation(address, Operation::ReceivePixels) if address == self.address => self.receive_pixels(),
238 Message::PixelsComplete(address) if address == self.address => self.pixels_complete(),
239 Message::RequestOperation(address, Operation::ShowLoadedPage) if address == self.address => self.show_loaded_page(),
240 Message::RequestOperation(address, Operation::LoadNextPage) if address == self.address => self.load_next_page(),
241 Message::RequestOperation(address, Operation::StartReset) if address == self.address => Some(self.start_reset()),
242 Message::RequestOperation(address, Operation::FinishReset) if address == self.address => self.finish_reset(),
243 Message::Goodbye(address) if address == self.address => self.goodbye(),
244 _ => None,
245 }
246 }
247
248 fn query_state<'a>(&mut self) -> Message<'a> {
250 let state = self.state;
251
252 match state {
255 State::PageLoadInProgress => self.state = State::PageLoaded,
256 State::PageShowInProgress => self.state = State::PageShown,
257 _ => {}
258 };
259
260 Message::ReportState(self.address, state)
261 }
262
263 fn receive_config<'a>(&mut self) -> Option<Message<'a>> {
265 match self.state {
266 State::Unconfigured | State::ConfigFailed => {
267 self.state = State::ConfigInProgress;
268 Some(Message::AckOperation(self.address, Operation::ReceiveConfig))
269 }
270 _ => None,
271 }
272 }
273
274 fn send_data<'a>(&mut self, offset: Offset, data: &[u8]) -> Option<Message<'a>> {
276 if self.state == State::ConfigInProgress && offset == Offset(0) && data.len() == 16 {
277 let (kind, width, height) = match data[0] {
278 0x04 => ("Max3000", data[5..9].iter().sum(), data[4]),
279 0x08 => ("Horizon", data[7], data[5]),
280 _ => return None,
281 };
282
283 info!(
284 "Vsign {:04X} configuration: {} x {} {} sign",
285 self.address.0, width, height, kind
286 );
287
288 self.sign_type = SignType::from_bytes(data).ok();
289 match self.sign_type {
290 Some(sign_type) => info!("Vsign {:04X} matches known type: {:?}", self.address.0, sign_type),
291 None => warn!("Please report unknown configuration {:?}", data),
292 }
293
294 self.width = u32::from(width);
295 self.height = u32::from(height);
296 self.data_chunks += 1;
297 } else if self.state == State::PixelsInProgress {
298 if offset == Offset(0) {
299 self.flush_pixels();
300 }
301 self.pending_data.extend_from_slice(data);
302 self.data_chunks += 1;
303 }
304 None
305 }
306
307 fn data_chunks_sent<'a>(&mut self, chunks: ChunkCount) -> Option<Message<'a>> {
309 if ChunkCount(self.data_chunks) == chunks {
310 match self.state {
311 State::ConfigInProgress => self.state = State::ConfigReceived,
312 State::PixelsInProgress => self.state = State::PixelsReceived,
313 _ => {}
314 }
315 } else {
316 match self.state {
317 State::ConfigInProgress => self.state = State::ConfigFailed,
318 State::PixelsInProgress => self.state = State::PixelsFailed,
319 _ => {}
320 }
321 }
322 self.flush_pixels();
323 self.data_chunks = 0;
324 None
325 }
326
327 fn receive_pixels<'a>(&mut self) -> Option<Message<'a>> {
329 match self.state {
330 State::ConfigReceived
331 | State::PixelsFailed
332 | State::PageLoaded
333 | State::PageLoadInProgress
334 | State::PageShown
335 | State::PageShowInProgress
336 | State::ShowingPages => {
337 self.state = State::PixelsInProgress;
338 self.pages.clear();
339 Some(Message::AckOperation(self.address, Operation::ReceivePixels))
340 }
341 _ => None,
342 }
343 }
344
345 fn pixels_complete<'a>(&mut self) -> Option<Message<'a>> {
347 if self.state == State::PixelsReceived {
348 self.state = match self.flip_style {
349 PageFlipStyle::Automatic => State::ShowingPages,
350 PageFlipStyle::Manual => State::PageLoaded,
351 };
352 for page in &self.pages {
353 info!(
354 "Vsign {:04X} Page {} ({} x {})\n{}",
355 self.address.0,
356 page.id(),
357 page.width(),
358 page.height(),
359 page
360 );
361 }
362 }
363 None
364 }
365
366 fn show_loaded_page<'a>(&mut self) -> Option<Message<'a>> {
368 if self.state == State::PageLoaded {
369 self.state = State::PageShowInProgress;
370 Some(Message::AckOperation(self.address, Operation::ShowLoadedPage))
371 } else {
372 None
373 }
374 }
375
376 fn load_next_page<'a>(&mut self) -> Option<Message<'a>> {
378 if self.state == State::PageShown {
379 self.state = State::PageLoadInProgress;
380 Some(Message::AckOperation(self.address, Operation::LoadNextPage))
381 } else {
382 None
383 }
384 }
385
386 fn start_reset<'a>(&mut self) -> Message<'a> {
388 self.state = State::ReadyToReset;
389 Message::AckOperation(self.address, Operation::StartReset)
390 }
391
392 fn finish_reset<'a>(&mut self) -> Option<Message<'a>> {
394 if self.state == State::ReadyToReset {
395 self.reset();
396 Some(Message::AckOperation(self.address, Operation::FinishReset))
397 } else {
398 None
399 }
400 }
401
402 fn goodbye<'a>(&mut self) -> Option<Message<'a>> {
404 self.reset();
405 None
406 }
407
408 fn flush_pixels(&mut self) {
410 if !self.pending_data.is_empty() {
411 let data = mem::take(&mut self.pending_data);
412 if self.width > 0 && self.height > 0 {
413 let page = Page::from_bytes(self.width, self.height, data).expect("Error loading page");
414 self.pages.push(page);
415 }
416 }
417 }
418
419 fn reset(&mut self) {
421 self.state = State::Unconfigured;
422 self.pages.clear();
423 self.pending_data.clear();
424 self.data_chunks = 0;
425 self.width = 0;
426 self.height = 0;
427 self.sign_type = None;
428 }
429}
430
431#[cfg(test)]
432mod tests {
433 use super::*;
434 use flipdot_core::{Data, PageId};
435 use test_case::test_case;
436
437 #[test_case(PageFlipStyle::Automatic ; "automatic page flip")]
438 #[test_case(PageFlipStyle::Manual ; "manual page flip")]
439 fn normal_behavior(flip_style: PageFlipStyle) {
440 let mut page1 = Page::new(PageId(0), 90, 7);
441 for x in 0..page1.width() {
442 for y in 0..page1.height() {
443 page1.set_pixel(x, y, x % 2 == y % 2);
444 }
445 }
446
447 let mut page2 = Page::new(PageId(1), 90, 7);
448 for x in 0..page2.width() {
449 for y in 0..page2.height() {
450 page2.set_pixel(x, y, x % 2 != y % 2);
451 }
452 }
453
454 let mut sign = VirtualSign::new(Address(3), flip_style);
456 assert_eq!(Address(3), sign.address());
457 assert_eq!(None, sign.sign_type());
458 assert_eq!(0, sign.pages().len());
459 assert_eq!(0, sign.width);
460 assert_eq!(0, sign.height);
461
462 let response = sign.process_message(&Message::Hello(Address(3)));
464 assert_eq!(Some(Message::ReportState(Address(3), State::Unconfigured)), response);
465
466 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceiveConfig));
467 assert_eq!(Some(Message::AckOperation(Address(3), Operation::ReceiveConfig)), response);
468
469 let response = sign.process_message(&Message::QueryState(Address(3)));
470 assert_eq!(Some(Message::ReportState(Address(3), State::ConfigInProgress)), response);
471
472 let response = sign.process_message(&Message::SendData(
473 Offset(0x00),
474 Data::try_new(SignType::Max3000Side90x7.to_bytes()).unwrap(),
475 ));
476 assert_eq!(None, response);
477
478 let response = sign.process_message(&Message::QueryState(Address(3)));
479 assert_eq!(Some(Message::ReportState(Address(3), State::ConfigInProgress)), response);
480
481 let response = sign.process_message(&Message::DataChunksSent(ChunkCount(1)));
482 assert_eq!(None, response);
483
484 let response = sign.process_message(&Message::QueryState(Address(3)));
485 assert_eq!(Some(Message::ReportState(Address(3), State::ConfigReceived)), response);
486
487 assert_eq!(Some(SignType::Max3000Side90x7), sign.sign_type());
488 assert_eq!(90, sign.width);
489 assert_eq!(7, sign.height);
490
491 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceivePixels));
492 assert_eq!(Some(Message::AckOperation(Address(3), Operation::ReceivePixels)), response);
493
494 assert_eq!(0, sign.pages().len());
496
497 let mut chunks_sent = 0;
498 for (i, chunk) in page1.as_bytes().chunks(16).enumerate() {
499 let response = sign.process_message(&Message::QueryState(Address(3)));
500 assert_eq!(Some(Message::ReportState(Address(3), State::PixelsInProgress)), response);
501
502 let response = sign.process_message(&Message::SendData(Offset((i * 16) as u16), Data::try_new(chunk).unwrap()));
503 assert_eq!(None, response);
504
505 chunks_sent += 1;
506 }
507
508 let response = sign.process_message(&Message::QueryState(Address(3)));
509 assert_eq!(Some(Message::ReportState(Address(3), State::PixelsInProgress)), response);
510
511 let response = sign.process_message(&Message::DataChunksSent(ChunkCount(chunks_sent)));
512 assert_eq!(None, response);
513
514 let response = sign.process_message(&Message::QueryState(Address(3)));
515 assert_eq!(Some(Message::ReportState(Address(3), State::PixelsReceived)), response);
516
517 let response = sign.process_message(&Message::PixelsComplete(Address(3)));
518 assert_eq!(None, response);
519
520 assert_eq!(&[page1], sign.pages());
521
522 let response = sign.process_message(&Message::QueryState(Address(3)));
523
524 match flip_style {
525 PageFlipStyle::Automatic => {
526 assert_eq!(Some(Message::ReportState(Address(3), State::ShowingPages)), response);
527 }
528
529 PageFlipStyle::Manual => {
530 assert_eq!(Some(Message::ReportState(Address(3), State::PageLoaded)), response);
531
532 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ShowLoadedPage));
534 assert_eq!(Some(Message::AckOperation(Address(3), Operation::ShowLoadedPage)), response);
535
536 let response = sign.process_message(&Message::QueryState(Address(3)));
537 assert_eq!(Some(Message::ReportState(Address(3), State::PageShowInProgress)), response);
538
539 let response = sign.process_message(&Message::QueryState(Address(3)));
540 assert_eq!(Some(Message::ReportState(Address(3), State::PageShown)), response);
541
542 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::LoadNextPage));
544 assert_eq!(Some(Message::AckOperation(Address(3), Operation::LoadNextPage)), response);
545
546 let response = sign.process_message(&Message::QueryState(Address(3)));
547 assert_eq!(Some(Message::ReportState(Address(3), State::PageLoadInProgress)), response);
548
549 let response = sign.process_message(&Message::QueryState(Address(3)));
550 assert_eq!(Some(Message::ReportState(Address(3), State::PageLoaded)), response);
551 }
552 }
553
554 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceivePixels));
556 assert_eq!(Some(Message::AckOperation(Address(3), Operation::ReceivePixels)), response);
557
558 assert_eq!(0, sign.pages().len());
559
560 let mut chunks_sent = 0;
561 for (i, chunk) in page2.as_bytes().chunks(16).enumerate() {
562 let response = sign.process_message(&Message::QueryState(Address(3)));
563 assert_eq!(Some(Message::ReportState(Address(3), State::PixelsInProgress)), response);
564
565 let response = sign.process_message(&Message::SendData(Offset((i * 16) as u16), Data::try_new(chunk).unwrap()));
566 assert_eq!(None, response);
567
568 chunks_sent += 1;
569 }
570
571 let response = sign.process_message(&Message::QueryState(Address(3)));
572 assert_eq!(Some(Message::ReportState(Address(3), State::PixelsInProgress)), response);
573
574 let response = sign.process_message(&Message::DataChunksSent(ChunkCount(chunks_sent)));
575 assert_eq!(None, response);
576
577 let response = sign.process_message(&Message::QueryState(Address(3)));
578 assert_eq!(Some(Message::ReportState(Address(3), State::PixelsReceived)), response);
579
580 let response = sign.process_message(&Message::PixelsComplete(Address(3)));
581 assert_eq!(None, response);
582
583 assert_eq!(&[page2], sign.pages());
584
585 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::StartReset));
587 assert_eq!(Some(Message::AckOperation(Address(3), Operation::StartReset)), response);
588
589 let response = sign.process_message(&Message::Hello(Address(3)));
590 assert_eq!(Some(Message::ReportState(Address(3), State::ReadyToReset)), response);
591
592 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::FinishReset));
593 assert_eq!(Some(Message::AckOperation(Address(3), Operation::FinishReset)), response);
594
595 let response = sign.process_message(&Message::Hello(Address(3)));
596 assert_eq!(Some(Message::ReportState(Address(3), State::Unconfigured)), response);
597
598 assert_eq!(Address(3), sign.address());
599 assert_eq!(None, sign.sign_type());
600 assert_eq!(0, sign.pages().len());
601 assert_eq!(0, sign.width);
602 assert_eq!(0, sign.height);
603
604 let response = sign.process_message(&Message::Hello(Address(3)));
606 assert_eq!(Some(Message::ReportState(Address(3), State::Unconfigured)), response);
607
608 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceiveConfig));
609 assert_eq!(Some(Message::AckOperation(Address(3), Operation::ReceiveConfig)), response);
610
611 let response = sign.process_message(&Message::QueryState(Address(3)));
612 assert_eq!(Some(Message::ReportState(Address(3), State::ConfigInProgress)), response);
613
614 let response = sign.process_message(&Message::SendData(
615 Offset(0x00),
616 Data::try_new(SignType::Max3000Side90x7.to_bytes()).unwrap(),
617 ));
618 assert_eq!(None, response);
619
620 let response = sign.process_message(&Message::QueryState(Address(3)));
621 assert_eq!(Some(Message::ReportState(Address(3), State::ConfigInProgress)), response);
622
623 let response = sign.process_message(&Message::DataChunksSent(ChunkCount(1)));
624 assert_eq!(None, response);
625
626 let response = sign.process_message(&Message::QueryState(Address(3)));
627 assert_eq!(Some(Message::ReportState(Address(3), State::ConfigReceived)), response);
628
629 assert_eq!(Some(SignType::Max3000Side90x7), sign.sign_type());
630 assert_eq!(90, sign.width);
631 assert_eq!(7, sign.height);
632
633 let response = sign.process_message(&Message::Goodbye(Address(3)));
635 assert_eq!(None, response);
636
637 assert_eq!(None, sign.sign_type());
638 assert_eq!(0, sign.pages().len());
639 assert_eq!(0, sign.width);
640 assert_eq!(0, sign.height);
641
642 let response = sign.process_message(&Message::Hello(Address(3)));
643 assert_eq!(Some(Message::ReportState(Address(3), State::Unconfigured)), response);
644 }
645
646 #[test]
647 fn invalid_operations() {
648 let mut sign = VirtualSign::new(Address(3), PageFlipStyle::Manual);
649
650 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceivePixels));
651 assert_eq!(None, response);
652
653 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ShowLoadedPage));
654 assert_eq!(None, response);
655
656 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::LoadNextPage));
657 assert_eq!(None, response);
658
659 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::FinishReset));
660 assert_eq!(None, response);
661
662 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceiveConfig));
663 assert_eq!(Some(Message::AckOperation(Address(3), Operation::ReceiveConfig)), response);
664
665 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceiveConfig));
666 assert_eq!(None, response);
667 }
668
669 #[test]
670 fn unknown_config() {
671 let mut sign = VirtualSign::new(Address(3), PageFlipStyle::Manual);
672
673 let response = sign.process_message(&Message::Hello(Address(3)));
674 assert_eq!(Some(Message::ReportState(Address(3), State::Unconfigured)), response);
675
676 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceiveConfig));
677 assert_eq!(Some(Message::AckOperation(Address(3), Operation::ReceiveConfig)), response);
678
679 let response = sign.process_message(&Message::QueryState(Address(3)));
680 assert_eq!(Some(Message::ReportState(Address(3), State::ConfigInProgress)), response);
681
682 let data = vec![
683 0x04, 0x99, 0x00, 0x0F, 0x09, 0x1C, 0x1C, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
684 ];
685 let response = sign.process_message(&Message::SendData(Offset(0x00), Data::try_new(data).unwrap()));
686 assert_eq!(None, response);
687
688 let response = sign.process_message(&Message::DataChunksSent(ChunkCount(1)));
689 assert_eq!(None, response);
690
691 let response = sign.process_message(&Message::QueryState(Address(3)));
692 assert_eq!(Some(Message::ReportState(Address(3), State::ConfigReceived)), response);
693
694 assert_eq!(None, sign.sign_type());
695 assert_eq!(56, sign.width);
696 assert_eq!(9, sign.height);
697 }
698
699 #[test]
700 fn invalid_config() {
701 let mut sign = VirtualSign::new(Address(3), PageFlipStyle::Manual);
702
703 let response = sign.process_message(&Message::Hello(Address(3)));
704 assert_eq!(Some(Message::ReportState(Address(3), State::Unconfigured)), response);
705
706 let response = sign.process_message(&Message::RequestOperation(Address(3), Operation::ReceiveConfig));
707 assert_eq!(Some(Message::AckOperation(Address(3), Operation::ReceiveConfig)), response);
708
709 let response = sign.process_message(&Message::QueryState(Address(3)));
710 assert_eq!(Some(Message::ReportState(Address(3), State::ConfigInProgress)), response);
711
712 let data = vec![
713 0x0F, 0x99, 0x00, 0x0F, 0x09, 0x1C, 0x1C, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
714 ];
715 let response = sign.process_message(&Message::SendData(Offset(0x00), Data::try_new(data).unwrap()));
716 assert_eq!(None, response);
717
718 let response = sign.process_message(&Message::DataChunksSent(ChunkCount(1)));
719 assert_eq!(None, response);
720
721 let response = sign.process_message(&Message::QueryState(Address(3)));
722 assert_eq!(Some(Message::ReportState(Address(3), State::ConfigFailed)), response);
723
724 assert_eq!(None, sign.sign_type());
725 assert_eq!(0, sign.width);
726 assert_eq!(0, sign.height);
727 }
728}