Skip to main content

POS Peripherals

Setup, configuration, and integration for cash drawers, customer displays, and barcode scanners.

Cash Drawers

Supported Models

BrandModelInterface
APGVasarioPrinter-driven (RJ12)
StarCD3-1616Printer-driven
MMFVal-u LinePrinter-driven, USB

Configuration

# config/hardware/cash_drawers.yaml
cash_drawers:
- id: "drawer_001"
name: "Register 1"
type: "printer_driven"
printer_id: "printer_001"
pin: 2
expected_float: 200.00

- id: "drawer_002"
name: "Register 2"
type: "usb"
vendor_id: "0x0416"
product_id: "0x0001"
expected_float: 200.00

Cash Drawer Operations

// src/hardware/cash_drawer.rs
pub struct CashDrawerService {
drawers: HashMap<String, CashDrawer>,
}

impl CashDrawerService {
pub async fn open_drawer(&self, drawer_id: &str) -> Result<()> {
let drawer = self.drawers.get(drawer_id)
.ok_or(Error::DrawerNotFound)?;

match drawer.drawer_type {
DrawerType::PrinterDriven { printer_id, pin } => {
let printer = printer_service.get(&printer_id)?;
printer.open_cash_drawer(pin).await?;
}
DrawerType::USB { vendor_id, product_id } => {
let device = usb::open_device(vendor_id, product_id)?;
device.send_open_command().await?;
}
}

// Log drawer open event
audit_service.log(AuditEvent::CashDrawerOpened {
drawer_id: drawer_id.to_string(),
user_id: current_user_id(),
timestamp: Utc::now(),
}).await?;

Ok(())
}

pub async fn check_status(&self, drawer_id: &str) -> Result<DrawerStatus> {
let drawer = self.drawers.get(drawer_id)
.ok_or(Error::DrawerNotFound)?;

// Some drawers support status check
match drawer.drawer_type {
DrawerType::PrinterDriven { printer_id, .. } => {
let printer = printer_service.get(&printer_id)?;
let status = printer.get_drawer_status().await?;
Ok(if status.is_open { DrawerStatus::Open } else { DrawerStatus::Closed })
}
_ => Ok(DrawerStatus::Unknown),
}
}
}

Customer Displays

Configuration

# config/hardware/customer_displays.yaml
customer_displays:
- id: "display_001"
name: "Register 1 Display"
type: "pole_display"
connection:
type: "serial"
port: "/dev/ttyUSB0"
baud_rate: 9600
width: 20
lines: 2

- id: "display_002"
name: "Register 2 Display"
type: "lcd_screen"
connection:
type: "usb"
vendor_id: "0x0801"
product_id: "0x0001"

Pole Display Integration

// src/hardware/customer_display.rs
pub struct CustomerDisplayService {
displays: HashMap<String, CustomerDisplay>,
}

impl CustomerDisplayService {
pub async fn show_welcome(&self, display_id: &str) -> Result<()> {
let display = self.get_display(display_id)?;

display.clear().await?;
display.write_line(0, "Welcome!").await?;
display.write_line(1, "Ready to serve you").await?;

Ok(())
}

pub async fn show_item(&self, display_id: &str, item: &OrderItem) -> Result<()> {
let display = self.get_display(display_id)?;

display.clear().await?;
display.write_line(0, &truncate(&item.name, display.width)).await?;
display.write_line(1, &format!("${:.2}", item.total)).await?;

Ok(())
}

pub async fn show_total(&self, display_id: &str, total: f64) -> Result<()> {
let display = self.get_display(display_id)?;

display.clear().await?;
display.write_line(0, "Total:").await?;
display.set_emphasis(true).await?;
display.write_line(1, &format!("${:.2}", total)).await?;
display.set_emphasis(false).await?;

Ok(())
}

pub async fn show_thank_you(&self, display_id: &str) -> Result<()> {
let display = self.get_display(display_id)?;

display.clear().await?;
display.write_line(0, "Thank You!").await?;
display.write_line(1, "Please come again").await?;

// Reset to welcome after delay
tokio::time::sleep(Duration::from_secs(5)).await;
self.show_welcome(display_id).await?;

Ok(())
}
}