1#![allow(dead_code)]
2
3use core::time::Duration;
4
5use cc_talk_core::cc_talk::{
6 BillRouteCode, BillRoutingError, BillValidatorPollResult, BillValidatorPollResultError,
7 BitMask, BitMaskError, ChangerDevice, ChangerError, ChangerFlags, ChangerPollResult,
8 CoinAcceptorPollResult, CurrencyToken, CurrencyTokenError, EscrowFaultCode, EscrowLevelStatus,
9 EscrowOperatingStatus, EscrowServiceStatus, Fault, FaultCode, FirmwareStorageType, Header,
10 HopperDispenseStatus, HopperDispenseValueStatus, HopperFlag, HopperStatus, LampControl,
11 PowerOption, RequestOptionFlags, SorterPath, StackerCycleError, TeachModeStatus,
12 parse_changer_flags_heapless,
13};
14
15use crate::commands::command::{Command, ParseResponseError};
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum PollingUnit {
19 Special = 0,
20 Ms = 1,
21 X10Ms = 2,
22 Seconds = 3,
23 Minutes = 4,
24 Hours = 5,
25 Days = 6,
26 Weeks = 7,
27 Months = 8,
28 Years = 9,
29}
30#[derive(Debug)]
31pub struct PollingPriority {
32 pub unit: PollingUnit,
33 pub value: u8,
34}
35
36impl PollingPriority {
37 pub fn as_duration(&self) -> Option<Duration> {
38 let value = self.value as u64;
39
40 let duration = match self.unit {
41 PollingUnit::Special => {
42 return None;
43 }
44 PollingUnit::Ms => Duration::from_millis(value),
45 PollingUnit::X10Ms => Duration::from_millis(value * 10),
46 PollingUnit::Seconds => Duration::from_secs(value),
47 PollingUnit::Minutes => Duration::from_secs(value * 60),
48 PollingUnit::Hours => Duration::from_secs(value * 3600),
49 PollingUnit::Days => Duration::from_secs(value * 86400),
50 PollingUnit::Weeks => Duration::from_secs(value * 604800),
51 PollingUnit::Months => Duration::from_secs(value * 2629746), PollingUnit::Years => Duration::from_secs(value * 31556952), };
54 Some(duration)
55 }
56}
57
58#[derive(Debug)]
59pub struct RequestPollingPriorityCommand;
60impl Command for RequestPollingPriorityCommand {
61 type Response = PollingPriority;
62
63 fn header(&self) -> Header {
64 Header::RequestPollingPriority
65 }
66
67 fn data(&self) -> &[u8] {
68 &[]
69 }
70
71 fn parse_response(
72 &self,
73 response_payload: &[u8],
74 ) -> Result<Self::Response, ParseResponseError> {
75 match response_payload.len() {
76 2 => {
77 let unit = match response_payload[0] {
78 0 => PollingUnit::Special,
79 1 => PollingUnit::Ms,
80 2 => PollingUnit::X10Ms,
81 3 => PollingUnit::Seconds,
82 4 => PollingUnit::Minutes,
83 5 => PollingUnit::Hours,
84 6 => PollingUnit::Days,
85 7 => PollingUnit::Weeks,
86 8 => PollingUnit::Months,
87 9 => PollingUnit::Years,
88 _ => return Err(ParseResponseError::ParseError("Invalid polling unit")),
89 };
90 Ok(PollingPriority {
91 unit,
92 value: response_payload[1],
93 })
94 }
95 _ => Err(ParseResponseError::DataLengthMismatch(
96 2,
97 response_payload.len(),
98 )),
99 }
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq)]
104pub enum CoinAcceptorStatus {
105 Ok = 0,
106 CoinReturnMechanismActivated = 1,
107 CoinOnString = 2,
108}
109
110#[derive(Debug)]
111pub struct RequestStatusCommand;
112impl Command for RequestStatusCommand {
113 type Response = CoinAcceptorStatus;
114
115 fn header(&self) -> Header {
116 Header::RequestStatus
117 }
118
119 fn data(&self) -> &[u8] {
120 &[]
121 }
122
123 fn parse_response(
124 &self,
125 response_payload: &[u8],
126 ) -> Result<Self::Response, ParseResponseError> {
127 match response_payload.len() {
128 1 => match response_payload[0] {
129 0 => Ok(CoinAcceptorStatus::Ok),
130 1 => Ok(CoinAcceptorStatus::CoinReturnMechanismActivated),
131 2 => Ok(CoinAcceptorStatus::CoinOnString),
132 _ => Err(ParseResponseError::ParseError("Invalid status")),
133 },
134 _ => Err(ParseResponseError::DataLengthMismatch(
135 1,
136 response_payload.len(),
137 )),
138 }
139 }
140}
141
142#[derive(Debug)]
143pub struct RequestVariableSetCommand;
144impl Command for RequestVariableSetCommand {
145 type Response = ();
146
147 fn header(&self) -> Header {
148 Header::RequestVariableSet
149 }
150
151 fn data(&self) -> &[u8] {
152 &[]
153 }
154
155 fn parse_response(&self, _: &[u8]) -> Result<Self::Response, ParseResponseError> {
157 Ok(())
158 }
159}
160
161#[derive(Debug)]
162pub struct RequestDatabaseVersionCommand;
163impl Command for RequestDatabaseVersionCommand {
164 type Response = u8;
165
166 fn header(&self) -> Header {
167 Header::RequestDatabaseVersion
168 }
169
170 fn data(&self) -> &[u8] {
171 &[]
172 }
173
174 fn parse_response(
175 &self,
176 response_payload: &[u8],
177 ) -> Result<Self::Response, ParseResponseError> {
178 match response_payload.len() {
179 1 => Ok(response_payload[0]),
180 _ => Err(ParseResponseError::DataLengthMismatch(
181 1,
182 response_payload.len(),
183 )),
184 }
185 }
186}
187
188#[derive(Debug, Clone, Copy, PartialEq, Eq)]
189pub struct TestSolenoidsCommand {
190 buffer: u8, }
192impl TestSolenoidsCommand {
193 pub fn new(bitmask: u8) -> Self {
195 TestSolenoidsCommand { buffer: bitmask }
196 }
197}
198impl Command for TestSolenoidsCommand {
199 type Response = ();
200
201 fn header(&self) -> Header {
202 Header::TestSolenoids
203 }
204
205 fn data(&self) -> &[u8] {
206 core::slice::from_ref(&self.buffer)
207 }
208
209 fn parse_response(&self, _: &[u8]) -> Result<Self::Response, ParseResponseError> {
211 Ok(())
212 }
213}
214
215#[derive(Debug, Clone, Copy, PartialEq, Eq)]
216pub struct OperateMotorsCommand {
217 buffer: u8,
218}
219impl OperateMotorsCommand {
220 pub fn new(bitmask: u8) -> Self {
222 OperateMotorsCommand { buffer: bitmask }
223 }
224}
225impl Command for OperateMotorsCommand {
226 type Response = ();
227
228 fn header(&self) -> Header {
229 Header::OperateMotors
230 }
231
232 fn data(&self) -> &[u8] {
233 core::slice::from_ref(&self.buffer)
234 }
235
236 fn parse_response(&self, _: &[u8]) -> Result<Self::Response, ParseResponseError> {
238 Ok(())
239 }
240}
241
242#[derive(Debug, Clone, Copy, PartialEq, Eq)]
243pub struct TestOutputLinesCommand {
244 buffer: u8, }
246impl TestOutputLinesCommand {
247 pub fn new(bitmask: u8) -> Self {
249 TestOutputLinesCommand { buffer: bitmask }
250 }
251}
252impl Command for TestOutputLinesCommand {
253 type Response = ();
254
255 fn header(&self) -> Header {
256 Header::TestOutputLines
257 }
258
259 fn data(&self) -> &[u8] {
260 core::slice::from_ref(&self.buffer)
261 }
262
263 fn parse_response(&self, _: &[u8]) -> Result<Self::Response, ParseResponseError> {
265 Ok(())
266 }
267}
268
269#[derive(Debug, Clone, Copy, PartialEq, Eq)]
270pub struct ReadInputLinesCommand;
271impl Command for ReadInputLinesCommand {
272 type Response = ();
273
274 fn header(&self) -> Header {
275 Header::ReadInputLines
276 }
277
278 fn data(&self) -> &[u8] {
279 &[]
280 }
281
282 fn parse_response(&self, _: &[u8]) -> Result<Self::Response, ParseResponseError> {
284 Ok(())
285 }
286}
287
288#[derive(Debug, Clone, Copy, PartialEq, Eq)]
289pub struct ReadOptoStatesCommand;
290impl Command for ReadOptoStatesCommand {
291 type Response = u8; fn header(&self) -> Header {
294 Header::ReadOptoStates
295 }
296
297 fn data(&self) -> &[u8] {
298 &[]
299 }
300
301 fn parse_response(&self, payload: &[u8]) -> Result<Self::Response, ParseResponseError> {
303 match payload.len() {
304 1 => Ok(payload[0]),
305 2..=usize::MAX => {
306 crate::log::warning!(
307 "expected size of 1, but got {} instead. Maybe some information got lost.",
308 payload.len()
309 );
310 Ok(payload[0]) }
312 _ => Err(ParseResponseError::DataLengthMismatch(1, payload.len())),
313 }
314 }
315}
316
317#[derive(Debug, Clone, Copy, PartialEq, Eq)]
318pub struct LatchOutputLinesCommand {
319 buffer: u8,
320}
321impl Command for LatchOutputLinesCommand {
322 type Response = ();
323
324 fn header(&self) -> Header {
325 Header::LatchOutputLines
326 }
327
328 fn data(&self) -> &[u8] {
329 core::slice::from_ref(&self.buffer)
330 }
331
332 fn parse_response(&self, _: &[u8]) -> Result<Self::Response, ParseResponseError> {
334 Ok(())
335 }
336}
337
338#[derive(Debug)]
339pub struct PerformSelfCheckCommand;
340impl Command for PerformSelfCheckCommand {
341 type Response = Fault;
342
343 fn header(&self) -> Header {
344 Header::PerformSelfCheck
345 }
346
347 fn data(&self) -> &[u8] {
348 &[]
349 }
350
351 fn parse_response(&self, payload: &[u8]) -> Result<Self::Response, ParseResponseError> {
353 match payload.len() {
354 1 => {
355 let fault_code = FaultCode::try_from(payload[0])
356 .map_err(|_| ParseResponseError::ParseError("Invalid fault code"))?;
357
358 Ok(Fault::new(fault_code))
359 }
360 2 => {
361 let fault_code = FaultCode::try_from(payload[0])
362 .map_err(|_| ParseResponseError::ParseError("Invalid fault code"))?;
363 let fault_info = payload[1];
364
365 Ok(Fault::with_info(fault_code, fault_info))
366 }
367 _ => Err(ParseResponseError::DataLengthMismatch(0, payload.len())),
368 }
369 }
370}
371
372#[derive(Debug, Eq, PartialEq)]
373#[cfg_attr(feature = "defmt", derive(defmt::Format))]
374pub struct ModifyInhibitStatusCommand<const N: usize> {
375 buffer: [u8; N],
376}
377impl<const N: usize> ModifyInhibitStatusCommand<N> {
378 pub fn build(mask: BitMask<N>) -> Result<Self, BitMaskError> {
379 Ok(ModifyInhibitStatusCommand {
380 buffer: mask.to_le_bytes::<N>()?,
381 })
382 }
383}
384impl<const N: usize> Command for ModifyInhibitStatusCommand<N> {
385 type Response = ();
386
387 fn header(&self) -> Header {
388 Header::ModifyInhibitStatus
389 }
390
391 fn data(&self) -> &[u8] {
392 &self.buffer
393 }
394
395 fn parse_response(&self, payload: &[u8]) -> Result<Self::Response, ParseResponseError> {
397 if payload.is_empty() {
398 Ok(())
399 } else {
400 Err(ParseResponseError::DataLengthMismatch(0, payload.len()))
401 }
402 }
403}
404
405#[derive(Debug)]
406pub struct RequestInhibitStatusCommand<const N: usize>;
407impl<const N: usize> Command for RequestInhibitStatusCommand<N> {
408 type Response = [u8; N];
409
410 fn header(&self) -> Header {
411 Header::RequestInhibitStatus
412 }
413
414 fn data(&self) -> &[u8] {
415 &[]
416 }
417
418 fn parse_response(
419 &self,
420 response_payload: &[u8],
421 ) -> Result<Self::Response, ParseResponseError> {
422 match response_payload.len() {
423 len if len == N => Ok(response_payload.try_into().unwrap()),
424 len if len > N => {
425 crate::log::info!("unexpected response length: expected {}, got {}", N, len);
426 Ok(response_payload[0..len].try_into().unwrap())
427 }
428 _ => Err(ParseResponseError::DataLengthMismatch(
429 4,
430 response_payload.len(),
431 )),
432 }
433 }
434}
435
436#[derive(Debug, Default)]
437pub struct ReadBufferedCreditOrErrorCodeCommand {
438 last_event_counter: u8,
439}
440impl ReadBufferedCreditOrErrorCodeCommand {
441 pub fn new(last_event_counter: u8) -> Self {
442 ReadBufferedCreditOrErrorCodeCommand { last_event_counter }
443 }
444}
445impl Command for ReadBufferedCreditOrErrorCodeCommand {
446 type Response = CoinAcceptorPollResult;
447
448 fn header(&self) -> Header {
449 Header::ReadBufferedCreditOrErrorCodes
450 }
451
452 fn data(&self) -> &[u8] {
453 &[]
454 }
455
456 fn parse_response(&self, payload: &[u8]) -> Result<Self::Response, ParseResponseError> {
457 if payload.is_empty() {
458 return Err(ParseResponseError::DataLengthMismatch(1, payload.len()));
459 }
460 CoinAcceptorPollResult::try_from((payload, self.last_event_counter))
461 .map_err(|_| ParseResponseError::ParseError("Invalid coin acceptor poll result"))
462 }
463}
464
465#[derive(Debug, Eq, PartialEq)]
466#[cfg_attr(feature = "defmt", derive(defmt::Format))]
467pub struct ModifyMasterInhibitStatusCommand<const N: usize> {
468 buffer: [u8; N],
469}
470impl<const N: usize> ModifyMasterInhibitStatusCommand<N> {
471 pub fn build(mask: BitMask<N>) -> Result<Self, BitMaskError> {
472 Ok(ModifyMasterInhibitStatusCommand {
473 buffer: mask.to_le_bytes::<N>()?,
474 })
475 }
476}
477impl<const N: usize> Command for ModifyMasterInhibitStatusCommand<N> {
478 type Response = ();
479
480 fn header(&self) -> Header {
481 Header::ModifyMasterInhibitStatus
482 }
483
484 fn data(&self) -> &[u8] {
485 &self.buffer
486 }
487
488 fn parse_response(&self, payload: &[u8]) -> Result<Self::Response, ParseResponseError> {
489 if payload.is_empty() {
490 Ok(())
491 } else {
492 Err(ParseResponseError::DataLengthMismatch(0, payload.len()))
493 }
494 }
495}
496
497#[derive(Debug)]
498pub struct RequestMasterInhibitStatusCommand<const N: usize>;
499impl<const N: usize> Command for RequestMasterInhibitStatusCommand<N> {
500 type Response = [u8; N];
501
502 fn header(&self) -> Header {
503 Header::RequestMasterInhibitStatus
504 }
505
506 fn data(&self) -> &[u8] {
507 &[]
508 }
509
510 fn parse_response(
511 &self,
512 response_payload: &[u8],
513 ) -> Result<Self::Response, ParseResponseError> {
514 match response_payload.len() {
515 len if len == N => Ok(response_payload
516 .try_into()
517 .map_err(|_| ParseResponseError::ParseError("unable to map to slice"))?),
518 len if len > N => {
519 crate::log::info!("unexpected response length: expected {}, got {}", N, len);
520 Ok(response_payload[0..len]
521 .try_into()
522 .map_err(|_| ParseResponseError::ParseError("unable to map to slice"))?)
523 }
524 _ => Err(ParseResponseError::DataLengthMismatch(
525 4,
526 response_payload.len(),
527 )),
528 }
529 }
530}
531
532#[derive(Debug)]
533pub struct RequestInsertionCounterCommand;
534impl Command for RequestInsertionCounterCommand {
535 type Response = u32;
536
537 fn header(&self) -> Header {
538 Header::RequestInsertionCounter
539 }
540
541 fn data(&self) -> &[u8] {
542 &[]
543 }
544
545 fn parse_response(
546 &self,
547 response_payload: &[u8],
548 ) -> Result<Self::Response, ParseResponseError> {
549 match response_payload.len() {
550 3 => Ok(u32::from_le_bytes([
551 response_payload[0],
552 response_payload[1],
553 response_payload[2],
554 0u8,
555 ])),
556 _ => Err(ParseResponseError::DataLengthMismatch(
557 3,
558 response_payload.len(),
559 )),
560 }
561 }
562}
563
564#[derive(Debug)]
565pub struct RequestCreditCounterCommand;
566impl Command for RequestCreditCounterCommand {
567 type Response = u32;
568
569 fn header(&self) -> Header {
570 Header::RequestAcceptCounter
571 }
572
573 fn data(&self) -> &[u8] {
574 &[]
575 }
576
577 fn parse_response(
578 &self,
579 response_payload: &[u8],
580 ) -> Result<Self::Response, ParseResponseError> {
581 match response_payload.len() {
582 3 => Ok(u32::from_le_bytes([
583 response_payload[0],
584 response_payload[1],
585 response_payload[2],
586 0u8,
587 ])),
588 _ => Err(ParseResponseError::DataLengthMismatch(
589 3,
590 response_payload.len(),
591 )),
592 }
593 }
594}
595
596#[derive(Debug)]
598pub struct ModifyEncryptedInhibitAndOverrideRegistersCommand;
599
600#[derive(Debug)]
601pub struct ModifySorterOverrideStatusCommand {
602 buffer: u8,
603}
604impl ModifySorterOverrideStatusCommand {
605 pub fn build(bitmask: BitMask<1>) -> Result<Self, BitMaskError> {
606 Ok(ModifySorterOverrideStatusCommand {
607 buffer: bitmask.to_le_bytes::<1>()?[0],
608 })
609 }
610}
611impl Command for ModifySorterOverrideStatusCommand {
612 type Response = ();
613
614 fn header(&self) -> Header {
615 Header::ModifySorterOverrideStatus
616 }
617
618 fn data(&self) -> &[u8] {
619 core::slice::from_ref(&self.buffer)
620 }
621
622 fn parse_response(&self, payload: &[u8]) -> Result<Self::Response, ParseResponseError> {
623 if payload.is_empty() {
624 Ok(())
625 } else {
626 Err(ParseResponseError::DataLengthMismatch(0, payload.len()))
627 }
628 }
629}
630
631#[derive(Debug)]
632pub struct RequestSorterOverrideStatusCommand;
633impl Command for RequestSorterOverrideStatusCommand {
634 type Response = BitMask<1>;
635
636 fn header(&self) -> Header {
637 Header::RequestSorterOverrideStatus
638 }
639
640 fn data(&self) -> &[u8] {
641 &[]
642 }
643
644 fn parse_response(
645 &self,
646 response_payload: &[u8],
647 ) -> Result<Self::Response, ParseResponseError> {
648 match response_payload.len() {
649 1 => BitMask::<1>::from_le_bytes(response_payload, 8).map_err(|_| {
650 ParseResponseError::ParseError("Invalid sorter override status bitmask")
651 }),
652 _ => Err(ParseResponseError::DataLengthMismatch(
653 1,
654 response_payload.len(),
655 )),
656 }
657 }
658}
659
660#[derive(Debug)]
661pub struct EnterNewPinNumberCommand {
662 pub pin: [u8; 4],
663}
664impl Command for EnterNewPinNumberCommand {
665 type Response = ();
666
667 fn header(&self) -> Header {
668 Header::EnterNewPinNumber
669 }
670
671 fn data(&self) -> &[u8] {
672 &self.pin
673 }
674
675 fn parse_response(
676 &self,
677 response_payload: &[u8],
678 ) -> Result<Self::Response, ParseResponseError> {
679 match response_payload.len() {
680 0 => Ok(()), _ => Err(ParseResponseError::DataLengthMismatch(
682 0,
683 response_payload.len(),
684 )),
685 }
686 }
687}
688
689#[derive(Debug)]
690pub struct EnterPinNumberCommand {
691 pub pin: [u8; 4],
692}
693impl Command for EnterPinNumberCommand {
694 type Response = ();
695
696 fn header(&self) -> Header {
697 Header::EnterPinNumber
698 }
699
700 fn data(&self) -> &[u8] {
701 &self.pin
702 }
703
704 fn parse_response(
705 &self,
706 response_payload: &[u8],
707 ) -> Result<Self::Response, ParseResponseError> {
708 match response_payload.len() {
709 0 => Ok(()), _ => Err(ParseResponseError::DataLengthMismatch(
711 0,
712 response_payload.len(),
713 )),
714 }
715 }
716}
717
718#[derive(Debug)]
719pub struct RequestpayoutHighLowStatusCommand;
720impl Command for RequestpayoutHighLowStatusCommand {
721 type Response = (u8, HopperStatus);
722
723 fn header(&self) -> Header {
724 Header::RequestPayoutStatus
725 }
726
727 fn data(&self) -> &[u8] {
728 &[]
729 }
730
731 fn parse_response(&self, payload: &[u8]) -> Result<Self::Response, ParseResponseError> {
732 match payload.len() {
733 1 => Ok((0, HopperStatus::from(payload[0]))),
734 2 => Ok((payload[0], HopperStatus::from(payload[1]))),
735 _ => Err(ParseResponseError::DataLengthMismatch(1, payload.len())),
736 }
737 }
738}
739
740#[derive(Debug)]
742pub struct ReadDataBlockCommand<const N: usize> {
743 pub block_number: u8,
744}
745impl<const N: usize> Command for ReadDataBlockCommand<N> {
746 type Response = [u8; N];
747
748 fn header(&self) -> Header {
749 Header::ReadDataBlock
750 }
751
752 fn data(&self) -> &[u8] {
753 core::slice::from_ref(&self.block_number)
754 }
755
756 fn parse_response(
757 &self,
758 response_payload: &[u8],
759 ) -> Result<Self::Response, ParseResponseError> {
760 match response_payload.len() {
761 len if len == N => Ok(response_payload.try_into().unwrap()),
762 len if len > N => {
763 crate::log::info!("unexpected response length: expected {}, got {}", N, len);
764 Ok(response_payload[0..N].try_into().unwrap())
765 }
766 _ => Err(ParseResponseError::DataLengthMismatch(
767 N,
768 response_payload.len(),
769 )),
770 }
771 }
772}
773
774#[derive(Debug)]
776pub struct WriteDataBlockCommand<const N: usize> {
777 data: heapless::Vec<u8, 256>,
778}
779impl<const N: usize> WriteDataBlockCommand<N> {
780 pub fn new(block_number: u8, buffer: &[u8]) -> Result<Self, ()> {
781 if buffer.len() > N {
782 return Err(());
783 }
784
785 let mut data = heapless::Vec::new();
786 data.push(block_number).map_err(|_| ())?;
787 data.extend_from_slice(buffer).map_err(|_| ())?;
788
789 Ok(WriteDataBlockCommand { data })
790 }
791}
792impl<const N: usize> Command for WriteDataBlockCommand<N> {
793 type Response = ();
794
795 fn header(&self) -> Header {
796 Header::WriteDataBlock
797 }
798
799 fn data(&self) -> &[u8] {
800 self.data.as_slice()
801 }
802
803 fn parse_response(
804 &self,
805 response_payload: &[u8],
806 ) -> Result<Self::Response, ParseResponseError> {
807 if response_payload.is_empty() {
808 Ok(())
809 } else {
810 Err(ParseResponseError::DataLengthMismatch(
811 0,
812 response_payload.len(),
813 ))
814 }
815 }
816}
817
818#[derive(Debug)]
819pub struct RequestOptionFlagsCommand;
820impl Command for RequestOptionFlagsCommand {
821 type Response = RequestOptionFlags;
822
823 fn header(&self) -> Header {
824 Header::RequestOptionFlags
825 }
826
827 fn data(&self) -> &[u8] {
828 &[]
829 }
830
831 fn parse_response(
833 &self,
834 response_payload: &[u8],
835 ) -> Result<Self::Response, ParseResponseError> {
836 match response_payload.len() {
837 1 => Ok(RequestOptionFlags::new(response_payload[0])),
838 _ => Err(ParseResponseError::DataLengthMismatch(
839 1,
840 response_payload.len(),
841 )),
842 }
843 }
844}
845
846#[derive(Debug)]
847pub struct RequestCoinPositionCommand {
848 buffer: [u8; 1],
849}
850impl RequestCoinPositionCommand {
851 pub fn new(coin_position: u8) -> Self {
852 RequestCoinPositionCommand {
853 buffer: [coin_position],
854 }
855 }
856}
857impl Command for RequestCoinPositionCommand {
858 type Response = (u8, u8);
859
860 fn header(&self) -> Header {
861 Header::RequestCoinPosition
862 }
863
864 fn data(&self) -> &[u8] {
865 &self.buffer
866 }
867
868 fn parse_response(
869 &self,
870 response_payload: &[u8],
871 ) -> Result<Self::Response, ParseResponseError> {
872 match response_payload.len() {
873 2 => Ok((response_payload[0], response_payload[1])),
874 _ => Err(ParseResponseError::DataLengthMismatch(
875 2,
876 response_payload.len(),
877 )),
878 }
879 }
880}
881
882#[derive(Debug)]
883pub struct PowerManagementControlCommand {
884 buffer: [u8; 1],
885}
886impl PowerManagementControlCommand {
887 pub fn new(power_option: PowerOption) -> Self {
888 PowerManagementControlCommand {
889 buffer: [power_option as u8],
890 }
891 }
892}
893impl Command for PowerManagementControlCommand {
894 type Response = ();
895
896 fn header(&self) -> Header {
897 Header::PowerManagementControl
898 }
899
900 fn data(&self) -> &[u8] {
901 &self.buffer
902 }
903
904 fn parse_response(
905 &self,
906 response_payload: &[u8],
907 ) -> Result<Self::Response, ParseResponseError> {
908 if response_payload.is_empty() {
909 Ok(())
910 } else {
911 Err(ParseResponseError::DataLengthMismatch(
912 0,
913 response_payload.len(),
914 ))
915 }
916 }
917}
918
919#[derive(Debug)]
920pub struct ModifySorterPathCommand {
921 buffer: [u8; 2],
922}
923impl ModifySorterPathCommand {
924 pub fn new(coin_position: u8, sorter: u8) -> Self {
925 ModifySorterPathCommand {
926 buffer: [coin_position, sorter],
927 }
928 }
929}
930impl Command for ModifySorterPathCommand {
931 type Response = ();
932
933 fn header(&self) -> Header {
934 Header::ModifySorterPaths
935 }
936
937 fn data(&self) -> &[u8] {
938 &self.buffer
939 }
940
941 fn parse_response(
942 &self,
943 response_payload: &[u8],
944 ) -> Result<Self::Response, ParseResponseError> {
945 if response_payload.is_empty() {
946 Ok(())
947 } else {
948 Err(ParseResponseError::DataLengthMismatch(
949 0,
950 response_payload.len(),
951 ))
952 }
953 }
954}
955
956#[derive(Debug)]
957pub struct RequestSorterPathCommand {
958 buffer: [u8; 1],
959}
960impl RequestSorterPathCommand {
961 pub fn new(coin_position: u8) -> Self {
962 RequestSorterPathCommand {
963 buffer: [coin_position],
964 }
965 }
966}
967impl Command for RequestSorterPathCommand {
968 type Response = SorterPath;
969
970 fn header(&self) -> Header {
971 Header::RequestSorterPaths
972 }
973
974 fn data(&self) -> &[u8] {
975 &self.buffer
976 }
977
978 fn parse_response(
979 &self,
980 response_payload: &[u8],
981 ) -> Result<Self::Response, ParseResponseError> {
982 match response_payload.len() {
983 1 => Ok(SorterPath::from(response_payload[0])),
984 2..=usize::MAX => {
985 crate::log::info!(
986 "multipath coin are not yet supported, got {} bytes",
987 response_payload.len()
988 );
989 Ok(SorterPath::from(response_payload[0]))
990 }
991 _ => Err(ParseResponseError::DataLengthMismatch(
992 1,
993 response_payload.len(),
994 )),
995 }
996 }
997}
998
999#[derive(Debug)]
1000pub struct ModifyPayoutAbsoluteCountCommand {
1001 buffer: [u8; 3],
1002 has_hopper_number: bool,
1003}
1004impl ModifyPayoutAbsoluteCountCommand {
1005 pub fn new(count: u32) -> Self {
1006 ModifyPayoutAbsoluteCountCommand {
1007 buffer: [(count & 0xFF) as u8, ((count >> 8) & 0xFF) as u8, 0u8],
1008 has_hopper_number: false,
1009 }
1010 }
1011
1012 pub fn new_with_hopper(hopper_number: u8, count: u32) -> Self {
1013 ModifyPayoutAbsoluteCountCommand {
1014 buffer: [
1015 hopper_number,
1016 (count & 0xFF) as u8,
1017 ((count >> 8) & 0xFF) as u8,
1018 ],
1019 has_hopper_number: true,
1020 }
1021 }
1022}
1023impl Command for ModifyPayoutAbsoluteCountCommand {
1024 type Response = ();
1025
1026 fn header(&self) -> Header {
1027 Header::ModifyPayoutAbsoluteCount
1028 }
1029
1030 fn data(&self) -> &[u8] {
1031 if self.has_hopper_number {
1032 &self.buffer[..]
1033 } else {
1034 &self.buffer[..2]
1035 }
1036 }
1037
1038 fn parse_response(
1039 &self,
1040 response_payload: &[u8],
1041 ) -> Result<Self::Response, ParseResponseError> {
1042 if response_payload.is_empty() {
1043 Ok(())
1044 } else {
1045 Err(ParseResponseError::DataLengthMismatch(
1046 0,
1047 response_payload.len(),
1048 ))
1049 }
1050 }
1051}
1052
1053#[derive(Debug)]
1054pub struct RequestPayoutAbsoluteCountCommand {
1055 buffer: [u8; 1],
1056 has_hopper_number: bool,
1057}
1058impl RequestPayoutAbsoluteCountCommand {
1059 pub fn new() -> Self {
1060 RequestPayoutAbsoluteCountCommand {
1061 buffer: [0u8],
1062 has_hopper_number: false,
1063 }
1064 }
1065
1066 pub fn new_with_hopper(hopper_number: u8) -> Self {
1067 RequestPayoutAbsoluteCountCommand {
1068 buffer: [hopper_number],
1069 has_hopper_number: true,
1070 }
1071 }
1072}
1073impl Default for RequestPayoutAbsoluteCountCommand {
1074 fn default() -> Self {
1075 Self::new()
1076 }
1077}
1078impl Command for RequestPayoutAbsoluteCountCommand {
1079 type Response = u16;
1080
1081 fn header(&self) -> Header {
1082 Header::RequestPayoutAbsoluteCount
1083 }
1084
1085 fn data(&self) -> &[u8] {
1086 if self.has_hopper_number {
1087 &self.buffer[..]
1088 } else {
1089 &[]
1090 }
1091 }
1092
1093 fn parse_response(
1094 &self,
1095 response_payload: &[u8],
1096 ) -> Result<Self::Response, ParseResponseError> {
1097 match response_payload.len() {
1098 2 => Ok(u16::from_le_bytes([
1099 response_payload[0],
1100 response_payload[1],
1101 ])),
1102 _ => Err(ParseResponseError::DataLengthMismatch(
1103 2,
1104 response_payload.len(),
1105 )),
1106 }
1107 }
1108}
1109
1110#[derive(Debug)]
1112pub struct MeterControlCommand;
1113
1114#[derive(Debug)]
1116pub struct DisplayControlCommand;
1117
1118#[derive(Debug)]
1119pub struct TeachModeControlCommand {
1120 buffer: [u8; 2],
1121 has_orientation: bool,
1122}
1123impl TeachModeControlCommand {
1124 pub fn new(position: u8) -> Self {
1125 TeachModeControlCommand {
1126 buffer: [position, 0u8],
1127 has_orientation: false,
1128 }
1129 }
1130
1131 pub fn new_with_orientation(position: u8, orientation: u8) -> Self {
1132 TeachModeControlCommand {
1133 buffer: [position, orientation],
1134 has_orientation: true,
1135 }
1136 }
1137}
1138impl Command for TeachModeControlCommand {
1139 type Response = ();
1140
1141 fn header(&self) -> Header {
1142 Header::TeachModeControl
1143 }
1144
1145 fn data(&self) -> &[u8] {
1146 if self.has_orientation {
1147 &self.buffer[..]
1148 } else {
1149 &self.buffer[..1]
1150 }
1151 }
1152
1153 fn parse_response(
1154 &self,
1155 response_payload: &[u8],
1156 ) -> Result<Self::Response, ParseResponseError> {
1157 if response_payload.is_empty() {
1158 Ok(())
1159 } else {
1160 Err(ParseResponseError::DataLengthMismatch(
1161 0,
1162 response_payload.len(),
1163 ))
1164 }
1165 }
1166}
1167
1168#[derive(Debug)]
1169pub struct RequestTeachModeStatusCommand {
1170 buffer: [u8; 1],
1171}
1172impl RequestTeachModeStatusCommand {
1173 pub fn new(abort: bool) -> Self {
1174 RequestTeachModeStatusCommand {
1175 buffer: [if abort { 1 } else { 0 }],
1176 }
1177 }
1178}
1179impl Command for RequestTeachModeStatusCommand {
1180 type Response = (u8, TeachModeStatus);
1181
1182 fn header(&self) -> Header {
1183 Header::RequestTeachStatus
1184 }
1185
1186 fn data(&self) -> &[u8] {
1187 &self.buffer
1188 }
1189
1190 fn parse_response(
1192 &self,
1193 response_payload: &[u8],
1194 ) -> Result<Self::Response, ParseResponseError> {
1195 match response_payload.len() {
1196 2 => Ok((
1197 response_payload[0],
1198 TeachModeStatus::from(response_payload[1]),
1199 )),
1200 _ => Err(ParseResponseError::DataLengthMismatch(
1201 2,
1202 response_payload.len(),
1203 )),
1204 }
1205 }
1206}
1207
1208#[derive(Debug)]
1209pub struct ConfigurationToEepromCommand;
1210impl Command for ConfigurationToEepromCommand {
1211 type Response = ();
1212
1213 fn header(&self) -> Header {
1214 Header::ConfigurationToEEPROM
1215 }
1216
1217 fn data(&self) -> &[u8] {
1218 &[]
1219 }
1220
1221 fn parse_response(&self, payload: &[u8]) -> Result<Self::Response, ParseResponseError> {
1223 match payload.len() {
1224 0 => Ok(()),
1225 _ => Err(ParseResponseError::DataLengthMismatch(0, payload.len())),
1226 }
1227 }
1228}
1229
1230#[derive(Debug)]
1231pub struct CountersToEepromCommand;
1232impl Command for CountersToEepromCommand {
1233 type Response = ();
1234
1235 fn header(&self) -> Header {
1236 Header::CountersToEEPROM
1237 }
1238
1239 fn data(&self) -> &[u8] {
1240 &[]
1241 }
1242
1243 fn parse_response(&self, payload: &[u8]) -> Result<Self::Response, ParseResponseError> {
1244 match payload.len() {
1245 0 => Ok(()),
1246 _ => Err(ParseResponseError::DataLengthMismatch(0, payload.len())),
1247 }
1248 }
1249}
1250
1251#[derive(Debug)]
1252pub struct RequestRejectCounterCommand;
1253impl Command for RequestRejectCounterCommand {
1254 type Response = u32;
1255
1256 fn header(&self) -> Header {
1257 Header::RequestRejectCounter
1258 }
1259
1260 fn data(&self) -> &[u8] {
1261 &[]
1262 }
1263
1264 fn parse_response(
1265 &self,
1266 response_payload: &[u8],
1267 ) -> Result<Self::Response, ParseResponseError> {
1268 match response_payload.len() {
1269 3 => Ok(u32::from_le_bytes([
1270 response_payload[0],
1271 response_payload[1],
1272 response_payload[2],
1273 0u8,
1274 ])),
1275 _ => Err(ParseResponseError::DataLengthMismatch(
1276 3,
1277 response_payload.len(),
1278 )),
1279 }
1280 }
1281}
1282
1283#[derive(Debug)]
1284pub struct RequestFraudCounterCommand;
1285impl Command for RequestFraudCounterCommand {
1286 type Response = u32;
1287
1288 fn header(&self) -> Header {
1289 Header::RequestFraudCounter
1290 }
1291
1292 fn data(&self) -> &[u8] {
1293 &[]
1294 }
1295
1296 fn parse_response(
1297 &self,
1298 response_payload: &[u8],
1299 ) -> Result<Self::Response, ParseResponseError> {
1300 match response_payload.len() {
1301 3 => Ok(u32::from_le_bytes([
1302 response_payload[0],
1303 response_payload[1],
1304 response_payload[2],
1305 0u8,
1306 ])),
1307 _ => Err(ParseResponseError::DataLengthMismatch(
1308 3,
1309 response_payload.len(),
1310 )),
1311 }
1312 }
1313}
1314
1315#[derive(Debug)]
1317pub struct KeypadControlCommand;
1318
1319#[derive(Debug)]
1320pub struct ModifyDefaultSorterPathCommand {
1321 buffer: [u8; 1],
1322}
1323impl ModifyDefaultSorterPathCommand {
1324 pub fn new(sorter: u8) -> Self {
1325 ModifyDefaultSorterPathCommand { buffer: [sorter] }
1326 }
1327}
1328impl Command for ModifyDefaultSorterPathCommand {
1329 type Response = ();
1330
1331 fn header(&self) -> Header {
1332 Header::ModifyDefaultSorterPath
1333 }
1334
1335 fn data(&self) -> &[u8] {
1336 &self.buffer
1337 }
1338
1339 fn parse_response(
1340 &self,
1341 response_payload: &[u8],
1342 ) -> Result<Self::Response, ParseResponseError> {
1343 if response_payload.is_empty() {
1344 Ok(())
1345 } else {
1346 Err(ParseResponseError::DataLengthMismatch(
1347 0,
1348 response_payload.len(),
1349 ))
1350 }
1351 }
1352}
1353
1354#[derive(Debug)]
1355pub struct RequestDefaultSorterPathCommand;
1356impl Command for RequestDefaultSorterPathCommand {
1357 type Response = SorterPath;
1358
1359 fn header(&self) -> Header {
1360 Header::RequestDefaultSorterPath
1361 }
1362
1363 fn data(&self) -> &[u8] {
1364 &[]
1365 }
1366
1367 fn parse_response(
1368 &self,
1369 response_payload: &[u8],
1370 ) -> Result<Self::Response, ParseResponseError> {
1371 match response_payload.len() {
1372 1 => Ok(SorterPath::from(response_payload[0])),
1373 _ => Err(ParseResponseError::DataLengthMismatch(
1374 1,
1375 response_payload.len(),
1376 )),
1377 }
1378 }
1379}
1380
1381#[derive(Debug)]
1382pub struct ModifyPayoutCapacityCommand {
1383 buffer: [u8; 3],
1384 has_hopper_number: bool,
1385}
1386impl ModifyPayoutCapacityCommand {
1387 pub fn new(capacity: u16) -> Self {
1388 ModifyPayoutCapacityCommand {
1389 buffer: [(capacity & 0xFF) as u8, ((capacity >> 8) & 0xFF) as u8, 0u8],
1390 has_hopper_number: false,
1391 }
1392 }
1393
1394 pub fn new_with_hopper(hopper_number: u8, capacity: u16) -> Self {
1395 ModifyPayoutCapacityCommand {
1396 buffer: [
1397 hopper_number,
1398 (capacity & 0xFF) as u8,
1399 ((capacity >> 8) & 0xFF) as u8,
1400 ],
1401 has_hopper_number: true,
1402 }
1403 }
1404}
1405impl Command for ModifyPayoutCapacityCommand {
1406 type Response = ();
1407
1408 fn header(&self) -> Header {
1409 Header::ModifyPayoutCapacity
1410 }
1411
1412 fn data(&self) -> &[u8] {
1413 if self.has_hopper_number {
1414 &self.buffer[..]
1415 } else {
1416 &self.buffer[..2]
1417 }
1418 }
1419
1420 fn parse_response(
1421 &self,
1422 response_payload: &[u8],
1423 ) -> Result<Self::Response, ParseResponseError> {
1424 if response_payload.is_empty() {
1425 Ok(())
1426 } else {
1427 Err(ParseResponseError::DataLengthMismatch(
1428 0,
1429 response_payload.len(),
1430 ))
1431 }
1432 }
1433}
1434
1435#[derive(Debug)]
1436pub struct RequestPayoutCapacityCommand {
1437 buffer: [u8; 1],
1438 has_hopper_number: bool,
1439}
1440impl RequestPayoutCapacityCommand {
1441 pub fn new() -> Self {
1442 RequestPayoutCapacityCommand {
1443 buffer: [0u8],
1444 has_hopper_number: false,
1445 }
1446 }
1447
1448 pub fn new_with_hopper(hopper_number: u8) -> Self {
1449 RequestPayoutCapacityCommand {
1450 buffer: [hopper_number],
1451 has_hopper_number: true,
1452 }
1453 }
1454}
1455impl Default for RequestPayoutCapacityCommand {
1456 fn default() -> Self {
1457 Self::new()
1458 }
1459}
1460impl Command for RequestPayoutCapacityCommand {
1461 type Response = u16;
1462
1463 fn header(&self) -> Header {
1464 Header::RequestPayoutCapacity
1465 }
1466
1467 fn data(&self) -> &[u8] {
1468 if self.has_hopper_number {
1469 &self.buffer[..]
1470 } else {
1471 &[]
1472 }
1473 }
1474
1475 fn parse_response(
1476 &self,
1477 response_payload: &[u8],
1478 ) -> Result<Self::Response, ParseResponseError> {
1479 match response_payload.len() {
1480 2 => Ok(u16::from_le_bytes([
1481 response_payload[0],
1482 response_payload[1],
1483 ])),
1484 _ => Err(ParseResponseError::DataLengthMismatch(
1485 2,
1486 response_payload.len(),
1487 )),
1488 }
1489 }
1490}
1491
1492#[derive(Debug)]
1493pub struct ModifyCoinIdCommand {
1494 buffer: [u8; 7],
1495}
1496impl ModifyCoinIdCommand {
1497 pub fn new(coin_position: u8, coin_id: &[u8; 6]) -> Self {
1498 ModifyCoinIdCommand {
1499 buffer: [
1500 coin_position,
1501 coin_id[0],
1502 coin_id[1],
1503 coin_id[2],
1504 coin_id[3],
1505 coin_id[4],
1506 coin_id[5],
1507 ],
1508 }
1509 }
1510}
1511impl Command for ModifyCoinIdCommand {
1512 type Response = ();
1513
1514 fn header(&self) -> Header {
1515 Header::ModifyCoinId
1516 }
1517
1518 fn data(&self) -> &[u8] {
1519 &self.buffer
1520 }
1521
1522 fn parse_response(
1523 &self,
1524 response_payload: &[u8],
1525 ) -> Result<Self::Response, ParseResponseError> {
1526 if response_payload.is_empty() {
1527 Ok(())
1528 } else {
1529 Err(ParseResponseError::DataLengthMismatch(
1530 0,
1531 response_payload.len(),
1532 ))
1533 }
1534 }
1535}
1536
1537#[derive(Debug)]
1538pub struct RequestCoinIdCommand {
1539 buffer: [u8; 1],
1540}
1541impl RequestCoinIdCommand {
1542 pub fn new(coin_position: u8) -> Self {
1543 RequestCoinIdCommand {
1544 buffer: [coin_position],
1545 }
1546 }
1547}
1548impl Command for RequestCoinIdCommand {
1549 type Response = CurrencyToken;
1550
1551 fn header(&self) -> Header {
1552 Header::RequestCoinId
1553 }
1554
1555 fn data(&self) -> &[u8] {
1556 &self.buffer
1557 }
1558
1559 fn parse_response(
1560 &self,
1561 response_payload: &[u8],
1562 ) -> Result<Self::Response, ParseResponseError> {
1563 match response_payload.len() {
1564 6 => {
1565 let payload_str = core::str::from_utf8(&response_payload[0..6])
1566 .map_err(|_| ParseResponseError::ParseError("Invalid UTF-8 in coin ID"))?;
1567
1568 CurrencyToken::build(payload_str)
1569 .map_err(|_| ParseResponseError::ParseError("Invalid coin ID format"))
1570 }
1571 _ => Err(ParseResponseError::DataLengthMismatch(
1572 6,
1573 response_payload.len(),
1574 )),
1575 }
1576 }
1577}
1578
1579#[derive(Debug)]
1580pub struct UploadWindowDataCommand {
1581 buffer: [u8; 3],
1582 size: u8,
1583}
1584impl UploadWindowDataCommand {
1585 pub fn program_coin(position: u8) -> Self {
1586 UploadWindowDataCommand {
1587 buffer: [0u8, position, 0u8],
1588 size: 2,
1589 }
1590 }
1591
1592 pub fn modify_credit_code(position: u8, credit_code: u8) -> Self {
1593 UploadWindowDataCommand {
1594 buffer: [1u8, position, credit_code],
1595 size: 3,
1596 }
1597 }
1598
1599 pub fn delete_coin(position: u8) -> Self {
1600 UploadWindowDataCommand {
1601 buffer: [2u8, position, 0],
1602 size: 2,
1603 }
1604 }
1605
1606 pub fn program_token(position: u8, data: u8) -> Self {
1607 UploadWindowDataCommand {
1608 buffer: [3u8, position, data],
1609 size: 3,
1610 }
1611 }
1612
1613 pub fn delete_token(position: u8) -> Self {
1614 UploadWindowDataCommand {
1615 buffer: [4, position, 0],
1616 size: 2,
1617 }
1618 }
1619}
1620impl Command for UploadWindowDataCommand {
1621 type Response = ();
1622
1623 fn header(&self) -> Header {
1624 Header::UploadWindowData
1625 }
1626
1627 fn data(&self) -> &[u8] {
1628 &self.buffer[..self.size as usize]
1629 }
1630
1631 fn parse_response(
1632 &self,
1633 response_payload: &[u8],
1634 ) -> Result<Self::Response, ParseResponseError> {
1635 if response_payload.is_empty() {
1636 Ok(())
1637 } else {
1638 Err(ParseResponseError::DataLengthMismatch(
1639 0,
1640 response_payload.len(),
1641 ))
1642 }
1643 }
1644}
1645
1646#[derive(Debug)]
1648pub struct DownloadCalibrationDataCommand;
1649impl Command for DownloadCalibrationDataCommand {
1650 type Response = ();
1651
1652 fn header(&self) -> Header {
1653 Header::DownloadCalibrationInfo
1654 }
1655
1656 fn data(&self) -> &[u8] {
1657 &[]
1658 }
1659
1660 fn parse_response(&self, _: &[u8]) -> Result<Self::Response, ParseResponseError> {
1661 Ok(())
1662 }
1663}
1664
1665#[derive(Debug)]
1666pub struct ModifySecuritySettingCommand {
1667 buffer: [u8; 2],
1668}
1669impl ModifySecuritySettingCommand {
1670 pub fn new(position: u8, security_setting: u8) -> Self {
1671 ModifySecuritySettingCommand {
1673 buffer: [position, security_setting],
1674 }
1675 }
1676}
1677impl Command for ModifySecuritySettingCommand {
1678 type Response = ();
1679
1680 fn header(&self) -> Header {
1681 Header::ModifySecuritySetting
1682 }
1683
1684 fn data(&self) -> &[u8] {
1685 &self.buffer
1686 }
1687
1688 fn parse_response(
1689 &self,
1690 response_payload: &[u8],
1691 ) -> Result<Self::Response, ParseResponseError> {
1692 match response_payload.len() {
1693 0 => Ok(()),
1694 _ => Err(ParseResponseError::DataLengthMismatch(
1695 0,
1696 response_payload.len(),
1697 )),
1698 }
1699 }
1700}
1701
1702#[derive(Debug)]
1703pub struct RequestSecuritySettingCommand {
1704 buffer: [u8; 1],
1705}
1706impl RequestSecuritySettingCommand {
1707 pub fn new(position: u8) -> Self {
1708 RequestSecuritySettingCommand { buffer: [position] }
1709 }
1710}
1711impl Command for RequestSecuritySettingCommand {
1712 type Response = u8;
1713
1714 fn header(&self) -> Header {
1715 Header::RequestSecuritySetting
1716 }
1717
1718 fn data(&self) -> &[u8] {
1719 &self.buffer
1720 }
1721
1722 fn parse_response(
1723 &self,
1724 response_payload: &[u8],
1725 ) -> Result<Self::Response, ParseResponseError> {
1726 match response_payload.len() {
1727 1 => Ok(response_payload[0]),
1728 _ => Err(ParseResponseError::DataLengthMismatch(
1729 1,
1730 response_payload.len(),
1731 )),
1732 }
1733 }
1734}
1735
1736#[derive(Debug)]
1737pub struct ModifyBankSelectCommand {
1738 buffer: [u8; 1],
1739}
1740impl ModifyBankSelectCommand {
1741 pub fn new(bank: u8) -> Self {
1742 ModifyBankSelectCommand { buffer: [bank] }
1743 }
1744}
1745impl Command for ModifyBankSelectCommand {
1746 type Response = ();
1747
1748 fn header(&self) -> Header {
1749 Header::ModifyBankSelect
1750 }
1751
1752 fn data(&self) -> &[u8] {
1753 &self.buffer
1754 }
1755
1756 fn parse_response(
1757 &self,
1758 response_payload: &[u8],
1759 ) -> Result<Self::Response, ParseResponseError> {
1760 match response_payload.len() {
1761 0 => Ok(()),
1762 _ => Err(ParseResponseError::DataLengthMismatch(
1763 0,
1764 response_payload.len(),
1765 )),
1766 }
1767 }
1768}
1769
1770#[derive(Debug)]
1771pub struct RequestBankSelectCommand;
1772impl Command for RequestBankSelectCommand {
1773 type Response = u8;
1774
1775 fn header(&self) -> Header {
1776 Header::RequestBankSelect
1777 }
1778
1779 fn data(&self) -> &[u8] {
1780 &[]
1781 }
1782
1783 fn parse_response(
1784 &self,
1785 response_payload: &[u8],
1786 ) -> Result<Self::Response, ParseResponseError> {
1787 match response_payload.len() {
1788 1 => Ok(response_payload[0]),
1789 _ => Err(ParseResponseError::DataLengthMismatch(
1790 1,
1791 response_payload.len(),
1792 )),
1793 }
1794 }
1795}
1796
1797#[derive(Debug)]
1799pub struct HandheldFunctionCommand;
1800
1801#[derive(Debug)]
1802pub struct RequestAlarmCounterCommand;
1803impl Command for RequestAlarmCounterCommand {
1804 type Response = u8;
1805
1806 fn header(&self) -> Header {
1807 Header::RequestAlarmCounter
1808 }
1809
1810 fn data(&self) -> &[u8] {
1811 &[]
1812 }
1813
1814 fn parse_response(
1815 &self,
1816 response_payload: &[u8],
1817 ) -> Result<Self::Response, ParseResponseError> {
1818 match response_payload.len() {
1819 1 => Ok(response_payload[0]),
1820 _ => Err(ParseResponseError::DataLengthMismatch(
1821 1,
1822 response_payload.len(),
1823 )),
1824 }
1825 }
1826}
1827
1828#[derive(Debug)]
1829pub struct ModifyPayoutFloatCommand {
1830 buffer: [u8; 3],
1831 has_hopper_number: bool,
1832}
1833impl ModifyPayoutFloatCommand {
1834 pub fn new(number_of_coins: u16) -> Self {
1835 ModifyPayoutFloatCommand {
1836 buffer: [
1837 (number_of_coins & 0xFF) as u8,
1838 ((number_of_coins >> 8) & 0xFF) as u8,
1839 0u8,
1840 ],
1841 has_hopper_number: false,
1842 }
1843 }
1844
1845 pub fn new_with_hopper(hopper_number: u8, number_of_coins: u16) -> Self {
1846 ModifyPayoutFloatCommand {
1847 buffer: [
1848 hopper_number,
1849 (number_of_coins & 0xFF) as u8,
1850 ((number_of_coins >> 8) & 0xFF) as u8,
1851 ],
1852 has_hopper_number: true,
1853 }
1854 }
1855}
1856impl Command for ModifyPayoutFloatCommand {
1857 type Response = ();
1858
1859 fn header(&self) -> Header {
1860 Header::ModifyPayoutFloat
1861 }
1862
1863 fn data(&self) -> &[u8] {
1864 if self.has_hopper_number {
1865 &self.buffer[..]
1866 } else {
1867 &self.buffer[..2]
1868 }
1869 }
1870
1871 fn parse_response(
1872 &self,
1873 response_payload: &[u8],
1874 ) -> Result<Self::Response, ParseResponseError> {
1875 match response_payload.len() {
1876 0 => Ok(()),
1877 _ => Err(ParseResponseError::DataLengthMismatch(
1878 0,
1879 response_payload.len(),
1880 )),
1881 }
1882 }
1883}
1884
1885#[derive(Debug)]
1886pub struct RequestPayoutFloatCommand {
1887 buffer: [u8; 1],
1888 has_hopper_number: bool,
1889}
1890impl RequestPayoutFloatCommand {
1891 pub fn new() -> Self {
1892 RequestPayoutFloatCommand {
1893 buffer: [0u8],
1894 has_hopper_number: false,
1895 }
1896 }
1897
1898 pub fn new_with_hopper(hopper_number: u8) -> Self {
1899 RequestPayoutFloatCommand {
1900 buffer: [hopper_number],
1901 has_hopper_number: true,
1902 }
1903 }
1904}
1905
1906impl Default for RequestPayoutFloatCommand {
1907 fn default() -> Self {
1908 Self::new()
1909 }
1910}
1911impl Command for RequestPayoutFloatCommand {
1912 type Response = u16;
1913
1914 fn header(&self) -> Header {
1915 Header::RequestPayoutFloat
1916 }
1917
1918 fn data(&self) -> &[u8] {
1919 if self.has_hopper_number {
1920 &self.buffer[..]
1921 } else {
1922 &[]
1923 }
1924 }
1925
1926 fn parse_response(
1927 &self,
1928 response_payload: &[u8],
1929 ) -> Result<Self::Response, ParseResponseError> {
1930 match response_payload.len() {
1931 2 => Ok(u16::from_le_bytes([
1932 response_payload[0],
1933 response_payload[1],
1934 ])),
1935 _ => Err(ParseResponseError::DataLengthMismatch(
1936 2,
1937 response_payload.len(),
1938 )),
1939 }
1940 }
1941}
1942
1943#[derive(Debug)]
1944pub struct RequestThermistorReadingCommand;
1945impl Command for RequestThermistorReadingCommand {
1946 type Response = u8;
1947
1948 fn header(&self) -> Header {
1949 Header::RequestThermistorReading
1950 }
1951
1952 fn data(&self) -> &[u8] {
1953 &[]
1954 }
1955
1956 fn parse_response(
1957 &self,
1958 response_payload: &[u8],
1959 ) -> Result<Self::Response, ParseResponseError> {
1960 match response_payload.len() {
1961 1 => Ok(response_payload[0]),
1962 _ => Err(ParseResponseError::DataLengthMismatch(
1963 1,
1964 response_payload.len(),
1965 )),
1966 }
1967 }
1968}
1969
1970#[derive(Debug)]
1971pub struct EmergencyStopCommand;
1972impl Command for EmergencyStopCommand {
1973 type Response = u8;
1974
1975 fn header(&self) -> Header {
1976 Header::EmergencyStop
1977 }
1978
1979 fn data(&self) -> &[u8] {
1980 &[]
1981 }
1982
1983 fn parse_response(
1984 &self,
1985 response_payload: &[u8],
1986 ) -> Result<Self::Response, ParseResponseError> {
1987 match response_payload.len() {
1988 1 => Ok(response_payload[0]),
1989 _ => Err(ParseResponseError::DataLengthMismatch(
1990 0,
1991 response_payload.len(),
1992 )),
1993 }
1994 }
1995}
1996
1997#[derive(Debug)]
1998pub struct RequestHopperCoinCommand;
1999impl Command for RequestHopperCoinCommand {
2000 type Response = CurrencyToken;
2001
2002 fn header(&self) -> Header {
2003 Header::RequestHopperCoin
2004 }
2005
2006 fn data(&self) -> &[u8] {
2007 &[]
2008 }
2009
2010 fn parse_response(
2011 &self,
2012 response_payload: &[u8],
2013 ) -> Result<Self::Response, ParseResponseError> {
2014 let coin_string = core::str::from_utf8(response_payload)
2015 .map_err(|_| ParseResponseError::ParseError("Invalid UTF-8 in coin string"))?;
2016
2017 CurrencyToken::build(coin_string).map_err(|err| match err {
2018 CurrencyTokenError::InvalidFormat => {
2019 ParseResponseError::ParseError("invalid coin string format")
2020 }
2021 CurrencyTokenError::ValueStringTooSmall => ParseResponseError::BufferTooSmall,
2022 CurrencyTokenError::CoinNotSupportedByDevice => {
2023 ParseResponseError::ParseError("not supported by device")
2024 }
2025 })
2026 }
2027}
2028
2029#[derive(Debug)]
2030pub struct RequestHopperDispenseCountCommand;
2031impl Command for RequestHopperDispenseCountCommand {
2032 type Response = u32;
2033
2034 fn header(&self) -> Header {
2035 Header::RequestHopperDispenseCount
2036 }
2037
2038 fn data(&self) -> &[u8] {
2039 &[]
2040 }
2041
2042 fn parse_response(
2043 &self,
2044 response_payload: &[u8],
2045 ) -> Result<Self::Response, ParseResponseError> {
2046 match response_payload.len() {
2047 3 => Ok(u32::from_le_bytes([
2048 response_payload[0],
2049 response_payload[1],
2050 response_payload[2],
2051 0,
2052 ])),
2053 _ => Err(ParseResponseError::DataLengthMismatch(
2054 3,
2055 response_payload.len(),
2056 )),
2057 }
2058 }
2059}
2060
2061#[derive(Debug)]
2062pub struct DispenseHopperCoinsCommand {
2063 buffer: [u8; 32],
2064 length: u8,
2065}
2066impl DispenseHopperCoinsCommand {
2067 pub fn new(coins: u8) -> Self {
2068 let buffer = [coins; 32];
2069 DispenseHopperCoinsCommand { buffer, length: 1 }
2070 }
2071
2072 pub fn new_with_data(coins: u8, additional_data: &[u8]) -> Self {
2073 const MAX_BUFFER_SIZE: usize = 32;
2074
2075 let mut buffer = [coins; MAX_BUFFER_SIZE];
2076
2077 let data_to_copy = additional_data.len().min(MAX_BUFFER_SIZE);
2078 buffer[..data_to_copy].copy_from_slice(&additional_data[..data_to_copy]);
2079
2080 let command_length = (1 + additional_data.len()).min(MAX_BUFFER_SIZE) as u8;
2081
2082 DispenseHopperCoinsCommand {
2083 buffer,
2084 length: command_length,
2085 }
2086 }
2087}
2088impl Command for DispenseHopperCoinsCommand {
2089 type Response = Option<u8>;
2090
2091 fn header(&self) -> Header {
2092 Header::DispenseHopperCoins
2093 }
2094
2095 fn data(&self) -> &[u8] {
2096 &self.buffer[..self.length as usize]
2097 }
2098
2099 fn parse_response(
2100 &self,
2101 response_payload: &[u8],
2102 ) -> Result<Self::Response, ParseResponseError> {
2103 if response_payload.len() == 1 {
2104 Ok(Some(response_payload[0]))
2105 } else {
2106 Ok(None)
2107 }
2108 }
2109}
2110
2111#[derive(Debug)]
2112pub struct RequestHopperStatusCommand;
2113impl Command for RequestHopperStatusCommand {
2114 type Response = HopperDispenseStatus;
2115
2116 fn header(&self) -> Header {
2117 Header::RequestHopperStatus
2118 }
2119
2120 fn data(&self) -> &[u8] {
2121 &[]
2122 }
2123
2124 fn parse_response(
2125 &self,
2126 response_payload: &[u8],
2127 ) -> Result<Self::Response, ParseResponseError> {
2128 match response_payload.len() {
2129 4 => Ok(HopperDispenseStatus::from([
2130 response_payload[0],
2131 response_payload[1],
2132 response_payload[2],
2133 response_payload[3],
2134 ])),
2135 _ => Err(ParseResponseError::DataLengthMismatch(
2136 4,
2137 response_payload.len(),
2138 )),
2139 }
2140 }
2141}
2142
2143#[derive(Debug)]
2144pub struct ModifyVariableSetCommand<const N: usize> {
2145 buffer: [u8; N],
2146}
2147impl<const N: usize> ModifyVariableSetCommand<N> {
2148 pub fn new(buffer: [u8; N]) -> Self {
2149 ModifyVariableSetCommand { buffer }
2150 }
2151}
2152impl<const N: usize> Command for ModifyVariableSetCommand<N> {
2153 type Response = ();
2154
2155 fn header(&self) -> Header {
2156 Header::ModifyVariableSet
2157 }
2158
2159 fn data(&self) -> &[u8] {
2160 &self.buffer
2161 }
2162
2163 fn parse_response(
2164 &self,
2165 response_payload: &[u8],
2166 ) -> Result<Self::Response, ParseResponseError> {
2167 if response_payload.is_empty() {
2168 Ok(())
2169 } else {
2170 Err(ParseResponseError::DataLengthMismatch(
2171 0,
2172 response_payload.len(),
2173 ))
2174 }
2175 }
2176}
2177
2178#[derive(Debug)]
2179pub struct EnableHopperCommand {
2180 buffer: [u8; 1],
2181}
2182impl EnableHopperCommand {
2183 pub fn new(enable: bool) -> Self {
2184 EnableHopperCommand {
2185 buffer: [if enable { 0xA5 } else { 0 }],
2186 }
2187 }
2188}
2189impl Command for EnableHopperCommand {
2190 type Response = ();
2191
2192 fn header(&self) -> Header {
2193 Header::EnableHopper
2194 }
2195
2196 fn data(&self) -> &[u8] {
2197 &self.buffer
2198 }
2199
2200 fn parse_response(
2201 &self,
2202 response_payload: &[u8],
2203 ) -> Result<Self::Response, ParseResponseError> {
2204 if response_payload.is_empty() {
2205 Ok(())
2206 } else {
2207 Err(ParseResponseError::DataLengthMismatch(
2208 0,
2209 response_payload.len(),
2210 ))
2211 }
2212 }
2213}
2214
2215#[derive(Debug)]
2216pub struct TestHopperCommand;
2217impl Command for TestHopperCommand {
2218 type Response = heapless::Vec<HopperFlag, 21>;
2219
2220 fn header(&self) -> Header {
2221 Header::TestHopper
2222 }
2223
2224 fn data(&self) -> &[u8] {
2225 &[]
2226 }
2227
2228 fn parse_response(
2229 &self,
2230 response_payload: &[u8],
2231 ) -> Result<Self::Response, ParseResponseError> {
2232 match response_payload.len() {
2233 0..=3 => Ok(HopperFlag::parse_hopper_flags_heapless(response_payload)),
2234 _ => Err(ParseResponseError::DataLengthMismatch(
2235 3,
2236 response_payload.len(),
2237 )),
2238 }
2239 }
2240}
2241
2242#[derive(Debug)]
2243pub struct PumpRngCommand<const N: usize> {
2244 buffer: [u8; N],
2245}
2246impl<const N: usize> PumpRngCommand<N> {
2247 pub fn new(buffer: [u8; N]) -> Self {
2248 PumpRngCommand { buffer }
2249 }
2250}
2251impl<const N: usize> Command for PumpRngCommand<N> {
2252 type Response = ();
2253
2254 fn header(&self) -> Header {
2255 Header::PumpRNG
2256 }
2257
2258 fn data(&self) -> &[u8] {
2259 &self.buffer
2260 }
2261
2262 fn parse_response(
2263 &self,
2264 response_payload: &[u8],
2265 ) -> Result<Self::Response, ParseResponseError> {
2266 match response_payload.len() {
2267 0 => Ok(()),
2268 _ => Err(ParseResponseError::DataLengthMismatch(
2269 0,
2270 response_payload.len(),
2271 )),
2272 }
2273 }
2274}
2275
2276#[derive(Debug)]
2277pub struct RequestCipherKeyCommand;
2278impl Command for RequestCipherKeyCommand {
2279 type Response = ();
2280
2281 fn header(&self) -> Header {
2282 Header::RequestCipherKey
2283 }
2284
2285 fn data(&self) -> &[u8] {
2286 &[]
2287 }
2288
2289 fn parse_response(&self, _: &[u8]) -> Result<Self::Response, ParseResponseError> {
2291 Ok(())
2292 }
2293}
2294
2295#[derive(Debug, Default)]
2296pub struct ReadBufferedBillEventsCommand {
2297 last_event_counter: u8,
2298}
2299impl ReadBufferedBillEventsCommand {
2300 pub fn new(last_event_counter: u8) -> Self {
2301 ReadBufferedBillEventsCommand { last_event_counter }
2302 }
2303}
2304impl Command for ReadBufferedBillEventsCommand {
2305 type Response = BillValidatorPollResult;
2306
2307 fn header(&self) -> Header {
2308 Header::ReadBufferedBillEvents
2309 }
2310
2311 fn data(&self) -> &[u8] {
2312 &[]
2313 }
2314
2315 fn parse_response(
2316 &self,
2317 response_payload: &[u8],
2318 ) -> Result<Self::Response, ParseResponseError> {
2319 BillValidatorPollResult::try_from((response_payload, self.last_event_counter)).map_err(
2320 |error| match error {
2321 BillValidatorPollResultError::NotEnoughEvents => {
2322 ParseResponseError::ParseError("unexpected number of events (too few)")
2323 }
2324 BillValidatorPollResultError::TooManyEvents => {
2325 ParseResponseError::ParseError("unexpected number of events (too many)")
2326 }
2327 BillValidatorPollResultError::InvalidPayload => {
2328 ParseResponseError::DataLengthMismatch(1357911, response_payload.len())
2329 }
2330 },
2331 )
2332 }
2333}
2334
2335#[derive(Debug)]
2336pub struct ModifyBillIdCommand {
2337 buffer: [u8; 8],
2338}
2339impl ModifyBillIdCommand {
2340 pub fn new(bill_type: u8, bill_string: &[u8; 7]) -> Self {
2341 ModifyBillIdCommand {
2342 buffer: [
2343 bill_type,
2344 bill_string[0],
2345 bill_string[1],
2346 bill_string[2],
2347 bill_string[3],
2348 bill_string[4],
2349 bill_string[5],
2350 bill_string[6],
2351 ],
2352 }
2353 }
2354}
2355impl Command for ModifyBillIdCommand {
2356 type Response = ();
2357
2358 fn header(&self) -> Header {
2359 Header::ModifyBillId
2360 }
2361
2362 fn data(&self) -> &[u8] {
2363 &self.buffer
2364 }
2365
2366 fn parse_response(
2367 &self,
2368 response_payload: &[u8],
2369 ) -> Result<Self::Response, ParseResponseError> {
2370 match response_payload.len() {
2371 0 => Ok(()),
2372 _ => Err(ParseResponseError::DataLengthMismatch(
2373 0,
2374 response_payload.len(),
2375 )),
2376 }
2377 }
2378}
2379
2380#[derive(Debug)]
2381pub struct RequestBillIdCommand {
2382 buffer: [u8; 1],
2383}
2384impl RequestBillIdCommand {
2385 pub fn new(bill_type: u8) -> Self {
2386 RequestBillIdCommand {
2387 buffer: [bill_type],
2388 }
2389 }
2390}
2391impl Command for RequestBillIdCommand {
2392 type Response = CurrencyToken;
2393
2394 fn header(&self) -> Header {
2395 Header::RequestBillId
2396 }
2397
2398 fn data(&self) -> &[u8] {
2399 &self.buffer
2400 }
2401
2402 fn parse_response(
2403 &self,
2404 response_payload: &[u8],
2405 ) -> Result<Self::Response, ParseResponseError> {
2406 match response_payload.len() {
2407 7 => {
2408 let payload_str = core::str::from_utf8(&response_payload[0..7])
2409 .map_err(|_| ParseResponseError::ParseError("Invalid UTF-8 in bill ID"))?;
2410
2411 CurrencyToken::build(payload_str)
2412 .map_err(|_| ParseResponseError::ParseError("Invalid bill ID format"))
2413 }
2414 _ => Err(ParseResponseError::DataLengthMismatch(
2415 7,
2416 response_payload.len(),
2417 )),
2418 }
2419 }
2420}
2421
2422#[derive(Debug)]
2424pub struct RequestCountryScalingFactorCommand;
2425
2426#[derive(Debug)]
2427pub struct RequestBillPositionCommand {
2428 buffer: [u8; 2],
2429}
2430impl RequestBillPositionCommand {
2431 pub fn new(country_code: &str) -> Self {
2432 RequestBillPositionCommand {
2433 buffer: [country_code.as_bytes()[0], country_code.as_bytes()[1]],
2434 }
2435 }
2436}
2437impl Command for RequestBillPositionCommand {
2438 type Response = ();
2439
2440 fn header(&self) -> Header {
2441 Header::RequestBillPosition
2442 }
2443
2444 fn data(&self) -> &[u8] {
2445 &self.buffer
2446 }
2447
2448 fn parse_response(
2449 &self,
2450 response_payload: &[u8],
2451 ) -> Result<Self::Response, ParseResponseError> {
2452 match response_payload.len() {
2453 1..=255 => Ok(()),
2454 _ => Err(ParseResponseError::DataLengthMismatch(
2455 1,
2456 response_payload.len(),
2457 )),
2458 }
2459 }
2460}
2461
2462#[derive(Debug)]
2463pub struct RouteBillCommand {
2464 buffer: [u8; 1],
2465}
2466impl RouteBillCommand {
2467 pub fn new(command: BillRouteCode) -> Self {
2468 RouteBillCommand {
2469 buffer: [command as u8],
2470 }
2471 }
2472}
2473impl Command for RouteBillCommand {
2474 type Response = Option<BillRoutingError>;
2475
2476 fn header(&self) -> Header {
2477 Header::RouteBill
2478 }
2479
2480 fn data(&self) -> &[u8] {
2481 &self.buffer
2482 }
2483
2484 fn parse_response(
2485 &self,
2486 response_payload: &[u8],
2487 ) -> Result<Self::Response, ParseResponseError> {
2488 match response_payload.len() {
2489 0 => Ok(None),
2490 1 => match BillRoutingError::try_from(response_payload[0]) {
2491 Ok(error) => Ok(Some(error)),
2492 Err(_) => Ok(None),
2493 },
2494 _ => Err(ParseResponseError::DataLengthMismatch(
2495 0,
2496 response_payload.len(),
2497 )),
2498 }
2499 }
2500}
2501
2502#[derive(Debug)]
2503pub struct ModifyBillOperatingModeCommand {
2504 buffer: [u8; 1],
2505}
2506impl ModifyBillOperatingModeCommand {
2507 pub fn new(use_stacker: bool, use_escrow: bool) -> Self {
2508 let mut mask = 0u8;
2509 if use_stacker {
2510 mask += 1;
2511 }
2512
2513 if use_escrow {
2514 mask += 2;
2515 }
2516
2517 ModifyBillOperatingModeCommand { buffer: [mask] }
2518 }
2519}
2520impl Command for ModifyBillOperatingModeCommand {
2521 type Response = ();
2522
2523 fn header(&self) -> Header {
2524 Header::ModifyBillOperatingMode
2525 }
2526
2527 fn data(&self) -> &[u8] {
2528 &self.buffer
2529 }
2530
2531 fn parse_response(
2532 &self,
2533 response_payload: &[u8],
2534 ) -> Result<Self::Response, ParseResponseError> {
2535 if response_payload.is_empty() {
2536 Ok(())
2537 } else {
2538 Err(ParseResponseError::DataLengthMismatch(
2539 0,
2540 response_payload.len(),
2541 ))
2542 }
2543 }
2544}
2545
2546#[derive(Debug)]
2547pub struct RequestBillOperatingModeCommand;
2548impl Command for RequestBillOperatingModeCommand {
2549 type Response = (bool, bool); fn header(&self) -> Header {
2552 Header::RequestBillOperatingMode
2553 }
2554
2555 fn data(&self) -> &[u8] {
2556 &[]
2557 }
2558
2559 fn parse_response(
2560 &self,
2561 response_payload: &[u8],
2562 ) -> Result<Self::Response, ParseResponseError> {
2563 match response_payload.len() {
2564 1 => Ok((
2565 response_payload[0] & 0x01 != 0,
2566 response_payload[0] & 0x02 != 0,
2567 )),
2568 _ => Err(ParseResponseError::DataLengthMismatch(
2569 1,
2570 response_payload.len(),
2571 )),
2572 }
2573 }
2574}
2575
2576#[derive(Debug)]
2577pub struct TestLampsCommand {
2578 buffer: [u8; 2],
2579}
2580impl TestLampsCommand {
2581 pub fn new(lamp: u8, command: LampControl) -> Self {
2582 TestLampsCommand {
2583 buffer: [lamp, command.into()],
2584 }
2585 }
2586}
2587impl Command for TestLampsCommand {
2588 type Response = ();
2589
2590 fn header(&self) -> Header {
2591 Header::TestLamps
2592 }
2593
2594 fn data(&self) -> &[u8] {
2595 &self.buffer
2596 }
2597
2598 fn parse_response(
2599 &self,
2600 response_payload: &[u8],
2601 ) -> Result<Self::Response, ParseResponseError> {
2602 match response_payload.len() {
2603 0 => Ok(()),
2604 _ => Err(ParseResponseError::DataLengthMismatch(
2605 0,
2606 response_payload.len(),
2607 )),
2608 }
2609 }
2610}
2611
2612#[derive(Debug)]
2613pub struct RequestIndividualAcceptCounterCommand {
2614 buffer: [u8; 1],
2615}
2616impl RequestIndividualAcceptCounterCommand {
2617 pub fn new(bill_or_coin_type: u8) -> Self {
2618 RequestIndividualAcceptCounterCommand {
2619 buffer: [bill_or_coin_type],
2620 }
2621 }
2622}
2623impl Command for RequestIndividualAcceptCounterCommand {
2624 type Response = u32;
2625
2626 fn header(&self) -> Header {
2627 Header::RequestIndividualAcceptCounter
2628 }
2629
2630 fn data(&self) -> &[u8] {
2631 &self.buffer
2632 }
2633
2634 fn parse_response(
2635 &self,
2636 response_payload: &[u8],
2637 ) -> Result<Self::Response, ParseResponseError> {
2638 match response_payload.len() {
2639 3 => Ok(u32::from_le_bytes([
2640 response_payload[0],
2641 response_payload[1],
2642 response_payload[2],
2643 0u8,
2644 ])),
2645 _ => Err(ParseResponseError::DataLengthMismatch(
2646 3,
2647 response_payload.len(),
2648 )),
2649 }
2650 }
2651}
2652
2653#[derive(Debug)]
2654pub struct ReadOptoVoltagesCommand;
2655impl Command for ReadOptoVoltagesCommand {
2656 type Response = ();
2657
2658 fn header(&self) -> Header {
2659 Header::ReadOptoVoltages
2660 }
2661
2662 fn data(&self) -> &[u8] {
2663 &[]
2664 }
2665
2666 fn parse_response(
2668 &self,
2669 response_payload: &[u8],
2670 ) -> Result<Self::Response, ParseResponseError> {
2671 match response_payload.len() {
2672 1..=2 => Ok(()),
2673 _ => Err(ParseResponseError::DataLengthMismatch(
2674 1,
2675 response_payload.len(),
2676 )),
2677 }
2678 }
2679}
2680
2681#[derive(Debug)]
2682pub struct PerformStackerCycleCommand;
2683impl Command for PerformStackerCycleCommand {
2684 type Response = Option<StackerCycleError>;
2685
2686 fn header(&self) -> Header {
2687 Header::PerformStackerCycle
2688 }
2689
2690 fn data(&self) -> &[u8] {
2691 &[]
2692 }
2693
2694 fn parse_response(
2696 &self,
2697 response_payload: &[u8],
2698 ) -> Result<Self::Response, ParseResponseError> {
2699 match response_payload.len() {
2700 1 => StackerCycleError::try_from(response_payload[0])
2701 .map(Some)
2702 .map_err(|_| ParseResponseError::ParseError("Invalid stacker cycle error")),
2703 _ => Ok(None),
2704 }
2705 }
2706}
2707
2708#[derive(Debug)]
2709pub struct OperateBiDirectionalMotorsCommand {
2710 buffer: [u8; 3],
2711}
2712impl OperateBiDirectionalMotorsCommand {
2713 pub fn new(motors: u8, directions: u8, speed: u8) -> Self {
2714 OperateBiDirectionalMotorsCommand {
2715 buffer: [motors, directions, speed],
2716 }
2717 }
2718}
2719impl Command for OperateBiDirectionalMotorsCommand {
2720 type Response = ();
2721
2722 fn header(&self) -> Header {
2723 Header::OperateBiDirectionalMotors
2724 }
2725
2726 fn data(&self) -> &[u8] {
2727 &self.buffer
2728 }
2729
2730 fn parse_response(
2731 &self,
2732 response_payload: &[u8],
2733 ) -> Result<Self::Response, ParseResponseError> {
2734 match response_payload.len() {
2735 0 => Ok(()),
2736 _ => Err(ParseResponseError::DataLengthMismatch(
2737 0,
2738 response_payload.len(),
2739 )),
2740 }
2741 }
2742}
2743
2744#[derive(Debug)]
2745pub struct RequestCurrencyRevisionCommand {
2746 buffer: [u8; 2],
2747 has_country_code: bool,
2748}
2749impl RequestCurrencyRevisionCommand {
2750 pub fn new() -> Self {
2751 RequestCurrencyRevisionCommand {
2752 buffer: [0u8, 0u8],
2753 has_country_code: false,
2754 }
2755 }
2756
2757 pub fn build_with_country(country_code: &str) -> Result<Self, ()> {
2758 let bytes = country_code.as_bytes();
2759 if bytes.len() != 2 {
2760 return Err(());
2761 }
2762
2763 Ok(RequestCurrencyRevisionCommand {
2764 buffer: [bytes[0], bytes[1]],
2765 has_country_code: true,
2766 })
2767 }
2768}
2769
2770impl Default for RequestCurrencyRevisionCommand {
2771 fn default() -> Self {
2772 Self::new()
2773 }
2774}
2775impl Command for RequestCurrencyRevisionCommand {
2776 type Response = ();
2777
2778 fn header(&self) -> Header {
2779 Header::RequestCurrencyRevision
2780 }
2781
2782 fn data(&self) -> &[u8] {
2783 if self.has_country_code {
2784 &self.buffer[..]
2785 } else {
2786 &[]
2787 }
2788 }
2789
2790 fn parse_response(&self, _: &[u8]) -> Result<Self::Response, ParseResponseError> {
2792 Ok(())
2793 }
2794}
2795
2796#[derive(Debug)]
2797pub struct UploadBillTablesCommand {
2798 buffer: [u8; 130], data_len: u8,
2800}
2801impl UploadBillTablesCommand {
2802 pub fn new(block: u8, line: u8, data: &[u8]) -> Result<Self, ()> {
2803 const MAX_PAYLOAD_SIZE: usize = 128;
2804 const COMMAND_BUFFER_SIZE: usize = 130;
2805
2806 if data.len() > MAX_PAYLOAD_SIZE {
2807 return Err(());
2808 }
2809
2810 let mut buffer = [0u8; COMMAND_BUFFER_SIZE];
2811 buffer[0] = block;
2812 buffer[1] = line;
2813
2814 let payload_start = 2;
2815 buffer[payload_start..payload_start + data.len()].copy_from_slice(data);
2816
2817 Ok(UploadBillTablesCommand {
2818 buffer,
2819 data_len: (2 + data.len()) as u8, })
2821 }
2822}
2823impl Command for UploadBillTablesCommand {
2824 type Response = ();
2825
2826 fn header(&self) -> Header {
2827 Header::UploadBillTables
2828 }
2829
2830 fn data(&self) -> &[u8] {
2831 &self.buffer[..self.data_len as usize]
2832 }
2833
2834 fn parse_response(
2835 &self,
2836 response_payload: &[u8],
2837 ) -> Result<Self::Response, ParseResponseError> {
2838 if response_payload.is_empty() {
2839 Ok(())
2840 } else {
2841 Err(ParseResponseError::DataLengthMismatch(
2842 0,
2843 response_payload.len(),
2844 ))
2845 }
2846 }
2847}
2848
2849#[derive(Debug)]
2850pub struct BeginBillTableUpgradeCommand;
2851impl Command for BeginBillTableUpgradeCommand {
2852 type Response = ();
2853
2854 fn header(&self) -> Header {
2855 Header::BeginBillTableUpgrade
2856 }
2857
2858 fn data(&self) -> &[u8] {
2859 &[]
2860 }
2861
2862 fn parse_response(
2863 &self,
2864 response_payload: &[u8],
2865 ) -> Result<Self::Response, ParseResponseError> {
2866 match response_payload.len() {
2867 0 => Ok(()),
2868 _ => Err(ParseResponseError::DataLengthMismatch(
2869 0,
2870 response_payload.len(),
2871 )),
2872 }
2873 }
2874}
2875
2876#[derive(Debug)]
2877pub struct FinishBillTableUpgradeCommand;
2878impl Command for FinishBillTableUpgradeCommand {
2879 type Response = ();
2880
2881 fn header(&self) -> Header {
2882 Header::FinishBillTableUpgrade
2883 }
2884
2885 fn data(&self) -> &[u8] {
2886 &[]
2887 }
2888
2889 fn parse_response(
2890 &self,
2891 response_payload: &[u8],
2892 ) -> Result<Self::Response, ParseResponseError> {
2893 match response_payload.len() {
2894 0 => Ok(()),
2895 _ => Err(ParseResponseError::DataLengthMismatch(
2896 0,
2897 response_payload.len(),
2898 )),
2899 }
2900 }
2901}
2902
2903#[derive(Debug)]
2904pub struct RequestFirmwareUpgradeCapability {
2905 buffer: [u8; 1],
2906 has_module_identifier: bool,
2907}
2908impl RequestFirmwareUpgradeCapability {
2909 pub fn new() -> Self {
2910 RequestFirmwareUpgradeCapability {
2911 buffer: [0],
2912 has_module_identifier: false,
2913 }
2914 }
2915
2916 pub fn new_with_module_identifier(module_identifier: u8) -> Self {
2917 RequestFirmwareUpgradeCapability {
2918 buffer: [module_identifier],
2919 has_module_identifier: true,
2920 }
2921 }
2922}
2923
2924impl Default for RequestFirmwareUpgradeCapability {
2925 fn default() -> Self {
2926 Self::new()
2927 }
2928}
2929impl Command for RequestFirmwareUpgradeCapability {
2930 type Response = FirmwareStorageType;
2931
2932 fn header(&self) -> Header {
2933 Header::RequestFirmwareUpgradeCapability
2934 }
2935
2936 fn data(&self) -> &[u8] {
2937 if self.has_module_identifier {
2938 &self.buffer[..]
2939 } else {
2940 &[]
2941 }
2942 }
2943
2944 fn parse_response(
2945 &self,
2946 response_payload: &[u8],
2947 ) -> Result<Self::Response, ParseResponseError> {
2948 match response_payload.len() {
2949 1 => FirmwareStorageType::try_from(response_payload[0])
2950 .map_err(|_| ParseResponseError::ParseError("Invalid firmware storage type")),
2951 _ => Err(ParseResponseError::DataLengthMismatch(
2952 0,
2953 response_payload.len(),
2954 )),
2955 }
2956 }
2957}
2958
2959#[derive(Debug)]
2960pub struct UploadFirmwareCommand {
2961 buffer: [u8; 130], data_len: u8,
2963}
2964impl UploadFirmwareCommand {
2965 pub fn new(block: u8, line: u8, data: &[u8]) -> Result<Self, ()> {
2966 const MAX_PAYLOAD_SIZE: usize = 128;
2967 const COMMAND_BUFFER_SIZE: usize = 130;
2968
2969 if data.len() > MAX_PAYLOAD_SIZE {
2970 return Err(());
2971 }
2972
2973 let mut buffer = [0u8; COMMAND_BUFFER_SIZE];
2974 buffer[0] = block;
2975 buffer[1] = line;
2976
2977 let payload_start = 2;
2978 buffer[payload_start..payload_start + data.len()].copy_from_slice(data);
2979
2980 Ok(UploadFirmwareCommand {
2981 buffer,
2982 data_len: (2 + data.len()) as u8, })
2984 }
2985}
2986impl Command for UploadFirmwareCommand {
2987 type Response = ();
2988
2989 fn header(&self) -> Header {
2990 Header::UploadBillTables
2991 }
2992
2993 fn data(&self) -> &[u8] {
2994 &self.buffer[..self.data_len as usize]
2995 }
2996
2997 fn parse_response(
2998 &self,
2999 response_payload: &[u8],
3000 ) -> Result<Self::Response, ParseResponseError> {
3001 if response_payload.is_empty() {
3002 Ok(())
3003 } else {
3004 Err(ParseResponseError::DataLengthMismatch(
3005 0,
3006 response_payload.len(),
3007 ))
3008 }
3009 }
3010}
3011
3012#[derive(Debug)]
3013pub struct BeginFirmwareUpgradeCommand {
3014 buffer: [u8; 1],
3015 has_module_identifier: bool,
3016}
3017impl BeginFirmwareUpgradeCommand {
3018 pub fn new() -> Self {
3019 BeginFirmwareUpgradeCommand {
3020 buffer: [0],
3021 has_module_identifier: false,
3022 }
3023 }
3024
3025 pub fn new_with_module_identifier(module_identifier: u8) -> Self {
3026 BeginFirmwareUpgradeCommand {
3027 buffer: [module_identifier],
3028 has_module_identifier: true,
3029 }
3030 }
3031}
3032
3033impl Default for BeginFirmwareUpgradeCommand {
3034 fn default() -> Self {
3035 Self::new()
3036 }
3037}
3038impl Command for BeginFirmwareUpgradeCommand {
3039 type Response = ();
3040
3041 fn header(&self) -> Header {
3042 Header::BeginFirmwareUpgrade
3043 }
3044
3045 fn data(&self) -> &[u8] {
3046 if self.has_module_identifier {
3047 &self.buffer[..]
3048 } else {
3049 &[]
3050 }
3051 }
3052
3053 fn parse_response(&self, payload: &[u8]) -> Result<Self::Response, ParseResponseError> {
3054 match payload.len() {
3055 0 => Ok(()),
3056 _ => Err(ParseResponseError::DataLengthMismatch(0, payload.len())),
3057 }
3058 }
3059}
3060
3061#[derive(Debug)]
3062pub struct FinishFirmwareUpgradeCommand;
3063impl Command for FinishFirmwareUpgradeCommand {
3064 type Response = ();
3065
3066 fn header(&self) -> Header {
3067 Header::FinishFirmwareUpgrade
3068 }
3069
3070 fn data(&self) -> &[u8] {
3071 &[]
3072 }
3073
3074 fn parse_response(
3075 &self,
3076 response_payload: &[u8],
3077 ) -> Result<Self::Response, ParseResponseError> {
3078 match response_payload.len() {
3079 0 => Ok(()),
3080 _ => Err(ParseResponseError::DataLengthMismatch(
3081 0,
3082 response_payload.len(),
3083 )),
3084 }
3085 }
3086}
3087
3088#[derive(Debug)]
3089pub struct SetAcceptLimitCommand {
3090 buffer: [u8; 1],
3091}
3092impl SetAcceptLimitCommand {
3093 pub fn new(limit: u8) -> Self {
3094 SetAcceptLimitCommand { buffer: [limit] }
3095 }
3096}
3097impl Command for SetAcceptLimitCommand {
3098 type Response = ();
3099
3100 fn header(&self) -> Header {
3101 Header::SetAcceptLimit
3102 }
3103
3104 fn data(&self) -> &[u8] {
3105 &self.buffer
3106 }
3107
3108 fn parse_response(
3109 &self,
3110 response_payload: &[u8],
3111 ) -> Result<Self::Response, ParseResponseError> {
3112 match response_payload.len() {
3113 0 => Ok(()),
3114 _ => Err(ParseResponseError::DataLengthMismatch(
3115 0,
3116 response_payload.len(),
3117 )),
3118 }
3119 }
3120}
3121
3122#[derive(Debug)]
3123pub struct DispenseHopperValueCommand {
3124 buffer: [u8; 10],
3125}
3126impl DispenseHopperValueCommand {
3127 pub fn new(coin_value: u16) -> Self {
3128 DispenseHopperValueCommand {
3129 buffer: [
3130 0,
3131 0,
3132 0,
3133 0,
3134 0,
3135 0,
3136 0,
3137 0,
3138 (coin_value & 0xFF) as u8,
3140 ((coin_value >> 8) & 0xFF) as u8,
3141 ],
3142 }
3143 }
3144
3145 pub fn new_with_security_code(security_code: [u8; 8], coin_value: u16) -> Self {
3146 DispenseHopperValueCommand {
3147 buffer: [
3148 security_code[0],
3149 security_code[1],
3150 security_code[2],
3151 security_code[3],
3152 security_code[4],
3153 security_code[5],
3154 security_code[6],
3155 security_code[7],
3156 (coin_value & 0xFF) as u8,
3158 ((coin_value >> 8) & 0xFF) as u8,
3159 ],
3160 }
3161 }
3162}
3163impl Command for DispenseHopperValueCommand {
3164 type Response = Option<u8>;
3165
3166 fn header(&self) -> Header {
3167 Header::DispenseHopperValue
3168 }
3169
3170 fn data(&self) -> &[u8] {
3171 &self.buffer
3172 }
3173
3174 fn parse_response(
3175 &self,
3176 response_payload: &[u8],
3177 ) -> Result<Self::Response, ParseResponseError> {
3178 match response_payload.len() {
3179 0 => Ok(None),
3180 1 => Ok(Some(response_payload[0])),
3181 _ => Err(ParseResponseError::DataLengthMismatch(
3182 0,
3183 response_payload.len(),
3184 )),
3185 }
3186 }
3187}
3188
3189#[derive(Debug)]
3190pub struct RequestHopperPollingValueCommand;
3191impl Command for RequestHopperPollingValueCommand {
3192 type Response = HopperDispenseValueStatus;
3193
3194 fn header(&self) -> Header {
3195 Header::RequestHopperPollingValue
3196 }
3197
3198 fn data(&self) -> &[u8] {
3199 &[]
3200 }
3201
3202 fn parse_response(
3203 &self,
3204 response_payload: &[u8],
3205 ) -> Result<Self::Response, ParseResponseError> {
3206 match response_payload.len() {
3207 7 => Ok(HopperDispenseValueStatus::from([
3208 response_payload[0],
3209 response_payload[1],
3210 response_payload[2],
3211 response_payload[3],
3212 response_payload[4],
3213 response_payload[5],
3214 response_payload[6],
3215 ])),
3216 _ => Err(ParseResponseError::DataLengthMismatch(
3217 7,
3218 response_payload.len(),
3219 )),
3220 }
3221 }
3222}
3223
3224#[derive(Debug)]
3225pub struct EmergencyStopValueCommand;
3226impl Command for EmergencyStopValueCommand {
3227 type Response = u16;
3228
3229 fn header(&self) -> Header {
3230 Header::EmergencyStopValue
3231 }
3232
3233 fn data(&self) -> &[u8] {
3234 &[]
3235 }
3236
3237 fn parse_response(
3238 &self,
3239 response_payload: &[u8],
3240 ) -> Result<Self::Response, ParseResponseError> {
3241 match response_payload.len() {
3242 2 => Ok(u16::from_le_bytes([
3243 response_payload[0],
3244 response_payload[1],
3245 ])),
3246 _ => Err(ParseResponseError::DataLengthMismatch(
3247 2,
3248 response_payload.len(),
3249 )),
3250 }
3251 }
3252}
3253
3254#[derive(Debug)]
3255pub struct RequestHopperCoinValueCommand {
3256 buffer: [u8; 1],
3257}
3258impl RequestHopperCoinValueCommand {
3259 pub fn new(coin_type: u8) -> Self {
3260 RequestHopperCoinValueCommand {
3261 buffer: [coin_type],
3262 }
3263 }
3264}
3265impl Command for RequestHopperCoinValueCommand {
3266 type Response = (CurrencyToken, u16); fn header(&self) -> Header {
3269 Header::RequestHopperCoinValue
3270 }
3271
3272 fn data(&self) -> &[u8] {
3273 &self.buffer
3274 }
3275
3276 fn parse_response(
3277 &self,
3278 response_payload: &[u8],
3279 ) -> Result<Self::Response, ParseResponseError> {
3280 match response_payload.len() {
3281 8 => {
3282 let coin_str = core::str::from_utf8(&response_payload[0..=6])
3283 .map_err(|_| ParseResponseError::ParseError("Invalid UTF-8 in coin string"))?;
3284 let token = CurrencyToken::build(coin_str).map_err(|err| match err {
3285 CurrencyTokenError::InvalidFormat => {
3286 ParseResponseError::ParseError("invalid coin string format")
3287 }
3288 CurrencyTokenError::ValueStringTooSmall => ParseResponseError::BufferTooSmall,
3289 CurrencyTokenError::CoinNotSupportedByDevice => {
3290 ParseResponseError::ParseError("not supported by device")
3291 }
3292 })?;
3293 let value = u16::from_le_bytes([response_payload[6], response_payload[7]]);
3294 Ok((token, value))
3295 }
3296 _ => Err(ParseResponseError::DataLengthMismatch(
3297 8,
3298 response_payload.len(),
3299 )),
3300 }
3301 }
3302}
3303
3304#[derive(Debug)]
3305pub struct RequestIndexedHopperDispenseCountCommand {
3306 buffer: [u8; 1],
3307}
3308impl RequestIndexedHopperDispenseCountCommand {
3309 pub fn new(coin_type: u8) -> Self {
3310 RequestIndexedHopperDispenseCountCommand {
3311 buffer: [coin_type],
3312 }
3313 }
3314}
3315impl Command for RequestIndexedHopperDispenseCountCommand {
3316 type Response = u32; fn header(&self) -> Header {
3319 Header::RequestIndexedHopperDispenseCount
3320 }
3321
3322 fn data(&self) -> &[u8] {
3323 &self.buffer
3324 }
3325
3326 fn parse_response(
3327 &self,
3328 response_payload: &[u8],
3329 ) -> Result<Self::Response, ParseResponseError> {
3330 match response_payload.len() {
3331 3 => Ok(u32::from_le_bytes([
3332 response_payload[0],
3333 response_payload[1],
3334 response_payload[2],
3335 0,
3336 ])),
3337 _ => Err(ParseResponseError::DataLengthMismatch(
3338 3,
3339 response_payload.len(),
3340 )),
3341 }
3342 }
3343}
3344
3345#[derive(Debug)]
3346pub struct ReadBarcodeDataCommand;
3347impl Command for ReadBarcodeDataCommand {
3348 type Response = ();
3349
3350 fn header(&self) -> Header {
3351 Header::ReadBarCodeData
3352 }
3353
3354 fn data(&self) -> &[u8] {
3355 &[]
3356 }
3357
3358 fn parse_response(&self, _: &[u8]) -> Result<Self::Response, ParseResponseError> {
3360 Ok(())
3361 }
3362}
3363
3364#[derive(Debug)]
3365pub struct RequestMoneyInCommand;
3366impl Command for RequestMoneyInCommand {
3367 type Response = u32;
3368
3369 fn header(&self) -> Header {
3370 Header::RequestMoneyIn
3371 }
3372
3373 fn data(&self) -> &[u8] {
3374 &[]
3375 }
3376
3377 fn parse_response(
3378 &self,
3379 response_payload: &[u8],
3380 ) -> Result<Self::Response, ParseResponseError> {
3381 match response_payload.len() {
3382 4 => Ok(u32::from_le_bytes([
3383 response_payload[0],
3384 response_payload[1],
3385 response_payload[2],
3386 response_payload[3],
3387 ])),
3388 _ => Err(ParseResponseError::DataLengthMismatch(
3389 4,
3390 response_payload.len(),
3391 )),
3392 }
3393 }
3394}
3395
3396#[derive(Debug)]
3397pub struct RequestMoneyOutCommand;
3398impl Command for RequestMoneyOutCommand {
3399 type Response = u32;
3400
3401 fn header(&self) -> Header {
3402 Header::RequestMoneyOut
3403 }
3404
3405 fn data(&self) -> &[u8] {
3406 &[]
3407 }
3408
3409 fn parse_response(
3410 &self,
3411 response_payload: &[u8],
3412 ) -> Result<Self::Response, ParseResponseError> {
3413 match response_payload.len() {
3414 4 => Ok(u32::from_le_bytes([
3415 response_payload[0],
3416 response_payload[1],
3417 response_payload[2],
3418 response_payload[3],
3419 ])),
3420 _ => Err(ParseResponseError::DataLengthMismatch(
3421 4,
3422 response_payload.len(),
3423 )),
3424 }
3425 }
3426}
3427
3428#[derive(Debug)]
3429pub struct ClearMoneyCountersCommand;
3430impl Command for ClearMoneyCountersCommand {
3431 type Response = ();
3432
3433 fn header(&self) -> Header {
3434 Header::ClearMoneyCounters
3435 }
3436
3437 fn data(&self) -> &[u8] {
3438 &[]
3439 }
3440
3441 fn parse_response(
3442 &self,
3443 response_payload: &[u8],
3444 ) -> Result<Self::Response, ParseResponseError> {
3445 if response_payload.is_empty() {
3446 Ok(())
3447 } else {
3448 Err(ParseResponseError::DataLengthMismatch(
3449 0,
3450 response_payload.len(),
3451 ))
3452 }
3453 }
3454}
3455
3456#[derive(Debug)]
3457pub struct PayMoneyOutCommand {
3458 buffer: [u8; 4],
3459}
3460impl PayMoneyOutCommand {
3461 pub fn new(amount: u32) -> Self {
3462 PayMoneyOutCommand {
3463 buffer: amount.to_le_bytes(),
3464 }
3465 }
3466}
3467impl Command for PayMoneyOutCommand {
3468 type Response = ();
3469
3470 fn header(&self) -> Header {
3471 Header::PayMoneyOut
3472 }
3473
3474 fn data(&self) -> &[u8] {
3475 &self.buffer
3476 }
3477
3478 fn parse_response(
3479 &self,
3480 response_payload: &[u8],
3481 ) -> Result<Self::Response, ParseResponseError> {
3482 if response_payload.is_empty() {
3483 Ok(())
3484 } else {
3485 Err(ParseResponseError::DataLengthMismatch(
3486 0,
3487 response_payload.len(),
3488 ))
3489 }
3490 }
3491}
3492
3493#[derive(Debug)]
3494pub struct VerifyMoneyOutCommand;
3495impl Command for VerifyMoneyOutCommand {
3496 type Response = ChangerPollResult;
3497
3498 fn header(&self) -> Header {
3499 Header::VerifyMoneyOut
3500 }
3501
3502 fn data(&self) -> &[u8] {
3503 &[]
3504 }
3505
3506 fn parse_response(
3507 &self,
3508 response_payload: &[u8],
3509 ) -> Result<Self::Response, ParseResponseError> {
3510 match response_payload.len() {
3511 9 => ChangerPollResult::try_from(response_payload)
3512 .map_err(|_| ParseResponseError::ParseError("Invalid ChangerPollResult format")),
3513 _ => Err(ParseResponseError::DataLengthMismatch(
3514 9,
3515 response_payload.len(),
3516 )),
3517 }
3518 }
3519}
3520
3521#[derive(Debug)]
3522pub struct RequestActivityRegisterCommand;
3523impl Command for RequestActivityRegisterCommand {
3524 type Response = heapless::Vec<ChangerFlags, 13>;
3525
3526 fn header(&self) -> Header {
3527 Header::RequestActivityRegister
3528 }
3529
3530 fn data(&self) -> &[u8] {
3531 &[]
3532 }
3533
3534 fn parse_response(
3535 &self,
3536 response_payload: &[u8],
3537 ) -> Result<Self::Response, ParseResponseError> {
3538 match response_payload.len() {
3539 2 => Ok(parse_changer_flags_heapless(response_payload)),
3540 _ => Err(ParseResponseError::DataLengthMismatch(
3541 2,
3542 response_payload.len(),
3543 )),
3544 }
3545 }
3546}
3547
3548#[derive(Debug)]
3549pub struct RequestErrorStatusCommand;
3550impl Command for RequestErrorStatusCommand {
3551 type Response = (ChangerDevice, ChangerError);
3552
3553 fn header(&self) -> Header {
3554 Header::RequestErrorStatus
3555 }
3556
3557 fn data(&self) -> &[u8] {
3558 &[]
3559 }
3560
3561 fn parse_response(
3562 &self,
3563 response_payload: &[u8],
3564 ) -> Result<Self::Response, ParseResponseError> {
3565 match response_payload.len() {
3566 2 => Ok((
3567 ChangerDevice::from(response_payload[0]),
3568 ChangerError::from(response_payload[1]),
3569 )),
3570 _ => Err(ParseResponseError::DataLengthMismatch(
3571 2,
3572 response_payload.len(),
3573 )),
3574 }
3575 }
3576}
3577
3578#[derive(Debug)]
3579pub struct PurgeHopperCommand {
3580 buffer: [u8; 2],
3581}
3582impl PurgeHopperCommand {
3583 pub fn new(hopper_number: u8, count: u8) -> Self {
3586 PurgeHopperCommand {
3587 buffer: [hopper_number, count],
3588 }
3589 }
3590}
3591impl Command for PurgeHopperCommand {
3592 type Response = ();
3593
3594 fn header(&self) -> Header {
3595 Header::PurgeHopper
3596 }
3597
3598 fn data(&self) -> &[u8] {
3599 &self.buffer
3600 }
3601
3602 fn parse_response(
3603 &self,
3604 response_payload: &[u8],
3605 ) -> Result<Self::Response, ParseResponseError> {
3606 match response_payload.len() {
3607 0 => Ok(()),
3608 _ => Err(ParseResponseError::DataLengthMismatch(
3609 0,
3610 response_payload.len(),
3611 )),
3612 }
3613 }
3614}
3615
3616#[derive(Debug)]
3617pub struct ModifyHopperBalanceCommand {
3618 buffer: [u8; 3],
3619}
3620impl ModifyHopperBalanceCommand {
3621 pub fn new(hopper_number: u8, balance: u16) -> Self {
3622 ModifyHopperBalanceCommand {
3623 buffer: [
3624 hopper_number,
3625 (balance & 0xFF) as u8,
3626 ((balance >> 8) & 0xFF) as u8,
3627 ],
3628 }
3629 }
3630}
3631impl Command for ModifyHopperBalanceCommand {
3632 type Response = ();
3633
3634 fn header(&self) -> Header {
3635 Header::ModifyHopperBalance
3636 }
3637
3638 fn data(&self) -> &[u8] {
3639 &self.buffer
3640 }
3641
3642 fn parse_response(
3643 &self,
3644 response_payload: &[u8],
3645 ) -> Result<Self::Response, ParseResponseError> {
3646 match response_payload.len() {
3647 0 => Ok(()),
3648 _ => Err(ParseResponseError::DataLengthMismatch(
3649 0,
3650 response_payload.len(),
3651 )),
3652 }
3653 }
3654}
3655
3656#[derive(Debug)]
3657pub struct RequestHopperBalanceCommand {
3658 buffer: [u8; 1],
3659}
3660impl RequestHopperBalanceCommand {
3661 pub fn new(hopper_number: u8) -> Self {
3662 RequestHopperBalanceCommand {
3663 buffer: [hopper_number],
3664 }
3665 }
3666}
3667impl Command for RequestHopperBalanceCommand {
3668 type Response = (CurrencyToken, u16); fn header(&self) -> Header {
3671 Header::RequestHopperBalance
3672 }
3673
3674 fn data(&self) -> &[u8] {
3675 &self.buffer
3676 }
3677
3678 fn parse_response(
3679 &self,
3680 response_payload: &[u8],
3681 ) -> Result<Self::Response, ParseResponseError> {
3682 match response_payload.len() {
3683 8 => {
3684 let coin_str = core::str::from_utf8(&response_payload[0..6])
3685 .map_err(|_| ParseResponseError::ParseError("Invalid UTF-8 in coin string"))?;
3686 let token = CurrencyToken::build(coin_str).map_err(|err| match err {
3687 CurrencyTokenError::InvalidFormat => {
3688 ParseResponseError::ParseError("invalid coin string format")
3689 }
3690 CurrencyTokenError::ValueStringTooSmall => ParseResponseError::BufferTooSmall,
3691 CurrencyTokenError::CoinNotSupportedByDevice => {
3692 ParseResponseError::ParseError("not supported by device")
3693 }
3694 })?;
3695 let count = u16::from_le_bytes([response_payload[6], response_payload[7]]);
3696
3697 Ok((token, count))
3698 }
3699 _ => Err(ParseResponseError::DataLengthMismatch(
3700 8,
3701 response_payload.len(),
3702 )),
3703 }
3704 }
3705}
3706
3707#[derive(Debug)]
3708pub struct ModifyCashBoxValueCommand {
3709 buffer: [u8; 4],
3710}
3711impl ModifyCashBoxValueCommand {
3712 pub fn new(value: u32) -> Self {
3713 ModifyCashBoxValueCommand {
3714 buffer: value.to_le_bytes(),
3715 }
3716 }
3717}
3718impl Command for ModifyCashBoxValueCommand {
3719 type Response = ();
3720
3721 fn header(&self) -> Header {
3722 Header::ModifyCashBoxValue
3723 }
3724
3725 fn data(&self) -> &[u8] {
3726 &self.buffer
3727 }
3728
3729 fn parse_response(
3730 &self,
3731 response_payload: &[u8],
3732 ) -> Result<Self::Response, ParseResponseError> {
3733 if response_payload.is_empty() {
3734 Ok(())
3735 } else {
3736 Err(ParseResponseError::DataLengthMismatch(
3737 0,
3738 response_payload.len(),
3739 ))
3740 }
3741 }
3742}
3743
3744#[derive(Debug)]
3745pub struct RequestCashBoxValueCommand;
3746impl Command for RequestCashBoxValueCommand {
3747 type Response = u32;
3748
3749 fn header(&self) -> Header {
3750 Header::RequestCashBoxValue
3751 }
3752
3753 fn data(&self) -> &[u8] {
3754 &[]
3755 }
3756
3757 fn parse_response(
3758 &self,
3759 response_payload: &[u8],
3760 ) -> Result<Self::Response, ParseResponseError> {
3761 match response_payload.len() {
3762 4 => Ok(u32::from_le_bytes([
3763 response_payload[0],
3764 response_payload[1],
3765 response_payload[2],
3766 response_payload[3],
3767 ])),
3768 _ => Err(ParseResponseError::DataLengthMismatch(
3769 4,
3770 response_payload.len(),
3771 )),
3772 }
3773 }
3774}
3775
3776#[derive(Debug)]
3777pub struct ModifyRtcCommand {
3778 buffer: [u8; 4],
3779}
3780impl ModifyRtcCommand {
3781 pub fn new(unix_epoch_seconds: u32) -> Self {
3782 ModifyRtcCommand {
3783 buffer: unix_epoch_seconds.to_le_bytes(),
3784 }
3785 }
3786}
3787impl Command for ModifyRtcCommand {
3788 type Response = ();
3789
3790 fn header(&self) -> Header {
3791 Header::ModifyRealTimeClock
3792 }
3793
3794 fn data(&self) -> &[u8] {
3795 &self.buffer
3796 }
3797
3798 fn parse_response(
3799 &self,
3800 response_payload: &[u8],
3801 ) -> Result<Self::Response, ParseResponseError> {
3802 match response_payload.len() {
3803 0 => Ok(()),
3804 _ => Err(ParseResponseError::DataLengthMismatch(
3805 0,
3806 response_payload.len(),
3807 )),
3808 }
3809 }
3810}
3811
3812#[derive(Debug)]
3813pub struct RequestRtcCommand;
3814impl Command for RequestRtcCommand {
3815 type Response = u32; fn header(&self) -> Header {
3818 Header::RequestRealTimeClock
3819 }
3820
3821 fn data(&self) -> &[u8] {
3822 &[]
3823 }
3824
3825 fn parse_response(
3826 &self,
3827 response_payload: &[u8],
3828 ) -> Result<Self::Response, ParseResponseError> {
3829 match response_payload.len() {
3830 4 => Ok(u32::from_le_bytes([
3831 response_payload[0],
3832 response_payload[1],
3833 response_payload[2],
3834 response_payload[3],
3835 ])),
3836 _ => Err(ParseResponseError::DataLengthMismatch(
3837 4,
3838 response_payload.len(),
3839 )),
3840 }
3841 }
3842}
3843
3844#[derive(Debug)]
3846pub struct ReadEncryptedEventsCommand;
3847#[derive(Debug)]
3848pub struct RequestEncryptedHopperStatusCommand;
3849#[derive(Debug)]
3850pub struct RequestEncryptedMonetaryIdCommand;
3851
3852#[repr(u8)]
3853#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3854#[cfg_attr(feature = "defmt", derive(defmt::Format))]
3855pub enum DivertMode {
3856 AcceptCoins = 0,
3857 ReturnCoins = 1,
3858}
3859#[derive(Debug)]
3860pub struct OperateEscrowCommand {
3861 buffer: [u8; 1],
3862}
3863impl OperateEscrowCommand {
3864 pub fn new(divert_mode: DivertMode) -> Self {
3865 OperateEscrowCommand {
3866 buffer: [divert_mode as u8],
3867 }
3868 }
3869}
3870impl Command for OperateEscrowCommand {
3871 type Response = ();
3872
3873 fn header(&self) -> Header {
3874 Header::OperateEscrow
3875 }
3876
3877 fn data(&self) -> &[u8] {
3878 &self.buffer
3879 }
3880
3881 fn parse_response(
3882 &self,
3883 response_payload: &[u8],
3884 ) -> Result<Self::Response, ParseResponseError> {
3885 match response_payload.len() {
3887 0 => Ok(()),
3888 _ => Err(ParseResponseError::DataLengthMismatch(
3889 0,
3890 response_payload.len(),
3891 )),
3892 }
3893 }
3894}
3895
3896#[derive(Debug)]
3897pub struct RequestEscrowStatusCommand;
3898impl Command for RequestEscrowStatusCommand {
3899 type Response = (EscrowOperatingStatus, EscrowLevelStatus, EscrowFaultCode);
3900
3901 fn header(&self) -> Header {
3902 Header::RequestEscrowStatus
3903 }
3904
3905 fn data(&self) -> &[u8] {
3906 &[]
3907 }
3908
3909 fn parse_response(
3910 &self,
3911 response_payload: &[u8],
3912 ) -> Result<Self::Response, ParseResponseError> {
3913 match response_payload.len() {
3914 3 => {
3915 let operating_status = EscrowOperatingStatus::try_from(response_payload[0])
3916 .map_err(|_| ParseResponseError::ParseError("Invalid EscrowOperatingStatus"))?;
3917 let level_status = EscrowLevelStatus::try_from(response_payload[1])
3918 .map_err(|_| ParseResponseError::ParseError("Invalid EscrowLevelStatus"))?;
3919 let fault_code = EscrowFaultCode::from(response_payload[2]);
3920
3921 Ok((operating_status, level_status, fault_code))
3922 }
3923 _ => Err(ParseResponseError::DataLengthMismatch(
3924 3,
3925 response_payload.len(),
3926 )),
3927 }
3928 }
3929}
3930
3931#[derive(Debug)]
3932pub struct RequestServiceStatusCommand {
3933 buffer: [u8; 1],
3934}
3935impl RequestServiceStatusCommand {
3936 pub fn new_report() -> Self {
3937 RequestServiceStatusCommand { buffer: [0] }
3938 }
3939
3940 pub fn new_clear_report() -> Self {
3941 RequestServiceStatusCommand { buffer: [1] }
3942 }
3943}
3944impl Command for RequestServiceStatusCommand {
3945 type Response = Option<EscrowServiceStatus>;
3946
3947 fn header(&self) -> Header {
3948 Header::RequestServiceStatus
3949 }
3950
3951 fn data(&self) -> &[u8] {
3952 &self.buffer
3953 }
3954
3955 fn parse_response(
3956 &self,
3957 response_payload: &[u8],
3958 ) -> Result<Self::Response, ParseResponseError> {
3959 match response_payload.len() {
3960 0 => Ok(None),
3961 1 => {
3962 let status = EscrowServiceStatus::try_from(response_payload[0])
3963 .map_err(|_| ParseResponseError::ParseError("Invalid EscrowServiceStatus"))?;
3964
3965 Ok(Some(status))
3966 }
3967 _ => Err(ParseResponseError::DataLengthMismatch(
3968 1,
3969 response_payload.len(),
3970 )),
3971 }
3972 }
3973}
3974
3975#[derive(Debug)]
3976pub struct ClearCommsStatusVariablesCommand;
3977impl Command for ClearCommsStatusVariablesCommand {
3978 type Response = ();
3979
3980 fn header(&self) -> Header {
3981 Header::ClearCommsStatusVariable
3982 }
3983
3984 fn data(&self) -> &[u8] {
3985 &[]
3986 }
3987
3988 fn parse_response(
3989 &self,
3990 response_payload: &[u8],
3991 ) -> Result<Self::Response, ParseResponseError> {
3992 match response_payload.len() {
3993 0 => Ok(()),
3994 _ => Err(ParseResponseError::DataLengthMismatch(
3995 0,
3996 response_payload.len(),
3997 )),
3998 }
3999 }
4000}
4001
4002#[derive(Debug)]
4003pub struct RequestCommsStatusVariablesCommand;
4004impl Command for RequestCommsStatusVariablesCommand {
4005 type Response = (u8, u8, u8);
4006
4007 fn header(&self) -> Header {
4008 Header::RequestCommsStatusVariables
4009 }
4010
4011 fn data(&self) -> &[u8] {
4012 &[]
4013 }
4014
4015 fn parse_response(
4016 &self,
4017 response_payload: &[u8],
4018 ) -> Result<Self::Response, ParseResponseError> {
4019 match response_payload.len() {
4020 3 => Ok((
4021 response_payload[0],
4022 response_payload[1],
4023 response_payload[2],
4024 )),
4025 _ => Err(ParseResponseError::DataLengthMismatch(
4026 3,
4027 response_payload.len(),
4028 )),
4029 }
4030 }
4031}