mod codes {
pub const RESET: u8 = 0x30;
pub const GET_STATUS: u8 = 0x31;
pub const SET_SECURITY: u8 = 0x32;
pub const POLL: u8 = 0x33;
pub const ENABLE_BILL_TYPES: u8 = 0x34;
pub const STACK: u8 = 0x35;
pub const RETURN: u8 = 0x36;
pub const IDENTIFICATION: u8 = 0x37;
pub const HOLD: u8 = 0x38;
pub const GET_BILL_TABLE: u8 = 0x41;
pub const GET_CRC32: u8 = 0x51;
pub const REQUEST_STATISTICS: u8 = 0x60;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BillMask(pub [u8; 6]);
impl BillMask {
pub const ALL: Self = Self([0xFF; 6]);
pub const NONE: Self = Self([0x00; 6]);
pub fn single(index: u8) -> Self {
let mut mask = [0u8; 6];
mask[(index / 8) as usize] |= 1 << (index % 8);
Self(mask)
}
pub fn is_enabled(self, index: u8) -> bool {
(self.0[(index / 8) as usize] >> (index % 8)) & 1 == 1
}
}
impl Default for BillMask {
fn default() -> Self {
Self::ALL
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum SecurityLevel {
Low = 0x00,
Normal = 0x01,
High = 0x02,
VeryHigh = 0x03,
}
#[derive(Debug, Clone)]
pub enum Command {
Reset,
GetStatus,
SetSecurity(SecurityLevel),
Poll,
EnableBillTypes(BillMask),
Stack,
Return,
Identification,
Hold,
GetBillTable,
GetCrc32,
RequestStatistics,
}
impl Command {
pub fn to_data(&self) -> Vec<u8> {
match self {
Command::Reset => vec![codes::RESET],
Command::GetStatus => vec![codes::GET_STATUS],
Command::SetSecurity(level) => {
let mask = match level {
SecurityLevel::Low | SecurityLevel::Normal => 0x00u8,
SecurityLevel::High | SecurityLevel::VeryHigh => 0xFFu8,
};
vec![codes::SET_SECURITY, mask, mask, mask]
}
Command::Poll => vec![codes::POLL],
Command::EnableBillTypes(mask) => {
let mut data = vec![codes::ENABLE_BILL_TYPES];
data.extend_from_slice(&mask.0);
data
}
Command::Stack => vec![codes::STACK],
Command::Return => vec![codes::RETURN],
Command::Identification => vec![codes::IDENTIFICATION],
Command::Hold => vec![codes::HOLD],
Command::GetBillTable => vec![codes::GET_BILL_TABLE],
Command::GetCrc32 => vec![codes::GET_CRC32],
Command::RequestStatistics => vec![codes::REQUEST_STATISTICS],
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bill_mask_single() {
let mask = BillMask::single(0);
assert!(mask.is_enabled(0));
assert!(!mask.is_enabled(1));
assert_eq!(mask.0[0], 0x01);
}
#[test]
fn bill_mask_all_enabled() {
let mask = BillMask::ALL;
for i in 0..48u8 {
assert!(mask.is_enabled(i));
}
}
#[test]
fn enable_bill_types_data_len() {
let data = Command::EnableBillTypes(BillMask::ALL).to_data();
assert_eq!(data.len(), 7); assert_eq!(data[0], 0x34);
}
}