bnr_xfs/device_handle.rs
1use std::sync::{
2 atomic::{AtomicBool, Ordering},
3 mpsc, Arc,
4};
5
6use time as datetime;
7
8use crate::capabilities::Capabilities;
9use crate::cash_unit::{CashUnit, LogicalCashUnitList, PhysicalCashUnitList};
10use crate::currency::{CashOrder, CurrencyCode};
11use crate::denominations::BillsetIdList;
12use crate::denominations::DenominationList;
13use crate::dispense::DispenseRequest;
14use crate::history::{
15 BillAcceptanceHistory, BillDispenseHistory, SystemFailureHistory, SystemRestartHistory,
16 SystemUseHistory,
17};
18use crate::status::CdrStatus;
19use crate::xfs;
20use crate::{Error, Result};
21
22mod inner;
23pub mod usb;
24
25use usb::UsbDeviceHandle;
26
27/// BNR USB Vendor ID.
28pub const BNR_VID: u16 = 0x0bed;
29/// BNR USB Product ID.
30pub const BNR_PID: u16 = 0x0a00;
31/// Length of the URB (USB Request Block) header length on Linux.
32pub const URB_LEN: u64 = 64;
33
34/// BNR USB endpoint for device-to-host [XfsMethodResponse](crate::xfs::method_response::XfsMethodResponse)s.
35///
36/// Sets the MSB to indicate an `IN` endpoint.
37pub const BNR_RESPONSE_EP: u8 = (1 << 7) | 1;
38/// BNR USB endpoint for host-to-device [XfsMethodCall](crate::xfs::method_call::XfsMethodCall)s.
39pub const BNR_CALL_EP: u8 = 2;
40/// BNR USB endpoint for device-to-host asynchronous callback calls.
41///
42/// Sets the MSB to indicate an `IN` endpoint.
43pub const BNR_CALLBACK_CALL_EP: u8 = (1 << 7) | 3;
44/// BNR USB endpoint for host-to-device asynchronous callback responses.
45pub const BNR_CALLBACK_RESPONSE_EP: u8 = 4;
46
47/// Trait for arguments to state change callbacks used by the XFS API.
48pub trait CallbackArg {
49 fn value(&self) -> i32;
50 fn is_null(&self) -> bool;
51 fn is_cash_order(&self) -> bool;
52 fn as_cash_order(&self) -> Result<&CashOrder>;
53 fn as_cash_order_mut(&mut self) -> Result<&mut CashOrder>;
54}
55
56impl CallbackArg for () {
57 fn value(&self) -> i32 {
58 0
59 }
60
61 fn is_null(&self) -> bool {
62 true
63 }
64
65 fn is_cash_order(&self) -> bool {
66 false
67 }
68
69 fn as_cash_order(&self) -> Result<&CashOrder> {
70 Err(Error::Xfs(
71 "Expected CashOrder CallbackArg, have: null".into(),
72 ))
73 }
74
75 fn as_cash_order_mut(&mut self) -> Result<&mut CashOrder> {
76 Err(Error::Xfs(
77 "Expected CashOrder CallbackArg, have: null".into(),
78 ))
79 }
80}
81
82/// Function signature for the `Operation Completed` callback used by the XFS API.
83///
84/// Handles device-sent messages indicating an asynchronous operation has completed.
85///
86/// # Parameters
87///
88/// - `call_id`: callback ID returned by the initial async call
89/// - `operation_id`: async operation ID to uniquely identify the type of call
90/// - `result`: the result status of the call
91/// - `extended_result`: the extended result of the call
92/// - `callback_arg`: callback call argument (may be the `unit` type if not supplied)
93pub type OperationCompletedFn = fn(i32, i32, i32, i32, &mut dyn CallbackArg);
94
95/// Function signature for the `Intermediate Occurred` callback used by the XFS API.
96///
97/// Handles an intermediate state transition occurred during an ongoing transaction.
98///
99/// # Parameters
100///
101/// - `call_id`: callback ID returned by the initial async call
102/// - `operation_id`: async operation ID to uniquely identify the type of call
103/// - `reason`: specifies the reason for the intermediate event
104/// - `callback_arg`: callback call argument (may be the `unit` type if not supplied)
105pub type IntermediateOccurredFn = fn(i32, i32, i32, &mut dyn CallbackArg);
106
107/// Function signature for the `Status Occured` callback used by the XFS API.
108///
109/// Handles a status event that occurred on the device.
110///
111/// # Parameters
112///
113/// - `status`: the status that occurred on the device (e.g. bill inserted)
114/// - `result`: the result of the status event
115/// - `extended_result`: the extended result of the status event
116/// - `callback_arg`: callback call argument (may be the `unit` type if not supplied)
117pub type StatusOccurredFn = fn(i32, i32, i32, &mut dyn CallbackArg);
118
119/// BNR XFS device handle for communication over USB.
120pub struct DeviceHandle {
121 usb: Arc<UsbDeviceHandle>,
122 stop_listener: Arc<AtomicBool>,
123 op_completed_callback: Option<OperationCompletedFn>,
124 intermediate_occurred_callback: Option<IntermediateOccurredFn>,
125 status_occurred_callback: Option<StatusOccurredFn>,
126 response_rx: mpsc::Receiver<xfs::method_call::XfsMethodCall>,
127}
128
129impl DeviceHandle {
130 /// Opens a new connection to the BNR XFS device.
131 ///
132 /// # Examples
133 ///
134 /// ```no_run
135 /// use bnr_xfs::{CallbackArg, DeviceHandle};
136 ///
137 /// // Callback handler for when an async call completes
138 /// //
139 /// // See OperationCompletedFn for details.
140 /// fn op_com(_call_id: i32, _op_id: i32, _res: i32, _ext_res: i32, _cb_arg: &mut dyn CallbackArg) {
141 /// // process the completion event...
142 /// }
143 ///
144 /// // Callback handler for when an intermediate event occurs
145 /// //
146 /// // See IntermediateOccurredFn for details.
147 /// fn int_oc(_call_id: i32, _op_id: i32, _reason: i32, _cb_arg: &mut dyn CallbackArg) {
148 /// // process the intermediate event...
149 /// }
150 ///
151 /// // Callback handler for when a status event occurs
152 /// //
153 /// // See StatusOccurredFn for details.
154 /// fn st_oc(_call_id: i32, _op_id: i32, _reason: i32, _cb_arg: &mut dyn CallbackArg) {
155 /// // process the status event...
156 /// }
157 ///
158 /// let device_handle = DeviceHandle::open(Some(op_com), Some(int_oc), Some(st_oc)).unwrap();
159 ///
160 /// let _status = device_handle.get_status().unwrap();
161 /// ```
162 pub fn open(
163 op_completed_callback: Option<OperationCompletedFn>,
164 intermediate_occurred_callback: Option<IntermediateOccurredFn>,
165 status_occurred_callback: Option<StatusOccurredFn>,
166 ) -> Result<Self> {
167 Self::open_inner(
168 UsbDeviceHandle::find_usb()?,
169 op_completed_callback,
170 intermediate_occurred_callback,
171 status_occurred_callback,
172 )
173 }
174
175 /// Reconnects to the BNR XFS device
176 pub fn reconnect(&mut self) -> Result<()> {
177 self.stop_background_listener();
178 self.usb = Arc::new(UsbDeviceHandle::find_usb()?);
179 self.stop_listener.store(false, Ordering::SeqCst);
180 let (response_tx, response_rx) = mpsc::channel();
181
182 self.start_background_listener(response_tx, Arc::clone(&self.stop_listener))?;
183
184 self.response_rx = response_rx;
185
186 Ok(())
187 }
188
189 /// Resets the BNR device.
190 pub fn reset(&self) -> Result<()> {
191 self.reset_inner()
192 }
193
194 /// Sends the message to cancel any currently active transactions/commands.
195 pub fn cancel(&self) -> Result<()> {
196 self.cancel_inner()
197 }
198
199 /// Stops secured communication session if started, ends the communication with the BNR and terminates the thread that has been started by a previous `open` call.
200 pub fn close(&self) -> Result<()> {
201 self.close_inner()
202 }
203
204 /// Reboots the BNR. This call puts the BNR in the same state than a power cycle (power off/on).
205 pub fn reboot(&self) -> Result<()> {
206 self.reboot_inner()
207 }
208
209 /// Gets the ISO 8601 formatted date-time from the device.
210 pub fn get_date_time(&self) -> Result<datetime::OffsetDateTime> {
211 self.get_date_time_inner()
212 }
213
214 /// Sets the ISO 8601 formatted date-time on the device to the provided time.
215 ///
216 /// **NOTE** This setting is not persistent across reboots/power-cycles.
217 ///
218 /// The default device time will reset to `2001-01-01 00:00:00`.
219 pub fn set_date_time(&self, date_time: datetime::OffsetDateTime) -> Result<()> {
220 self.set_date_time_inner(date_time)
221 }
222
223 /// Sets the ISO 8601 formatted date-time on the device to the current time.
224 ///
225 /// **NOTE** This setting is not persistent across reboots/power-cycles.
226 ///
227 /// The default device time will reset to `2001-01-01 00:00:00`.
228 pub fn set_current_date_time(&self) -> Result<()> {
229 self.set_date_time_inner(datetime::OffsetDateTime::now_utc())
230 }
231
232 /// Gets the current status of the BNR device.
233 pub fn get_status(&self) -> Result<CdrStatus> {
234 self.get_status_inner()
235 }
236
237 /// "Parks" the device for maintenance, disabling all modules.
238 pub fn park(&self) -> Result<()> {
239 self.park_inner()
240 }
241
242 /// Gets the [Capabilities] of the BNR device.
243 pub fn get_capabilities(&self) -> Result<Capabilities> {
244 self.get_capabilities_inner()
245 }
246
247 /// Sets the [Capabilities] for the BNR device.
248 pub fn set_capabilities(&self, caps: &Capabilities) -> Result<Capabilities> {
249 self.set_capabilities_inner(caps)
250 }
251
252 /// Sends the initial message to start a `CashIn` transaction, and begin accepting notes.
253 pub fn cash_in_start(&self) -> Result<()> {
254 self.cash_in_start_inner()
255 }
256
257 /// Sends the follow-up message to start a `CashIn` transaction, and begin accepting notes.
258 ///
259 /// After successfully sending this message, the device is ready to accept notes.
260 ///
261 /// params:
262 ///
263 /// - `limit`: optional limit on the number of notes to accept.
264 /// - `None` will tell the device to accept one note.
265 /// - `currency`: optional restriction on currency to accept.
266 /// - `None` will tell the device to accept all currencies.
267 ///
268 /// The BNR API takes two mutable pointers for this call, the first for `amount` and the second
269 /// for an ISO currency string (4-bytes, null-terminated ASCII).
270 ///
271 /// From the BNR API docs:
272 ///
273 /// ```no_build, no_run
274 /// @param[in] amount Amount to accept with this operation. If this parameter is NULL, the BNR
275 /// will accept only one banknote. If the amount is 0, banknotes will be accepted until the
276 /// escrow is full, or a bnr_Cancel() command is called. If the amount is different from 0,
277 /// banknotes will be accepted until the amount is reached, or the escrow is full, or a
278 /// bnr_Cancel() command is called.
279 ///
280 /// @param[in] currencyCode Currency to accept during this operation. If this parameter is
281 /// NULL or the string is empty, any currency will be accepted by the BNR.
282 /// ```
283 pub fn cash_in(&self, limit: Option<u32>, currency: Option<CurrencyCode>) -> Result<()> {
284 self.cash_in_inner(limit, currency)
285 }
286
287 /// Sends the message to end a `CashIn` transaction.
288 ///
289 /// The caller will need to call [cash_in_start](Self::cash_in_start) and [cash_in](Self::cash_in) to begin accepting notes again.
290 pub fn cash_in_end(&self) -> Result<()> {
291 self.cash_in_end_inner()
292 }
293
294 /// Sends the message to rollback a `CashIn` transaction, returning any inserted notes to the
295 /// customer.
296 ///
297 /// The caller should first call the [cancel](crate::cancel) function to cancel the `CashIn`
298 /// transaction.
299 pub fn cash_in_rollback(&self) -> Result<()> {
300 self.cash_in_rollback_inner()
301 }
302
303 /// This command allows the application to force cash that has been presented to be ejected from the bezel.
304 pub fn eject(&self) -> Result<()> {
305 self.eject_inner()
306 }
307
308 /// Empties a recycler or loader cash unit in the cashbox.
309 ///
310 /// **Note** When calling this function for a loader, the `to_float` parameter is not taken into account and the loader is completely emptied.
311 ///
312 /// Params:
313 ///
314 /// - `pcu_name`: Name of the physical cash unit to empty.
315 /// - `to_float` If `true`, the command empties up to the low threshold of the Physical Cash Unit, otherwise to zero.
316 pub fn empty(&self, pcu_name: &str, to_float: bool) -> Result<()> {
317 self.empty_inner(pcu_name, to_float)
318 }
319
320 /// Activates the presentation of the cash.
321 ///
322 /// It can only be used following the [dispense] method.
323 ///
324 /// A #XFS_S_CDR_CASH_AVAILABLE status event is issued to report that the bills are presented at the outlet,
325 /// then a #XFS_S_CDR_CASH_TAKEN status event is issued to report that the user has removed the bills, and the command completes.
326 ///
327 /// After #XFS_S_CDR_CASH_AVAILABLE status event, if no #XFS_S_CDR_CASH_TAKEN status event is received within a reasonable time period,
328 /// the application should send a [cancel_waiting_cash_taken] to terminate the command, then send a [retract] to clear the bills from the outlet.
329 pub fn present(&self) -> Result<()> {
330 self.present_inner()
331 }
332
333 /// Asks the BNR to stop waiting for cash removal at the Bezel if any.
334 ///
335 /// If it can do so, an OperationCompleteEvent is sent with the result field containing #XFS_E_CANCELLED to indicate that the operation was cancelled.
336 /// Otherwise, the current operation’s messages will be sent as usual.
337 ///
338 /// This method is meant to be called after the BNR has sent a #XFS_S_CDR_CASH_AVAILABLE status event, and before #XFS_S_CDR_CASH_TAKEN status event.
339 /// If this method is called outside these conditions, then no operation will take place and no error will be returned.
340 /// If this method is called after cash has been removed but before the #XFS_S_CDR_CASH_TAKEN status event has been returned to the caller,
341 /// then no operation will take place and no error will be returned.
342 pub fn cancel_waiting_cash_taken(&self) -> Result<()> {
343 self.cancel_waiting_cash_taken_inner()
344 }
345
346 /// This command allows the application to force cash that has been presented to be retracted.
347 ///
348 /// Retracted bills will be moved to the intermediate stacker area and accounted in the Bundler LCU. The application can then present bills to the user, using [cash_in_rollback](Self::cash_in_rollback) or [present](Self::present)
349 /// (depending of the kind of the transaction) or clear the intermediate stacker area using the [reject](Self::reject) method.
350 ///
351 /// This method may only be called after bills have been presented at the outlet following a [dispense](Self::dispense) (if autoPresent mode is active), [cash_in_rollback](Self::cash_in_rollback) or [present](Self::present) method call,
352 /// and before the bills have been taken by the user.
353 ///
354 /// **Note** An asynchronous method must not be called before the preceding one is terminated (i.e. OperationComplete event has been received); typically before calling [retract],
355 /// the preceding command must be terminated by calling
356 /// [cancel_waiting_cash_taken](Self::cancel_waiting_cash_taken).
357 pub fn retract(&self) -> Result<()> {
358 self.retract_inner()
359 }
360
361 /// Gets the complete state of all physical and logical cash units in the BNR.
362 ///
363 /// Returns the [CashUnit] struct with details about the [PhysicalCashUnit]s and
364 /// [LogicalCashUnit]s on the BNR device.
365 pub fn query_cash_unit(&self) -> Result<CashUnit> {
366 self.query_cash_unit_inner()
367 }
368
369 /// Configures the BNR’s cash unit. This function is used to add or remove Logical and Physical Cash Unit in the BNR.
370 ///
371 /// Those settings are persistent over power cycles.
372 ///
373 /// Params:
374 ///
375 /// - `transport_count`: number of bills in the transport system.
376 /// - `lcu_list`: [LogicalCashUnitList] for configuring [LogicalCashUnit]s.
377 /// - `pcu_list`: [PhysicalCashUnitList] for configuring [PhysicalCashUnit]s.
378 pub fn configure_cash_unit(
379 &self,
380 transport_count: u32,
381 lcu_list: &LogicalCashUnitList,
382 pcu_list: &PhysicalCashUnitList,
383 ) -> Result<()> {
384 self.configure_cash_unit_inner(transport_count, lcu_list, pcu_list)
385 }
386
387 /// Updates the BNR’s cash unit. This function is used to change counts and thresholds of the BNR
388 /// [CashUnit]s.
389 ///
390 /// Those settings are persistent over power cycles.
391 ///
392 /// Params:
393 ///
394 /// - `transport_count`: number of bills in the transport system.
395 /// - `lcu_list`: [LogicalCashUnitList] for configuring [LogicalCashUnit]s.
396 /// - `pcu_list`: [PhysicalCashUnitList] for configuring [PhysicalCashUnit]s.
397 pub fn update_cash_unit(
398 &self,
399 transport_count: u32,
400 lcu_list: &LogicalCashUnitList,
401 pcu_list: &PhysicalCashUnitList,
402 ) -> Result<()> {
403 self.update_cash_unit_inner(transport_count, lcu_list, pcu_list)
404 }
405
406 /// BNR_CASH_OPERATIONS Determines if the amount requested by value or by bill list, is available for dispense.
407 ///
408 /// From the MEI/CPI documentation:
409 ///
410 /// Three methods are possible:
411 ///
412 /// - denominateRequest->mixNumber is #XFS_C_CDR_MXA_MIN_BILLS: The BNR chooses the banknotes to be distributed in order to obtain the total amount using the minimum number of banknotes. Two parameters must be correctly set:
413 /// - denominateRequest->denomination.amount has to be expressed in MDUs
414 /// - denominateRequest->currency.currencyCode is a string. See this page for a full list of the existing ISO currency codes: <http://www.iso.org/iso/home/standards/currency_codes.htm>
415 /// - denominateRequest->mixNumber is #BNRXFS_C_CDR_MXA_OPTIMUM_CHANGE: The BNR chooses the banknotes to be distributed in order to obtain the total amount in a way that slows down cashbox filling. As long as the low denomination Recyclers are not near to full, change is determined like with the MinBills algorithm. But when a Recycler becomes nearly full (5/6 of Full threshold), this algorithm will try to put more of this denomination in the change so that the Recycler doesn’t become full and this denomination doesn’t start to be cashed. Two parameters must be correctly set:
416 /// - denominateRequest->denomination.amount has to be expressed in MDUs
417 /// - denominateRequest->currency.currencyCode is a string. See this page for a full list of the existing ISO currency codes: <http://www.iso.org/iso/home/standards/currency_codes.htm>
418 /// - denominateRequest->mixNumber is #XFS_C_CDR_MIX_DENOM: The user chooses through a list of Logical Cash Units the banknotes to be distributed by the BNR in order to obtain the total amount. The following parameters must be correctly set:
419 /// - denominateRequest->denomination.size gives the size of the items array
420 /// - for each item of denominateRequest->denomination.items from 0 to (denominateRequest->denomination.size - 1):
421 /// - denominateRequest->denomination.items[item].unit contains the number of a LCU from where banknotes must be distributed.
422 /// - denominateRequest->denomination.items[item].count gives the number of notes to distribute from the LCU.
423 pub fn denominate(&self, request: &DispenseRequest) -> Result<()> {
424 self.denominate_inner(request)
425 }
426
427 /// Dispenses the amount requested by value or by bill list.
428 ///
429 /// From the MEI/CPI documentation:
430 ///
431 /// The BNR will make a bundle of notes and wait for the bnr_Present() command to give it to the customer.
432 ///
433 /// Three methods are possible:
434 ///
435 /// - `DispenseRequest::mix_number` is #XFS_C_CDR_MXA_MIN_BILLS: The BNR chooses the banknotes to be distributed in order to obtain the total amount using the minimum number of banknotes. Two parameters must be correctly set:
436 /// - `DispenseRequest::denomination.amount` has to be expressed in MDUs
437 /// - `DispenseRequest::currency.currency_code`
438 ///
439 /// - `DispenseRequest::mix_number` is #BNRXFS_C_CDR_MXA_OPTIMUM_CHANGE: The BNR chooses the banknotes to be distributed in order to obtain the total amount in a way that slows down cashbox filling. As long as the low denomination Recyclers are not near to full, change is determined like with the MinBills algorithm. But when a Recycler becomes nearly full (5/6 of Full threshold), this algorithm will try to put more of this denomination in the change so that the Recycler doesn’t become full and this denomination doesn’t start to be cashed. Two parameters must be correctly set:
440 /// - `DispenseRequest::denomination.amount` has to be expressed in MDUs
441 /// - `DispenseRequest::currency.currency_code`
442 ///
443 /// - `DispenseRequest::mix_number` is #XFS_C_CDR_MIX_DENOM: The user chooses through a list of Logical Cash Units the banknotes to be distributed by the BNR in order to obtain the total amount. The following parameters must be correctly set:
444 /// - `DispenseRequest::denomination::size` gives the size of the items array
445 /// for each item of [DispenseRequest::denomination::items] from 0 to `DispenseRequest::denomination::size - 1`:
446 /// - `DispenseRequest::denomination::items[item]::unit` contains the number of a LCU from where banknotes must be distributed.
447 /// - `DispenseRequest::denomination::items[item]::count` gives the number of banknotes to distribute from the LCU.
448 ///
449 /// - `DispenseRequest::currency.currency_code` is a string in the C library.
450 /// - See [CurrencyCode] for a full list of the existing ISO currency codes, also: <http://www.iso.org/iso/home/standards/currency_codes.htm>
451 /// - conversion from the enum to a string is handled internally, the user does not need to worry about this.
452 ///
453 /// Params:
454 ///
455 /// - `request`: Amount or bill list requested for dispense.
456 ///
457 /// Returns `Ok` If function call is successful. Otherwise, return is strictly negative and its absolute value contains the error code.
458 pub fn dispense(&self, request: &DispenseRequest) -> Result<()> {
459 self.dispense_inner(request)
460 }
461
462 /// Stops any active sessions on the BNR device.
463 pub fn stop_session(&self) -> Result<()> {
464 self.stop_session_inner()
465 }
466
467 /// Gets a list of denominations in the BNR.
468 ///
469 /// Returns:
470 ///
471 /// - Ok([DenominationList]): list of the denominations currently defined in the BNR.
472 /// - Error conditions: see [update_denominations](Self::update_denominations) for a list of error code descriptions.
473 pub fn query_denominations(&self) -> Result<DenominationList> {
474 self.query_denominations_inner()
475 }
476
477 /// Updates the settings for a list of denominations.
478 ///
479 /// For each [DenominationInfo](crate::denominations::DenominationInfo) element of the [DenominationList],
480 /// the application can update its validation settings.
481 ///
482 /// From the BNR API docs:
483 ///
484 /// ```no_build,no_run
485 /// Those settings are persistent over power cycles; please refer to DenominationInfo for more details about settable properties, and their default values.
486 ///
487 /// @param[in] DenominationList This list of denominations will be a modified version of the one obtained from query_denominations() call.
488 /// ```
489 ///
490 /// Returns:
491 ///
492 /// - Ok(()) on success
493 /// - Error conditions:
494 /// - `#XFS_E_ILLEGAL` - A dispense command is already active on the BNR.
495 /// - `#XFS_E_NOT_SUPPORTED` - operation not supported by the BNR firmware version.
496 /// - `#XFS_E_PARAMETER_INVALID` - Invalid array size. The array size is bigger than expected.
497 /// - `#XFS_E_CDR_CASHIN_ACTIVE` - A cashIn command has been issued and is already active.
498 /// - `#XFS_E_FAILURE` - a command is already running on the BNR or an internal error occured.
499 pub fn update_denominations(&self, request: &DenominationList) -> Result<()> {
500 self.update_denominations_inner(request)
501 }
502
503 /// Queries the device for the configured [BillsetIdList].
504 ///
505 /// **NOTE** Firmware Compatibility: This function requires a BNR FW v1.12.0 or newer. With older FW versions, the return will be #XFS_E_NOT_SUPPORTED.
506 pub fn query_billset_ids(&self) -> Result<BillsetIdList> {
507 self.query_billset_ids_inner()
508 }
509
510 /// Gets the BNR [BillAcceptanceHistory].
511 pub fn get_bill_acceptance_history(&self) -> Result<BillAcceptanceHistory> {
512 self.get_bill_acceptance_history_inner()
513 }
514
515 /// Gets the BNR [BillDispenseHistory].
516 pub fn get_bill_dispense_history(&self) -> Result<BillDispenseHistory> {
517 self.get_bill_dispense_history_inner()
518 }
519
520 /// Gets the BNR [SystemFailureHistory].
521 pub fn get_failure_history(&self) -> Result<SystemFailureHistory> {
522 self.get_failure_history_inner()
523 }
524
525 /// Gets the BNR [SystemRestartHistory].
526 pub fn get_restart_history(&self) -> Result<SystemRestartHistory> {
527 self.get_restart_history_inner()
528 }
529
530 /// Gets the BNR [SystemUseHistory].
531 pub fn get_use_history(&self) -> Result<SystemUseHistory> {
532 self.get_use_history_inner()
533 }
534
535 /// Gets a reference to the [UsbDeviceHandle].
536 pub(crate) fn usb(&self) -> &UsbDeviceHandle {
537 self.usb.as_ref()
538 }
539
540 pub(crate) fn usb_clone(&self) -> Arc<UsbDeviceHandle> {
541 Arc::clone(&self.usb)
542 }
543
544 /// Gets the callback function for operation completed events.
545 pub fn op_completed_callback(&self) -> Option<OperationCompletedFn> {
546 self.op_completed_callback
547 }
548
549 /// Gets the callback function for intermediate events.
550 pub fn intermediate_occurred_callback(&self) -> Option<IntermediateOccurredFn> {
551 self.intermediate_occurred_callback
552 }
553
554 /// Gets the callback function for status events.
555 pub fn status_occurred_callback(&self) -> Option<StatusOccurredFn> {
556 self.status_occurred_callback
557 }
558}