#usb #bill-acceptor #bill-validator #events #bnr


Pure Rust implementation of the BNR XFS USB

4 releases

0.1.3 Mar 13, 2024
0.1.2 Feb 23, 2024
0.1.1 Feb 14, 2024
0.1.0 Jan 24, 2024

#76 in Finance

Download history 6/week @ 2024-01-24 114/week @ 2024-02-14 179/week @ 2024-02-21 26/week @ 2024-02-28 28/week @ 2024-03-06 92/week @ 2024-03-13 7/week @ 2024-03-20 7/week @ 2024-03-27 13/week @ 2024-04-03

120 downloads per month
Used in bnr

MIT license

11K SLoC


This library is used to communicate with MEI/CPI BNR cash recycler devices.

The XFS protocol is an XML-encoded messaging format over a USB connection.

Communication happens over four endpoints:

  • XFS response (device-to-host)
  • XFS call (host-to-device)
  • XFS callback call (device-to-host)
  • XFS callback response (host-to-device)


The main interface for device interaction is the DeviceHandle:

use bnr_xfs::{CallbackArg, DeviceHandle};

// Callback handler for when an async call completes
// See OperationCompletedFn for details.
fn op_com(_call_id: i32, _op_id: i32, _res: i32, _ext_res: i32, _cb_arg: &mut dyn CallbackArg) {
    // process the completion event...

// Callback handler for when an intermediate event occurs
// See IntermediateOccurredFn for details.
fn int_oc(_call_id: i32, _op_id: i32, _reason: i32, _cb_arg: &mut dyn CallbackArg) {
    // process the intermediate event...

// Callback handler for when a status event occurs
// See StatusOccurredFn for details.
fn st_oc(_call_id: i32, _op_id: i32, _reason: i32, _cb_arg: &mut dyn CallbackArg) {
    // process the status event...

let device_handle = DeviceHandle::open(Some(op_com), Some(int_oc), Some(st_oc)).unwrap();

let _status = device_handle.get_status().unwrap();


End-to-end device tests live in the tests/e2e_tests directory.

These tests currently require a BNR device to be connected to the computer running the tests.

To run the tests:

$ cargo test --all --features e2e_tests


There is still a reasonable amount of the BNR XFS API surface from the C library that needs to be implemented in Rust.

Implementations should follow the pattern of existing functions, and any additional types need to implement conversion to-and-from XFS XML.

Helper macros exist for implementing conversions of most of the basic XFS types.

If you notice an unimplemented type, please submit a merge request!


~161K SLoC