Skip to main content

ebds/omnibus/
reply.rs

1use crate::std;
2use std::fmt;
3
4use crate::{
5    banknote::*, cash::CurrencyDenomination, impl_from_for_omnibus_reply, impl_message_ops,
6    impl_omnibus_reply_ops, len::OMNIBUS_REPLY, status::*, AdvancedBookmarkModeReply,
7    ClearAuditDataRequestAck, ClearAuditDataRequestResults, ExtendedNoteInhibitsReplyAlt,
8    ExtendedNoteReply, MessageOps, MessageType, NoteRetrievedEvent, NoteRetrievedReply,
9    QueryApplicationIdReply, QueryApplicationPartNumberReply, QueryBootPartNumberReply,
10    QueryDeviceCapabilitiesReply, QueryValueTableReply, QueryVariantIdReply, QueryVariantNameReply,
11    QueryVariantPartNumberReply, SetEscrowTimeoutReply, StandardDenomination,
12};
13
14pub mod index {
15    use crate::index::DATA;
16
17    pub const DEVICE_STATE: usize = DATA;
18    pub const DEVICE_STATUS: usize = DATA + 1;
19    pub const EXCEPTION_STATUS: usize = DATA + 2;
20    pub const MISC_DEVICE_STATE: usize = DATA + 3;
21    pub const MODEL_NUMBER: usize = DATA + 4;
22    pub const CODE_REVISION: usize = DATA + 5;
23}
24
25/// Omnibus Reply - (Type 2)
26///
27/// [OmnibusReply] represents a message sent from the device back to the hostl
28///
29/// The most common reply to an [OmnibusCommand](crate::OmnibusCommand) is the standard reply.
30///
31/// However, if barcode vouchers, extended note, extended coupon reporting is enabled in the standard
32/// omnibus command, or if the unit is an SCR, then other reply formats are possible.
33///
34/// These replies are detailed in sections 7.5.1, 7.5.2, 7.5.4, and 7.5.15 respectively.
35///
36/// There are also other circumstances that may result in the device responding back
37/// to the host with a different type of message. These special cases will be described in a future section
38/// when the associated feature is enabled.
39///
40/// The Omnibus Reply is formatted as follows:
41///
42/// | Name  | STX  | LEN  | CTRL | Data 0 | Data 1 | Data 2 | Data 3 | Data 4 | Data 5 | ETX  | CHK |
43/// |:------|:----:|:----:|:----:|:------:|:------:|:------:|:------:|:------:|:------:|:----:|:---:|
44/// | Byte  | 0    | 1    | 2    | 4      | 5      | 6      | 7      | 8      | 9      | 10   | 11  |
45/// | Value | 0x02 | 0x09 | 0x1n | nn     | nn     | nn     | nn     | nn     | nn     | 0x03 | zz  |
46///
47/// The data bytes are bitfields representing device information:
48///
49/// * Data byte 0: [DeviceState]
50/// * Data byte 1: [DeviceStatus]
51/// * Data byte 2: [ExceptionStatus]
52/// * Data byte 3: [MiscDeviceState]
53/// * Data byte 4: [ModelNumber]
54/// * Data byte 5: [CodeRevision]
55#[derive(Clone, Copy, Debug, Default, PartialEq)]
56#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
57pub struct OmnibusReply {
58    buf: [u8; OMNIBUS_REPLY],
59}
60
61impl OmnibusReply {
62    /// Create a new OmnibusReply message
63    pub fn new() -> Self {
64        let mut message = Self {
65            buf: [0u8; OMNIBUS_REPLY],
66        };
67
68        message.init();
69        message.set_message_type(MessageType::OmnibusReply);
70
71        message
72    }
73}
74
75impl_from_for_omnibus_reply!(AdvancedBookmarkModeReply);
76impl_from_for_omnibus_reply!(ClearAuditDataRequestAck);
77impl_from_for_omnibus_reply!(ClearAuditDataRequestResults);
78impl_from_for_omnibus_reply!(ExtendedNoteReply);
79impl_from_for_omnibus_reply!(ExtendedNoteInhibitsReplyAlt);
80impl_from_for_omnibus_reply!(NoteRetrievedReply);
81impl_from_for_omnibus_reply!(NoteRetrievedEvent);
82impl_from_for_omnibus_reply!(QueryValueTableReply);
83impl_from_for_omnibus_reply!(SetEscrowTimeoutReply);
84impl_from_for_omnibus_reply!(QueryBootPartNumberReply);
85impl_from_for_omnibus_reply!(QueryApplicationPartNumberReply);
86impl_from_for_omnibus_reply!(QueryVariantNameReply);
87impl_from_for_omnibus_reply!(QueryVariantPartNumberReply);
88impl_from_for_omnibus_reply!(QueryDeviceCapabilitiesReply);
89impl_from_for_omnibus_reply!(QueryApplicationIdReply);
90impl_from_for_omnibus_reply!(QueryVariantIdReply);
91
92impl fmt::Display for OmnibusReply {
93    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94        write!(
95            f,
96            "AckNak: {}, DeviceType: {}, MessageType: {}, DeviceState: {}, DeviceStatus: {}, ExceptionStatus: {}, MiscDeviceState: {}, ModelNumber: {}, CodeRevision: {}",
97            self.acknak(),
98            self.device_type(),
99            self.message_type(),
100            self.device_state(),
101            self.device_status(),
102            self.exception_status(),
103            self.misc_device_state(),
104            self.model_number(),
105            self.code_revision(),
106        )
107    }
108}
109
110pub trait OmnibusReplyOps: MessageOps {
111    /// Get the device state data field
112    fn device_state(&self) -> DeviceState {
113        self.buf()[index::DEVICE_STATE].into()
114    }
115
116    /// Set the device state data field
117    fn set_device_state(&mut self, device_state: DeviceState) {
118        self.buf_mut()[index::DEVICE_STATE] = device_state.into();
119    }
120
121    /// Get the idling device state data field
122    fn idling(&self) -> Idling {
123        self.device_state().idling().into()
124    }
125
126    /// Get the idling device state data field
127    fn set_idling(&mut self, idling: Idling) {
128        let mut state = self.device_state();
129        state.set_idling(idling.into());
130        self.set_device_state(state);
131    }
132
133    /// Get the accepting device state data field
134    fn accepting(&self) -> Accepting {
135        self.device_state().accepting().into()
136    }
137
138    /// Get the accepting device state data field
139    fn set_accepting(&mut self, accepting: Accepting) {
140        let mut state = self.device_state();
141        state.set_accepting(accepting.into());
142        self.set_device_state(state);
143    }
144
145    /// Get the escrowed state device state data field
146    fn escrowed_state(&self) -> EscrowedState {
147        self.device_state().escrowed_state().into()
148    }
149
150    /// Get the escrowed state device state data field
151    fn set_escrowed_state(&mut self, escrowed_state: EscrowedState) {
152        let mut state = self.device_state();
153        state.set_escrowed_state(escrowed_state.into());
154        self.set_device_state(state);
155    }
156
157    /// Get the stacking device state data field
158    fn stacking(&self) -> Stacking {
159        self.device_state().stacking().into()
160    }
161
162    /// Get the stacking device state data field
163    fn set_stacking(&mut self, stacking: Stacking) {
164        let mut state = self.device_state();
165        state.set_stacking(stacking.into());
166        self.set_device_state(state);
167    }
168
169    /// Get the stacked event device state data field
170    fn stacked_event(&self) -> StackedEvent {
171        self.device_state().stacked_event().into()
172    }
173
174    /// Get the stacked event device state data field
175    fn set_stacked_event(&mut self, stacked_event: StackedEvent) {
176        let mut state = self.device_state();
177        state.set_stacked_event(stacked_event.into());
178        self.set_device_state(state);
179    }
180
181    /// Get the returning device state data field
182    fn returning(&self) -> Returning {
183        self.device_state().returning().into()
184    }
185
186    /// Get the returning device state data field
187    fn set_returning(&mut self, returning: Returning) {
188        let mut state = self.device_state();
189        state.set_returning(returning.into());
190        self.set_device_state(state);
191    }
192
193    /// Get the returned event device state data field
194    fn returned_event(&self) -> ReturnedEvent {
195        self.device_state().returned_event().into()
196    }
197
198    /// Get the returned event device state data field
199    fn set_returned_event(&mut self, returned_event: ReturnedEvent) {
200        let mut state = self.device_state();
201        state.set_returned_event(returned_event.into());
202        self.set_device_state(state);
203    }
204
205    /// Get the device status data field
206    fn device_status(&self) -> DeviceStatus {
207        self.buf()[index::DEVICE_STATUS].into()
208    }
209
210    fn set_device_status(&mut self, device_status: DeviceStatus) {
211        self.buf_mut()[index::DEVICE_STATUS] = device_status.into();
212    }
213
214    /// Get the cheated device status data field
215    fn cheated(&self) -> Cheated {
216        self.device_status().cheated().into()
217    }
218
219    /// Set the cheated device status data field
220    fn set_cheated(&mut self, cheated: Cheated) {
221        let mut status = self.device_status();
222        status.set_cheated(cheated.into());
223        self.set_device_status(status);
224    }
225
226    /// Get the rejected device status data field
227    fn rejected(&self) -> Rejected {
228        self.device_status().rejected().into()
229    }
230
231    /// Set the rejected device status data field
232    fn set_rejected(&mut self, rejected: Rejected) {
233        let mut status = self.device_status();
234        status.set_rejected(rejected.into());
235        self.set_device_status(status);
236    }
237
238    /// Get the jammed device status data field
239    fn jammed(&self) -> Jammed {
240        self.device_status().jammed().into()
241    }
242
243    /// Set the jammed device status data field
244    fn set_jammed(&mut self, jammed: Jammed) {
245        let mut status = self.device_status();
246        status.set_jammed(jammed.into());
247        self.set_device_status(status);
248    }
249
250    /// Get the stacker full device status data field
251    fn stacker_full(&self) -> StackerFull {
252        self.device_status().stacker_full().into()
253    }
254
255    /// Set the stacker full device status data field
256    fn set_stacker_full(&mut self, stacker_full: StackerFull) {
257        let mut status = self.device_status();
258        status.set_stacker_full(stacker_full.into());
259        self.set_device_status(status);
260    }
261
262    /// Get the cassette attached device status data field
263    fn cassette_attached(&self) -> CassetteAttached {
264        self.device_status().cassette_attached().into()
265    }
266
267    /// Set the cassette attached device status data field
268    fn set_cassette_attached(&mut self, cassette_attached: CassetteAttached) {
269        let mut status = self.device_status();
270        status.set_cassette_attached(cassette_attached.into());
271        self.set_device_status(status);
272    }
273
274    /// Get the status of the cash box
275    fn cash_box_status(&self) -> CashBoxStatus {
276        let status = self.device_status();
277
278        if status.stacker_full() {
279            CashBoxStatus::Full
280        } else if status.cassette_attached() {
281            CashBoxStatus::Attached
282        } else {
283            CashBoxStatus::Removed
284        }
285    }
286
287    /// Get the paused device status data field
288    fn paused(&self) -> Paused {
289        self.device_status().paused().into()
290    }
291
292    /// Set the paused device status data field
293    fn set_paused(&mut self, paused: Paused) {
294        let mut status = self.device_status();
295        status.set_paused(paused.into());
296        self.set_device_status(status);
297    }
298
299    /// Get the calibration in progress device status data field
300    fn calibration(&self) -> Calibration {
301        self.device_status().calibration().into()
302    }
303
304    /// Set the calibration in progress device status data field
305    fn set_calibration(&mut self, calibration: Calibration) {
306        let mut status = self.device_status();
307        status.set_calibration(calibration.into());
308        self.set_device_status(status);
309    }
310
311    /// Get the exception status data field
312    fn exception_status(&self) -> ExceptionStatus {
313        self.buf()[index::EXCEPTION_STATUS].into()
314    }
315
316    fn set_exception_status(&mut self, exception_status: ExceptionStatus) {
317        self.buf_mut()[index::EXCEPTION_STATUS] = exception_status.into();
318    }
319
320    /// Get the power up status data field
321    fn power_up(&self) -> PowerUpStatus {
322        self.exception_status().power_up().into()
323    }
324
325    /// Set the power up status data field
326    fn set_power_up(&mut self, power_up: PowerUpStatus) {
327        let mut ex = self.exception_status();
328        ex.set_power_up(power_up.into());
329        self.set_exception_status(ex);
330    }
331
332    /// Get the invalid command data field
333    fn invalid_command(&self) -> InvalidCommand {
334        self.exception_status().invalid_command().into()
335    }
336
337    /// Set the invalid command data field
338    fn set_invalid_command(&mut self, invalid_command: InvalidCommand) {
339        let mut ex = self.exception_status();
340        ex.set_invalid_command(invalid_command.into());
341        self.set_exception_status(ex);
342    }
343
344    /// Get the failure data field
345    fn failure(&self) -> Failure {
346        self.exception_status().failure().into()
347    }
348
349    /// Set the failure data field
350    fn set_failure(&mut self, failure: Failure) {
351        let mut ex = self.exception_status();
352        ex.set_failure(failure.into());
353        self.set_exception_status(ex);
354    }
355
356    /// Get the note value data field
357    fn note_value(&self) -> StandardDenomination {
358        self.exception_status().note_value().into()
359    }
360
361    /// Set the note value data field
362    fn set_note_value(&mut self, note_value: StandardDenomination) {
363        let mut ex = self.exception_status();
364        ex.set_note_value(note_value.into());
365        self.set_exception_status(ex);
366    }
367
368    /// Get the transport open data field
369    fn transport_open(&self) -> TransportOpen {
370        self.exception_status().transport_open().into()
371    }
372
373    /// Set the transport open data field
374    fn set_transport_open(&mut self, transport_open: TransportOpen) {
375        let mut ex = self.exception_status();
376        ex.set_transport_open(transport_open.into());
377        self.set_exception_status(ex);
378    }
379
380    /// Get the miscellaneous device status data field
381    fn misc_device_state(&self) -> MiscDeviceState {
382        self.buf()[index::MISC_DEVICE_STATE].into()
383    }
384
385    fn set_misc_device_state(&mut self, misc_device_state: MiscDeviceState) {
386        self.buf_mut()[index::MISC_DEVICE_STATE] = misc_device_state.into();
387    }
388
389    /// Get the stalled data field
390    fn stalled(&self) -> Stalled {
391        self.misc_device_state().stalled().into()
392    }
393
394    /// Set the stalled data field
395    fn set_stalled(&mut self, stalled: Stalled) {
396        let mut misc = self.misc_device_state();
397        misc.set_stalled(stalled.into());
398        self.set_misc_device_state(misc);
399    }
400
401    /// Get the flash download data field
402    fn flash_download(&self) -> FlashDownload {
403        self.misc_device_state().flash_download().into()
404    }
405
406    /// Set the flash download data field
407    fn set_flash_download(&mut self, flash_download: FlashDownload) {
408        let mut misc = self.misc_device_state();
409        misc.set_flash_download(flash_download.into());
410        self.set_misc_device_state(misc);
411    }
412
413    /// Get the pre-stack data field
414    fn pre_stack(&self) -> PreStack {
415        self.misc_device_state().pre_stack().into()
416    }
417
418    /// Set the pre-stack data field
419    fn set_pre_stack(&mut self, pre_stack: PreStack) {
420        let mut misc = self.misc_device_state();
421        misc.set_pre_stack(pre_stack.into());
422        self.set_misc_device_state(misc);
423    }
424
425    /// Get the raw barcode data field
426    fn raw_barcode(&self) -> RawBarcode {
427        self.misc_device_state().raw_barcode().into()
428    }
429
430    /// Set the raw barcode data field
431    fn set_raw_barcode(&mut self, raw_barcode: RawBarcode) {
432        let mut misc = self.misc_device_state();
433        misc.set_raw_barcode(raw_barcode.into());
434        self.set_misc_device_state(misc);
435    }
436
437    /// Get the device capabilities data field
438    fn device_capabilities(&self) -> DeviceCapabilities {
439        self.misc_device_state().device_capabilities().into()
440    }
441
442    /// Set the device capabilities data field
443    fn set_device_capabilities(&mut self, device_capabilities: DeviceCapabilities) {
444        let mut misc = self.misc_device_state();
445        misc.set_device_capabilities(device_capabilities.into());
446        self.set_misc_device_state(misc);
447    }
448
449    /// Get the disabled data field
450    fn disabled(&self) -> Disabled {
451        self.misc_device_state().disabled().into()
452    }
453
454    /// Set the disabled data field
455    fn set_disabled(&mut self, disabled: Disabled) {
456        let mut misc = self.misc_device_state();
457        misc.set_disabled(disabled.into());
458        self.set_misc_device_state(misc);
459    }
460
461    /// Get the model number data field
462    fn model_number(&self) -> ModelNumber {
463        self.buf()[index::MODEL_NUMBER].into()
464    }
465
466    /// Set the model number data field
467    fn set_model_number(&mut self, model_number: ModelNumber) {
468        self.buf_mut()[index::MODEL_NUMBER] = model_number.into();
469    }
470
471    /// Get the code revision data field
472    fn code_revision(&self) -> CodeRevision {
473        self.buf()[index::CODE_REVISION].into()
474    }
475
476    /// Set the code revision data field
477    fn set_code_revision(&mut self, code_revision: CodeRevision) {
478        self.buf_mut()[index::CODE_REVISION] = code_revision.into()
479    }
480}
481
482impl_message_ops!(OmnibusReply);
483impl_omnibus_reply_ops!(OmnibusReply);
484
485impl From<&OmnibusReply> for Banknote {
486    fn from(reply: &OmnibusReply) -> Self {
487        use crate::bau_currency;
488
489        let note_value = bau_currency().denomination_value_base(reply.note_value());
490        Self::default().with_value(note_value.into())
491    }
492}
493
494impl From<&dyn OmnibusReplyOps> for DocumentStatus {
495    fn from(reply: &dyn OmnibusReplyOps) -> Self {
496        Self::default().with_standard_denomination(reply.note_value())
497    }
498}
499
500#[cfg(test)]
501mod tests {
502    use super::*;
503    use crate::Result;
504
505    #[test]
506    #[rustfmt::skip]
507    fn test_omnibus_reply_from_buf() -> Result<()> {
508        let msg_bytes = [
509            // STX | LEN | Message Type
510            0x02, 0x0b, 0x20,
511            // Data
512            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
513            // ETX | Checksum
514            0x03, 0x2b,
515        ];
516
517        let mut msg = OmnibusReply::new();
518        msg.from_buf(msg_bytes.as_ref())?;
519
520        assert_eq!(msg.message_type(), MessageType::OmnibusReply);
521        assert_eq!(msg.device_state(), DeviceState::from(0));
522        assert_eq!(msg.device_status(), DeviceStatus::from(0));
523        assert_eq!(msg.exception_status(), ExceptionStatus::from(0));
524        assert_eq!(msg.misc_device_state(), MiscDeviceState::from(0));
525        assert_eq!(msg.model_number(), ModelNumber::from(0));
526        assert_eq!(msg.code_revision(), CodeRevision::from(0));
527
528        Ok(())
529    }
530}