1use crate::std;
2
3use crate::{
4    error::{Error, Result},
5    impl_default, impl_extended_ops, impl_message_ops, impl_omnibus_extended_command,
6    len::SET_EXTENDED_NOTE_INHIBITS_BASE,
7    std::fmt,
8    ExtendedCommand, ExtendedCommandOps, ExtendedNoteReporting, MessageOps, MessageType,
9    OmnibusCommandOps,
10};
11
12pub const CFSC_ENABLE_LEN: usize = 8;
14pub const SC_ENABLE_LEN: usize = 19;
16
17mod bitmask {
18    pub const ENABLE_NOTE: u8 = 0b111_1111;
19}
20
21pub mod index {
22    pub const ENABLE_NOTE: usize = 7;
23}
24
25bitfield! {
26    #[derive(Clone, Copy, Debug, Default, PartialEq)]
28    pub struct EnableNote(u16);
29    u16;
30    pub note1, set_note1: 0;
31    pub note2, set_note2: 1;
32    pub note3, set_note3: 2;
33    pub note4, set_note4: 3;
34    pub note5, set_note5: 4;
35    pub note6, set_note6: 5;
36    pub note7, set_note7: 6;
37    pub note_index, set_note_index: 15, 7;
38}
39
40impl EnableNote {
41    pub const LEN: usize = 7;
42
43    pub const fn none() -> Self {
45        Self(0)
46    }
47
48    pub const fn all() -> Self {
50        Self(bitmask::ENABLE_NOTE as u16)
51    }
52
53    pub const fn len() -> usize {
55        Self::LEN
56    }
57
58    pub fn set_index(&mut self, index: usize) -> Result<()> {
62        match index {
63            1 => self.set_note1(true),
64            2 => self.set_note2(true),
65            3 => self.set_note3(true),
66            4 => self.set_note4(true),
67            5 => self.set_note5(true),
68            6 => self.set_note6(true),
69            7 => self.set_note7(true),
70            _ => return Err(Error::failure("invalid enable index")),
71        }
72        Ok(())
73    }
74}
75
76impl From<&[bool]> for EnableNote {
77    fn from(b: &[bool]) -> Self {
78        let mut inner = 0u16;
79        let end = std::cmp::min(b.len(), Self::len());
81        for (i, &set) in b[..end].iter().enumerate() {
82            let bit = if set { 1 } else { 0 };
83            inner |= bit << i;
84        }
85        Self(inner)
86    }
87}
88
89impl<const N: usize> From<&[bool; N]> for EnableNote {
90    fn from(b: &[bool; N]) -> Self {
91        b.as_ref().into()
92    }
93}
94
95impl<const N: usize> From<[bool; N]> for EnableNote {
96    fn from(b: [bool; N]) -> Self {
97        (&b).into()
98    }
99}
100
101impl From<u8> for EnableNote {
102    fn from(b: u8) -> Self {
103        Self((b & bitmask::ENABLE_NOTE) as u16)
104    }
105}
106
107impl From<&EnableNote> for u8 {
108    fn from(e: &EnableNote) -> u8 {
109        (e.0 & 0xff) as u8
110    }
111}
112
113impl From<EnableNote> for u8 {
114    fn from(e: EnableNote) -> u8 {
115        (&e).into()
116    }
117}
118
119impl fmt::Display for EnableNote {
120    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121        let idx = self.note_index();
122
123        write!(f, "{{")?;
124        write!(f, r#""note_{idx}": {}, "#, self.note1())?;
125        write!(f, r#""note_{}": {}, "#, idx.saturating_add(1), self.note2())?;
126        write!(f, r#""note_{}": {}, "#, idx.saturating_add(2), self.note3())?;
127        write!(f, r#""note_{}": {}, "#, idx.saturating_add(3), self.note4())?;
128        write!(f, r#""note_{}": {}, "#, idx.saturating_add(4), self.note5())?;
129        write!(f, r#""note_{}": {}, "#, idx.saturating_add(5), self.note6())?;
130        write!(f, r#""note_{}": {}"#, idx.saturating_add(6), self.note7())?;
131        write!(f, "}}")
132    }
133}
134
135#[derive(Clone, Copy, Debug, PartialEq)]
201pub struct SetExtendedNoteInhibits<const M: usize, const N: usize> {
202    buf: [u8; M],
203}
204
205impl<const M: usize, const N: usize> SetExtendedNoteInhibits<M, N> {
206    pub const ENABLE_NOTE_LEN: usize = N;
208
209    pub fn new() -> Self {
211        assert!(
212            M == SET_EXTENDED_NOTE_INHIBITS_BASE + CFSC_ENABLE_LEN
213                || M == SET_EXTENDED_NOTE_INHIBITS_BASE + SC_ENABLE_LEN
214        );
215
216        let mut message = Self { buf: [0u8; M] };
217
218        message.init();
219        message.set_message_type(MessageType::Extended);
220        message.set_extended_note(ExtendedNoteReporting::Set);
221        message.set_extended_command(ExtendedCommand::SetExtendedNoteInhibits);
222
223        message
224    }
225
226    pub fn enabled_notes(&self) -> [EnableNote; N] {
228        let mut ret = [EnableNote::none(); N];
229
230        for (¬e, set_note) in self.buf
231            [index::ENABLE_NOTE..index::ENABLE_NOTE + Self::ENABLE_NOTE_LEN]
232            .iter()
233            .zip(ret.iter_mut())
234        {
235            *set_note = EnableNote::from(note);
236        }
237
238        ret
239    }
240
241    pub fn set_enabled_notes(&mut self, notes: &[EnableNote]) {
247        let max_len = std::cmp::min(notes.len(), Self::ENABLE_NOTE_LEN);
248
249        for (i, note) in notes[..max_len].iter().enumerate() {
250            self.buf[index::ENABLE_NOTE + i] = note.into();
251        }
252    }
253}
254
255impl<const M: usize, const N: usize> fmt::Display for SetExtendedNoteInhibits<M, N> {
256    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
257        write!(f, "{{")?;
258        write!(f, r#""message_type": {}, "#, self.message_type())?;
259        write!(f, r#""extended_command": {}, "#, self.extended_command())?;
260        write!(f, r#""denomination": {}, "#, self.denomination())?;
261        write!(f, r#""operational_mode": {}, "#, self.operational_mode())?;
262        write!(f, r#""configuration": {}, "#, self.configuration())?;
263        write!(f, r#""enabled_notes": ["#)?;
264
265        let mut notes = self.enabled_notes();
266        for (i, note) in notes.iter_mut().enumerate() {
267            if i != 0 {
268                write!(f, ", ")?;
269            }
270            note.set_note_index(((i * 7) + 1) as u16);
271            write!(f, "{note}")?;
272        }
273
274        write!(f, "]}}")
275    }
276}
277
278pub const CFSC_ENABLE_FULL_LEN: usize = SET_EXTENDED_NOTE_INHIBITS_BASE + CFSC_ENABLE_LEN;
279pub const SC_ENABLE_FULL_LEN: usize = SET_EXTENDED_NOTE_INHIBITS_BASE + SC_ENABLE_LEN;
280
281pub type SetExtendedNoteInhibitsCFSC =
282    SetExtendedNoteInhibits<CFSC_ENABLE_FULL_LEN, CFSC_ENABLE_LEN>;
283pub type SetExtendedNoteInhibitsSC = SetExtendedNoteInhibits<SC_ENABLE_FULL_LEN, SC_ENABLE_LEN>;
284
285impl_default!(SetExtendedNoteInhibits, M, N);
286impl_message_ops!(SetExtendedNoteInhibits, M, N);
287impl_extended_ops!(SetExtendedNoteInhibits, M, N);
288impl_omnibus_extended_command!(SetExtendedNoteInhibits, M, N);
289
290#[cfg(test)]
291mod tests {
292    use super::*;
293    use crate::Result;
294
295    #[test]
296    #[rustfmt::skip]
297    fn test_query_set_extended_note_inhibits_from_bytes() -> Result<()> {
298
299        let msg_bytes = [
301            0x02, 0x11, 0x70, 0x03,
303            0x00, 0x00, 0x00,
305            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307            0x03, 0x63,
309        ];
310
311        let mut msg = SetExtendedNoteInhibitsCFSC::new();
312        msg.from_buf(msg_bytes.as_ref())?;
313
314        assert_eq!(msg.message_type(), MessageType::Extended);
315        assert_eq!(msg.extended_command(), ExtendedCommand::SetExtendedNoteInhibits);
316
317        let exp_enabled = [
318            EnableNote::from(1), EnableNote::none(), EnableNote::none(), EnableNote::none(),
319            EnableNote::none(), EnableNote::none(), EnableNote::none(),  EnableNote::none(),
320        ];
321
322        assert_eq!(msg.enabled_notes(), exp_enabled);
323
324        let msg_bytes = [
326            0x02, 0x1c, 0x70, 0x03,
328            0x00, 0x00, 0x00,
330            0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
332            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
333            0x00, 0x00, 0x00,
334            0x03, 0x6e,
336        ];
337
338        let mut msg = SetExtendedNoteInhibitsSC::new();
339        msg.from_buf(msg_bytes.as_ref())?;
340
341        assert_eq!(msg.message_type(), MessageType::Extended);
342        assert_eq!(msg.extended_command(), ExtendedCommand::SetExtendedNoteInhibits);
343
344        let exp_enabled = [
345            EnableNote::from(1), EnableNote::none(), EnableNote::none(), EnableNote::none(),
346            EnableNote::none(), EnableNote::none(), EnableNote::none(),  EnableNote::none(),
347            EnableNote::none(), EnableNote::none(), EnableNote::none(),  EnableNote::none(),
348            EnableNote::none(), EnableNote::none(), EnableNote::none(),  EnableNote::none(),
349            EnableNote::none(), EnableNote::none(), EnableNote::none(),
350        ];
351
352        assert_eq!(msg.enabled_notes(), exp_enabled);
353
354        Ok(())
355    }
356
357    #[test]
358    fn test_display() -> Result<()> {
359        let enabled = SetExtendedNoteInhibitsCFSC::new();
360        let enabled_disp = r#"{"message_type": "Extended", "extended_command": "SetExtendedNoteInhibits", "denomination": "None", "operational_mode": {"orientation_control": "one way", "escrow_mode": "unset", "document_stack": "unset", "document_return": "unset"}, "configuration": {"no_push": "unset", "barcode": "unset", "power_up": "a", "extended_note": "set", "extended_coupon": "unset"}, "enabled_notes": [{"note_1": false, "note_2": false, "note_3": false, "note_4": false, "note_5": false, "note_6": false, "note_7": false}, {"note_8": false, "note_9": false, "note_10": false, "note_11": false, "note_12": false, "note_13": false, "note_14": false}, {"note_15": false, "note_16": false, "note_17": false, "note_18": false, "note_19": false, "note_20": false, "note_21": false}, {"note_22": false, "note_23": false, "note_24": false, "note_25": false, "note_26": false, "note_27": false, "note_28": false}, {"note_29": false, "note_30": false, "note_31": false, "note_32": false, "note_33": false, "note_34": false, "note_35": false}, {"note_36": false, "note_37": false, "note_38": false, "note_39": false, "note_40": false, "note_41": false, "note_42": false}, {"note_43": false, "note_44": false, "note_45": false, "note_46": false, "note_47": false, "note_48": false, "note_49": false}, {"note_50": false, "note_51": false, "note_52": false, "note_53": false, "note_54": false, "note_55": false, "note_56": false}]}"#;
361
362        assert_eq!(format!("{enabled}").as_str(), enabled_disp);
363
364        Ok(())
365    }
366}