Skip to main content

waveshare_barcodescanner/
interface.rs

1use std::time::{Duration, Instant};
2
3use anyhow::{Result, anyhow};
4use chrono::NaiveDate;
5use serial2::{CharSize, FlowControl, Parity, SerialPort, Settings, StopBits};
6use tracing::{debug, trace};
7
8use crate::{
9    Barcode, Barcodes, IlluminationMode, OperationMode, ScanArea, TargetLightMode,
10    crc::{calculate_crc, verify_crc},
11};
12
13pub struct BarcodeScanner {
14    /// serial or USB port to communicate over
15    port: SerialPort,
16    /// timeout for a single scan (in manual or command mode), default is 5s
17    scan_timeout: Duration,
18}
19
20impl BarcodeScanner {
21    /// open the serial port and initialize the necessary device options for scanning
22    ///
23    /// # Arguments
24    ///
25    /// * `serial_port_name` the device name of the serial port to open
26    ///
27    /// # Examples
28    ///
29    /// ```no_run
30    /// use anyhow::Result;
31    /// use waveshare_barcodescanner::interface::BarcodeScanner;
32    /// 
33    /// fn main() -> Result<()> {
34    ///     let scanner = BarcodeScanner::new("/dev/serial0")?;
35    ///     Ok(())
36    /// }
37    /// ```
38    ///
39    /// # Notes
40    ///
41    /// The device is expected to be in UART mode, with the serial options set to 9600,8,N,1 (factory default).
42    pub fn new(serial_port_name: &str) -> Result<Self> {
43        let mut port = SerialPort::open(serial_port_name, |mut settings: Settings| {
44            settings.set_raw();
45            settings.set_baud_rate(9600)?;
46            settings.set_char_size(CharSize::Bits8);
47            settings.set_stop_bits(StopBits::One);
48            settings.set_parity(Parity::None);
49            settings.set_flow_control(FlowControl::None);
50            Ok(settings)
51        })?;
52        port.discard_buffers()?;
53        port.set_read_timeout(Duration::from_millis(100))?;
54        let mut scanner = BarcodeScanner {
55            port,
56            scan_timeout: Duration::from_secs(5),
57        };
58        // in order for barcode payload decoding to work corectly, always set the decoding options
59        let mut default_barcode_result_options: u8 = 0x00;
60        // without protocol
61        // CR as end of line
62        // without RF
63        // without prefix
64        // with CodeID
65        default_barcode_result_options |= 0x04;
66        // without suffix
67        // with end character
68        default_barcode_result_options |= 0x01;
69        scanner.send_write_command(0x0060, &[default_barcode_result_options])?;
70        Ok(scanner)
71    }
72
73    /// return the hardware version of the attached barcode scanner
74    ///
75    /// # Examples
76    ///
77    /// ```no_run
78    /// use anyhow::Result;
79    /// use waveshare_barcodescanner::interface::BarcodeScanner;
80    /// 
81    /// fn main() -> Result<()> {
82    ///     let mut scanner = BarcodeScanner::new("/dev/serial0")?;
83    ///     println!("Detected barcode scanner hardware version: {}", scanner.get_hw_version()?);
84    ///     Ok(())
85    /// }
86    /// ```
87    pub fn get_hw_version(&mut self) -> Result<String> {
88        let mut buffer: [u8; 1] = [0; 1];
89        let bytes_read = self.send_read_command_fixed_reply(0x00E1, &mut buffer)?;
90        if bytes_read != 1 {
91            return Err(anyhow!(
92                "incorrect number of bytes read from device, expected 1 received {}",
93                bytes_read
94            ));
95        }
96        match buffer[0] {
97            0x64 => Ok(String::from("V1.00")),
98            0x6E => Ok(String::from("V1.10")),
99            0x78 => Ok(String::from("V1.20")),
100            0x82 => Ok(String::from("V1.30")),
101            0x8C => Ok(String::from("V1.40")),
102            _ => Ok(format!("unknown {:0X}", buffer[0])),
103        }
104    }
105
106    /// return the software version of the attached barcode scanner
107    ///
108    /// # Examples
109    ///
110    /// ```no_run
111    /// use anyhow::Result;
112    /// use waveshare_barcodescanner::interface::BarcodeScanner;
113    /// 
114    /// fn main() -> Result<()> {
115    ///     let mut scanner = BarcodeScanner::new("/dev/serial0")?;
116    ///     println!("Detected barcode scanner software version: {}", scanner.get_sw_version()?);
117    ///     Ok(())
118    /// }
119    /// ```
120    pub fn get_sw_version(&mut self) -> Result<String> {
121        let mut buffer: [u8; 1] = [0; 1];
122        let bytes_read = self.send_read_command_fixed_reply(0x00E2, &mut buffer)?;
123        if bytes_read != 1 {
124            return Err(anyhow!(
125                "incorrect number of bytes read from device, expected 1 received {}",
126                bytes_read
127            ));
128        }
129        match buffer[0] {
130            0x64 => Ok(String::from("V1.00")),
131            0x6E => Ok(String::from("V1.10")),
132            0x78 => Ok(String::from("V1.20")),
133            0x82 => Ok(String::from("V1.30")),
134            0x8C => Ok(String::from("V1.40")),
135            _ => Ok(format!("unknown {:0X}", buffer[0])),
136        }
137    }
138
139    /// return the software date of the attached barcode scanner
140    ///
141    /// # Examples
142    ///
143    /// ```no_run
144    /// use anyhow::Result;
145    /// use waveshare_barcodescanner::interface::BarcodeScanner;
146    /// 
147    /// fn main() -> Result<()> {
148    ///     let mut scanner = BarcodeScanner::new("/dev/serial0")?;
149    ///     println!("Detected barcode scanner software build date: {}", scanner.get_sw_date()?.format("%Y/%m/%d"));
150    ///     Ok(())
151    /// }
152    /// ```
153    pub fn get_sw_date(&mut self) -> Result<NaiveDate> {
154        let mut buffer: [u8; 1] = [0; 1];
155        let bytes_read = self.send_read_command_fixed_reply(0x00E3, &mut buffer)?;
156        if bytes_read != 1 {
157            return Err(anyhow!(
158                "incorrect number of bytes read from device, expected 1 received {}",
159                bytes_read
160            ));
161        }
162        // only the years past year 2000 are returned
163        let year: i32 = buffer[0] as i32 + 2000;
164        let bytes_read = self.send_read_command_fixed_reply(0x00E4, &mut buffer)?;
165        if bytes_read != 1 {
166            return Err(anyhow!(
167                "incorrect number of bytes read from device, expected 1 received {}",
168                bytes_read
169            ));
170        }
171        let month: u32 = buffer[0] as u32;
172        let bytes_read = self.send_read_command_fixed_reply(0x00E5, &mut buffer)?;
173        if bytes_read != 1 {
174            return Err(anyhow!(
175                "incorrect number of bytes read from device, expected 1 received {}",
176                bytes_read
177            ));
178        }
179        let day: u32 = buffer[0] as u32;
180        let date = match NaiveDate::from_ymd_opt(year, month, day) {
181            Some(date) => date,
182            None => {
183                return Err(anyhow!(
184                    "unable to construct date from  year {} month {} day {}",
185                    year,
186                    month,
187                    day
188                ));
189            }
190        };
191        Ok(date)
192    }
193
194    /// start scanning for barcodes
195    ///
196    /// # Examples
197    ///
198    /// ```no_run
199    /// use anyhow::Result;
200    /// use waveshare_barcodescanner::interface::BarcodeScanner;
201    /// 
202    /// fn main() -> Result<()> {
203    ///     let mut scanner = BarcodeScanner::new("/dev/serial0")?;
204    ///     println!("Please scan your badge for identification.");
205    ///     scanner.start_scan()?;
206    ///     match scanner.read_barcode()? {
207    ///         Some(barcode) => println!("data scanned: {}", barcode),
208    ///         None => println!("Please try again. Make sure the barcode on your badge is at the center of the green scanning light."),
209    ///     }
210    ///     Ok(())
211    /// }
212    /// ```
213    pub fn start_scan(&mut self) -> Result<()> {
214        self.send_write_command(0x0002, &[0x01])
215    }
216
217    /// stop scanning for barcodes
218    ///
219    /// # Notes
220    ///
221    /// When a barcode has been scanned, the scanner automatically stops scanning in manual and command mode.
222    pub fn stop_scan(&mut self) -> Result<()> {
223        self.send_write_command(0x0002, &[0x00])
224    }
225
226    /// waits for a barcode payload to be returned from the scanner
227    ///
228    /// will return immediately when the payload has been read or the `scan_timeout` has been reached
229    pub fn read_barcode(&mut self) -> Result<Option<Barcode>> {
230        // read the code ID
231        let mut codeid_buffer: [u8; 1] = [0x00; 1];
232        self.read_from_serial_exact(&mut codeid_buffer, Some(self.scan_timeout))?;
233        if codeid_buffer[0] == 0x00 {
234            // no data received until the timout was reached
235            // 0x00 is an invalid Code ID
236            debug!("timeout waiting for barcode data");
237            return Ok(None);
238        }
239        let mut lines: Vec<Vec<u8>> = Vec::new();
240        loop {
241            trace!("reading next line");
242            let (read_line, end_of_data) = self.read_line_from_serial()?;
243            if read_line.len() > 0 {
244                lines.push(read_line);
245            }
246            if end_of_data {
247                // no more data to read
248                trace!("no more data to read");
249                break;
250            }
251        }
252        if lines.is_empty() {
253            debug!("no barcode data was read from the device");
254            return Ok(None);
255        }
256        debug!(
257            "{} line(s) of barcode data was read from the device",
258            lines.len()
259        );
260        match codeid_buffer[0] {
261            0x65 => {
262                debug!("Interleaved 2of5");
263                Ok(Some(Barcode::Interleaved2of5(
264                    lines.get(0).unwrap().iter().map(|&c| c as char).collect(),
265                )))
266            }
267            0x62 => {
268                debug!("Code39");
269                Ok(Some(Barcode::Code39(
270                    lines.get(0).unwrap().iter().map(|&c| c as char).collect(),
271                )))
272            }
273            0x64 => {
274                debug!("EAN13");
275                Ok(Some(Barcode::EAN13(
276                    lines.get(0).unwrap().iter().map(|&c| c as char).collect(),
277                )))
278            }
279            0x6A => {
280                debug!("Code128");
281                Ok(Some(Barcode::Code128(
282                    lines.get(0).unwrap().iter().map(|&c| c as char).collect(),
283                )))
284            }
285            0x51 => {
286                debug!("QR code");
287                Ok(Some(Barcode::QR(
288                    lines
289                        .iter()
290                        .map(|line| line.iter().map(|&c| c as char).collect())
291                        .collect(),
292                )))
293            }
294            0x75 => {
295                debug!("Dot Matrix code");
296                Ok(Some(Barcode::DotMatrix(
297                    lines
298                        .iter()
299                        .map(|line| line.iter().map(|&c| c as char).collect())
300                        .collect(),
301                )))
302            }
303            _ => Err(anyhow!(
304                "unsupported barcode type received: {:02X}",
305                codeid_buffer[0]
306            )),
307        }
308    }
309
310    /// set the mode of operation and light/buzzer parameters
311    ///
312    /// # Arguments
313    ///
314    /// * `enable_led_indication_on_successful_scan` if true the LED on the circuit board will light up shortly after a successful scan
315    /// * `enable_buzzer` if true a successful scan will be confirmed with a short tone
316    /// * `target_light_mode` specifies how the green target light is used
317    /// * `illumination_mode` specifies how the white LED light will operate
318    /// * `operation_mode` defines the scanning mode
319    ///
320    /// # Note
321    ///
322    /// Only manual and command scanning operations are currently supported.
323    pub fn set_mode(
324        &mut self,
325        enable_led_indication_on_successful_scan: bool,
326        enable_buzzer: bool,
327        target_light_mode: TargetLightMode,
328        illumination_mode: IlluminationMode,
329        operation_mode: OperationMode,
330    ) -> Result<()> {
331        let mut operation: u8 = 0x0;
332        if enable_led_indication_on_successful_scan {
333            operation |= 0x80;
334        }
335        if enable_buzzer {
336            operation |= 0x40;
337        }
338        match target_light_mode {
339            TargetLightMode::AlwaysOff => {}
340            TargetLightMode::AlwaysOn => operation |= 0x20,
341            TargetLightMode::Standard => operation |= 0x10,
342        }
343        match illumination_mode {
344            IlluminationMode::AlwaysOff => {}
345            IlluminationMode::AlwaysOn => operation |= 0x08,
346            IlluminationMode::Standard => operation |= 0x04,
347        }
348        match operation_mode {
349            OperationMode::Manual => {}
350            OperationMode::Command => operation |= 0x01,
351            OperationMode::Continuous => operation |= 0x02,
352            OperationMode::Sensing => operation |= 0x03,
353        }
354        self.send_write_command(0x0000, &[operation])
355    }
356
357    /// set the scanning area and barcodes allowed
358    ///
359    /// # Arguments
360    ///
361    /// * `scan_area` defines the area of the camera view where barcodes are detected
362    /// * `allowed_barcodes` specifies which barcode types are recognized based on the barcode scanner model
363    pub fn set_scan_area_and_barcodes(
364        &mut self,
365        scan_area: ScanArea,
366        allowed_barcodes: Barcodes,
367    ) -> Result<()> {
368        let mut scanner_setting: u8 = 0x0;
369        match scan_area {
370            ScanArea::All => {}
371            ScanArea::Center => scanner_setting |= 0x08,
372        }
373        match allowed_barcodes {
374            Barcodes::EnableAll => scanner_setting |= 0x02,
375            Barcodes::DisableAll => {}
376            Barcodes::Default => scanner_setting |= 0x04,
377        }
378        self.send_write_command(0x002C, &[scanner_setting])
379    }
380
381    /// set the maximum time for a manual or command scan before the scanner goes inactive again
382    ///
383    /// # Arguments
384    ///
385    /// * `scan_timeout` the duration to activate scanning for, allowed range is 1ms to 25.5s
386    ///
387    /// # Note
388    ///
389    /// By default the barcode scanner is set to 5s of scanning duration
390    pub fn set_scan_timeout(&mut self, scan_timeout: Duration) -> Result<()> {
391        if scan_timeout > Duration::from_millis(25500) {
392            return Err(anyhow!(
393                "timeout is too big, maximum value is 25500 ms (25.5s)"
394            ));
395        }
396        if scan_timeout == Duration::from_millis(0) {
397            return Err(anyhow!("this crate does not support indefinite waiting"));
398        }
399        let scan_timeout_byte: u8 = (scan_timeout.as_millis() / 100).try_into()?;
400        self.send_write_command(0x0006, &[scan_timeout_byte])?;
401        self.scan_timeout = scan_timeout;
402        Ok(())
403    }
404
405    /// enable/disable barcode type: EAN13
406    pub fn allow_ean13(&mut self, enable: bool) -> Result<()> {
407        if enable {
408            self.send_write_command(0x002E, &[0x01])
409        } else {
410            self.send_write_command(0x002E, &[0x00])
411        }
412    }
413
414    /// enable/disable barcode type: EAN8
415    pub fn allow_ean8(&mut self, enable: bool) -> Result<()> {
416        if enable {
417            self.send_write_command(0x002F, &[0x01])
418        } else {
419            self.send_write_command(0x002F, &[0x00])
420        }
421    }
422
423    /// enable/disable barcode type: GS1 Databar Stacked(RSS)
424    pub fn allow_rss_stack(&mut self, enable: bool) -> Result<()> {
425        if enable {
426            self.send_write_command(0x0026, &[0x01])
427        } else {
428            self.send_write_command(0x0026, &[0x00])
429        }
430    }
431
432    /// enable/disable barcode type: GS1 Databar(RSS-14)
433    pub fn allow_rss14(&mut self, enable: bool) -> Result<()> {
434        if enable {
435            self.send_write_command(0x004F, &[0x01])
436        } else {
437            self.send_write_command(0x004F, &[0x00])
438        }
439    }
440
441    /// enable/disable barcode type: GS1 Databar Limited(RSS)
442    pub fn allow_limited_rss(&mut self, enable: bool) -> Result<()> {
443        if enable {
444            self.send_write_command(0x0050, &[0x01])
445        } else {
446            self.send_write_command(0x0050, &[0x00])
447        }
448    }
449
450    /// enable/disable barcode type: GS1 Databar Expanded(RSS)
451    ///
452    /// optionally specify the minimum and/or maximum number of characters expected in a valid barcode,
453    /// all others will be ignored
454    pub fn allow_expanded_rss(
455        &mut self,
456        enable: bool,
457        min_length: Option<u8>,
458        max_length: Option<u8>,
459    ) -> Result<()> {
460        if enable {
461            if let Some(min_length) = min_length {
462                self.send_write_command(0x0052, &[min_length])?;
463            }
464            if let Some(max_length) = max_length {
465                self.send_write_command(0x0053, &[max_length])?;
466            }
467            self.send_write_command(0x0051, &[0x01])
468        } else {
469            self.send_write_command(0x0051, &[0x00])
470        }
471    }
472
473    /// enable/disable barcode type: MSI-Plessey
474    ///
475    /// optionally specify the minimum and/or maximum number of characters expected in a valid barcode,
476    /// all others will be ignored
477    pub fn allow_msi(
478        &mut self,
479        enable: bool,
480        min_length: Option<u8>,
481        max_length: Option<u8>,
482    ) -> Result<()> {
483        if enable {
484            if let Some(min_length) = min_length {
485                self.send_write_command(0x004D, &[min_length])?;
486            }
487            if let Some(max_length) = max_length {
488                self.send_write_command(0x004E, &[max_length])?;
489            }
490            self.send_write_command(0x004C, &[0x01])
491        } else {
492            self.send_write_command(0x004C, &[0x00])
493        }
494    }
495
496    /// enable/disable barcode type: Code11
497    ///
498    /// optionally specify the minimum and/or maximum number of characters expected in a valid barcode,
499    /// all others will be ignored
500    pub fn allow_code11(
501        &mut self,
502        enable: bool,
503        min_length: Option<u8>,
504        max_length: Option<u8>,
505    ) -> Result<()> {
506        if enable {
507            if let Some(min_length) = min_length {
508                self.send_write_command(0x004A, &[min_length])?;
509            }
510            if let Some(max_length) = max_length {
511                self.send_write_command(0x004B, &[max_length])?;
512            }
513            self.send_write_command(0x0049, &[0x01])
514        } else {
515            self.send_write_command(0x0049, &[0x00])
516        }
517    }
518
519    /// enable/disable barcode type: Matrix 2of5
520    ///
521    /// optionally specify the minimum and/or maximum number of characters expected in a valid barcode,
522    /// all others will be ignored
523    pub fn allow_matrix2of5(
524        &mut self,
525        enable: bool,
526        min_length: Option<u8>,
527        max_length: Option<u8>,
528    ) -> Result<()> {
529        if enable {
530            if let Some(min_length) = min_length {
531                self.send_write_command(0x0047, &[min_length])?;
532            }
533            if let Some(max_length) = max_length {
534                self.send_write_command(0x0048, &[max_length])?;
535            }
536            self.send_write_command(0x0046, &[0x01])
537        } else {
538            self.send_write_command(0x0046, &[0x00])
539        }
540    }
541
542    /// enable/disable barcode type: Industrial
543    ///
544    /// optionally specify the minimum and/or maximum number of characters expected in a valid barcode,
545    /// all others will be ignored
546    pub fn allow_industrial(
547        &mut self,
548        enable: bool,
549        min_length: Option<u8>,
550        max_length: Option<u8>,
551    ) -> Result<()> {
552        if enable {
553            if let Some(min_length) = min_length {
554                self.send_write_command(0x0044, &[min_length])?;
555            }
556            if let Some(max_length) = max_length {
557                self.send_write_command(0x0045, &[max_length])?;
558            }
559            self.send_write_command(0x0043, &[0x01])
560        } else {
561            self.send_write_command(0x0043, &[0x00])
562        }
563    }
564
565    /// enable/disable barcode type: CodeBar
566    ///
567    /// optionally specify the minimum and/or maximum number of characters expected in a valid barcode,
568    /// all others will be ignored
569    pub fn allow_codebar(
570        &mut self,
571        enable: bool,
572        with_start_stop_character: bool,
573        min_length: Option<u8>,
574        max_length: Option<u8>,
575    ) -> Result<()> {
576        if enable {
577            if let Some(min_length) = min_length {
578                self.send_write_command(0x003D, &[min_length])?;
579            }
580            if let Some(max_length) = max_length {
581                self.send_write_command(0x003E, &[max_length])?;
582            }
583            let mut mode: u8 = 0x01;
584            if with_start_stop_character {
585                mode |= 0x02;
586            }
587            self.send_write_command(0x003C, &[mode])
588        } else {
589            self.send_write_command(0x003C, &[0x00])
590        }
591    }
592
593    /// enable/disable barcode type: Code128
594    ///
595    /// optionally specify the minimum and/or maximum number of characters expected in a valid barcode,
596    /// all others will be ignored
597    pub fn allow_code128(
598        &mut self,
599        enable: bool,
600        min_length: Option<u8>,
601        max_length: Option<u8>,
602    ) -> Result<()> {
603        if enable {
604            if let Some(min_length) = min_length {
605                self.send_write_command(0x0034, &[min_length])?;
606            }
607            if let Some(max_length) = max_length {
608                self.send_write_command(0x0035, &[max_length])?;
609            }
610            self.send_write_command(0x0033, &[0x01])
611        } else {
612            self.send_write_command(0x0033, &[0x00])
613        }
614    }
615
616    /// enable/disable barcode type: Code39
617    ///
618    /// optionally specify the minimum and/or maximum number of characters expected in a valid barcode,
619    /// all others will be ignored
620    pub fn allow_code39(
621        &mut self,
622        enable: bool,
623        min_length: Option<u8>,
624        max_length: Option<u8>,
625    ) -> Result<()> {
626        if enable {
627            if let Some(min_length) = min_length {
628                self.send_write_command(0x0037, &[min_length])?;
629            }
630            if let Some(max_length) = max_length {
631                self.send_write_command(0x0038, &[max_length])?;
632            }
633            self.send_write_command(0x0036, &[0x01])
634        } else {
635            self.send_write_command(0x0036, &[0x00])
636        }
637    }
638
639    /// enable/disable barcode type: Code93
640    ///
641    /// optionally specify the minimum and/or maximum number of characters expected in a valid barcode,
642    /// all others will be ignored
643    pub fn allow_code93(
644        &mut self,
645        enable: bool,
646        min_length: Option<u8>,
647        max_length: Option<u8>,
648    ) -> Result<()> {
649        if enable {
650            if let Some(min_length) = min_length {
651                self.send_write_command(0x003A, &[min_length])?;
652            }
653            if let Some(max_length) = max_length {
654                self.send_write_command(0x003B, &[max_length])?;
655            }
656            self.send_write_command(0x0039, &[0x01])
657        } else {
658            self.send_write_command(0x0039, &[0x00])
659        }
660    }
661
662    /// enable/disable barcode type: UPCA
663    pub fn allow_upca(&mut self, enable: bool) -> Result<()> {
664        if enable {
665            self.send_write_command(0x0030, &[0x01])
666        } else {
667            self.send_write_command(0x0030, &[0x00])
668        }
669    }
670
671    /// enable/disable barcode type: UPCE0
672    pub fn allow_upce0(&mut self, enable: bool) -> Result<()> {
673        if enable {
674            self.send_write_command(0x0031, &[0x01])
675        } else {
676            self.send_write_command(0x0031, &[0x00])
677        }
678    }
679
680    /// enable/disable barcode type: UPCE1
681    pub fn allow_upce1(&mut self, enable: bool) -> Result<()> {
682        if enable {
683            self.send_write_command(0x0032, &[0x01])
684        } else {
685            self.send_write_command(0x0032, &[0x00])
686        }
687    }
688
689    /// enable/disable barcode type: PDF417
690    pub fn allow_pdf417(&mut self, enable: bool) -> Result<()> {
691        if enable {
692            self.send_write_command(0x0055, &[0x01])
693        } else {
694            self.send_write_command(0x0055, &[0x00])
695        }
696    }
697
698    /// enable/disable barcode type: Micro PDF417
699    pub fn allow_micro_pdf417(&mut self, enable: bool) -> Result<()> {
700        if enable {
701            self.send_write_command(0x0029, &[0x01])
702        } else {
703            self.send_write_command(0x0029, &[0x00])
704        }
705    }
706
707    /// enable/disable barcode type: ISBN
708    pub fn allow_micro_isbn(&mut self, enable: bool) -> Result<()> {
709        if enable {
710            self.send_write_command(0x0057, &[0x01])
711        } else {
712            self.send_write_command(0x0057, &[0x00])
713        }
714    }
715
716    /// enable/disable barcode type: ISSN
717    pub fn allow_micro_issn(&mut self, enable: bool) -> Result<()> {
718        if enable {
719            self.send_write_command(0x0056, &[0x01])
720        } else {
721            self.send_write_command(0x0056, &[0x00])
722        }
723    }
724
725    /// enable/disable barcode type: Dot Matrix code
726    pub fn allow_dotmatrix(&mut self, enable: bool) -> Result<()> {
727        if enable {
728            self.send_write_command(0x0054, &[0x01])
729        } else {
730            self.send_write_command(0x0054, &[0x00])
731        }
732    }
733
734    /// enable/disable barcode type: QR code
735    pub fn allow_qr(&mut self, enable: bool) -> Result<()> {
736        if enable {
737            self.send_write_command(0x003F, &[0x01])
738        } else {
739            self.send_write_command(0x003F, &[0x00])
740        }
741    }
742
743    /// enable/disable barcode type: Micro QR
744    pub fn allow_microqr(&mut self, enable: bool) -> Result<()> {
745        if enable {
746            self.send_write_command(0x005F, &[0x01])
747        } else {
748            self.send_write_command(0x005F, &[0x00])
749        }
750    }
751
752    /// enable/disable barcode type: Interleaved 2 of 5
753    ///
754    /// optionally specify the minimum and/or maximum number of characters expected in a valid barcode,
755    /// all others will be ignored
756    pub fn allow_interleaved2of5(
757        &mut self,
758        enable: bool,
759        min_length: Option<u8>,
760        max_length: Option<u8>,
761    ) -> Result<()> {
762        if enable {
763            if let Some(min_length) = min_length {
764                self.send_write_command(0x0041, &[min_length])?;
765            }
766            if let Some(max_length) = max_length {
767                self.send_write_command(0x0042, &[max_length])?;
768            }
769            self.send_write_command(0x0040, &[0x01])
770        } else {
771            self.send_write_command(0x0040, &[0x00])
772        }
773    }
774
775    /// disable setting changes via barcode scanning (seems like a really good idea for production use)
776    pub fn disable_setting_scanning(&mut self) -> Result<()> {
777        let mut buffer: [u8; 1] = [0x00; 1];
778        let bytes_read = self.send_read_command_fixed_reply(0x0003, &mut buffer)?;
779        if bytes_read != 1 {
780            return Err(anyhow!(
781                "incorrect number of bytes read from device, expected 1 received {}",
782                bytes_read
783            ));
784        }
785        buffer[0] &= 0xfe;
786        buffer[0] |= 0x02;
787        self.send_write_command(0x0003, &buffer)?;
788        Ok(())
789    }
790
791    /// enable setting changes via barcode scanning
792    pub fn enable_setting_scanning(&mut self) -> Result<()> {
793        let mut buffer: [u8; 1] = [0x00; 1];
794        let bytes_read = self.send_read_command_fixed_reply(0x0003, &mut buffer)?;
795        if bytes_read != 1 {
796            return Err(anyhow!(
797                "incorrect number of bytes read from device, expected 1 received {}",
798                bytes_read
799            ));
800        }
801        buffer[0] &= 0xfc;
802        self.send_write_command(0x0003, &buffer)?;
803        Ok(())
804    }
805
806    /// save all pending changes to flash
807    pub fn save_to_flash(&mut self) -> Result<()> {
808        self.send_to_serial(0x09, 1, 0x0000, None, Some(&[0x00]))?;
809        let mut buffer: [u8; 1] = [0x00; 1];
810        self.read_from_serial_command_reply(&mut buffer)?;
811        Ok(())
812    }
813
814    /// set the barcode scanner to factory defaults
815    ///
816    /// # Note
817    ///
818    /// Make sure to afterwards enable `UART` mode via the corresponding barcode again.
819    pub fn factory_reset(&mut self) -> Result<()> {
820        self.send_to_serial(0x08, 1, 0x00D9, None, Some(&[0x50]))?;
821        let mut buffer: [u8; 1] = [0x00; 1];
822        self.read_from_serial_command_reply(&mut buffer)?;
823        Ok(())
824    }
825
826    /// send a read command and return the reply from the barcode scanner
827    ///
828    /// used for an expected payload size upon read
829    fn send_read_command_fixed_reply(
830        &mut self,
831        address: u16,
832        return_data: &mut [u8],
833    ) -> Result<usize> {
834        self.send_to_serial(0x07, 0x01, address, Some(return_data.len()), None)?;
835        self.read_from_serial_command_reply(return_data)
836    }
837
838    /// send a write command to the barcode scanner
839    fn send_write_command(&mut self, address: u16, data: &[u8]) -> Result<()> {
840        self.send_to_serial(0x08, data.len().try_into()?, address, None, Some(data))?;
841        let mut buffer: [u8; 1] = [0x00; 1];
842        self.read_from_serial_command_reply(&mut buffer)?;
843        Ok(())
844    }
845
846    /// write a command packet to the barcode scanner
847    fn send_to_serial(
848        &mut self,
849        function_type: u8,
850        length: u8,
851        address: u16,
852        return_data_length: Option<usize>,
853        write_data: Option<&[u8]>,
854    ) -> Result<()> {
855        let mut buffer: Vec<u8> = Vec::new();
856        buffer.push(0x7e);
857        buffer.push(0x00);
858        buffer.push(function_type);
859        buffer.push(length);
860        buffer.append(&mut address.to_be_bytes().to_vec());
861        if let Some(return_data_length) = return_data_length {
862            // special case, the barcode scanner expects a length of 0 when 256 bytes should be returned
863            if return_data_length == 256 {
864                buffer.push(0x00);
865            } else {
866                buffer.push(return_data_length.try_into()?);
867            }
868        }
869        if let Some(write_data) = write_data {
870            buffer.append(&mut write_data.to_vec());
871        }
872        buffer.append(&mut calculate_crc(&buffer[2..])?.to_be_bytes().to_vec());
873        debug!("WRITE TO SERIAL {} bytes: {:02X?}", buffer.len(), buffer);
874        self.port.write_all(&buffer)?;
875        Ok(())
876    }
877
878    /// read a command reply packet from the barcode scanner
879    ///
880    /// the `read_data` array needs to be allocated to the exact size of payload data expected
881    fn read_from_serial_command_reply(&mut self, read_data: &mut [u8]) -> Result<usize> {
882        debug!("reading {} bytes", read_data.len() + 6);
883        let mut buffer: Vec<u8> = (0..read_data.len() + 6).map(|_| 0x00).collect();
884        self.port.read_exact(&mut buffer)?;
885        debug!("READ FROM SERIAL {} bytes: {:02X?}", buffer.len(), buffer);
886        if buffer.len() < 6 {
887            // not enough data read
888            return Err(anyhow!(
889                "read data is shorter than expected, got {} expected {} bytes",
890                buffer.len(),
891                read_data.len()
892            ));
893        }
894        if buffer[0] != 0x02 || buffer[1] != 0x00 {
895            // invalid header
896            return Err(anyhow!("invalid header received"));
897        }
898        if buffer[2] != 0x00 {
899            // operation was not successful
900            return Err(anyhow!(
901                "barcode scanner indicates an unsuccessful operation, rc: {}",
902                buffer[2]
903            ));
904        }
905        // verify the checksum
906        let received_checksum =
907            ((buffer[buffer.len() - 2] as u16) << 8) | buffer[buffer.len() - 1] as u16;
908        verify_crc(&buffer[2..buffer.len() - 2], received_checksum)?;
909        let mut data_length: usize = buffer[3] as usize;
910        // special case, the barcode scanner returns a length of 0 when 256 bytes have been returned
911        if data_length == 0 {
912            data_length = 256;
913        }
914        read_data[..data_length as usize].copy_from_slice(&buffer[4..data_length + 4]);
915        Ok(data_length)
916    }
917
918    /// read a full packet from the barcode scanner
919    ///
920    /// the `read_data` array needs to be allocated to the exact size of data expected
921    ///
922    /// wait until the optional `timeout` if specified
923    fn read_from_serial_exact(
924        &mut self,
925        read_data: &mut [u8],
926        timeout: Option<Duration>,
927    ) -> Result<()> {
928        let start_ts = Instant::now();
929        loop {
930            debug!("reading {} bytes", read_data.len());
931            match self.port.read_exact(read_data) {
932                Ok(()) => {}
933                Err(err) => {
934                    if let Some(timeout) = timeout
935                        && err.kind() == std::io::ErrorKind::TimedOut
936                    {
937                        // no data from the serial interface yet, use the passed in timeout
938                        if start_ts.elapsed() < timeout {
939                            continue;
940                        }
941                        // timeout reached, return everything read so far
942                        return Ok(());
943                    }
944                    return Err(err.into());
945                }
946            }
947            debug!(
948                "READ FROM SERIAL {} bytes: {:02X?}",
949                read_data.len(),
950                read_data
951            );
952            return Ok(());
953        }
954    }
955
956    /// read the next line of recognized data from the barcode scanner
957    ///
958    /// will wait until EOL or end of data
959    fn read_line_from_serial(&mut self) -> Result<(Vec<u8>, bool)> {
960        let mut result: Vec<u8> = Vec::with_capacity(256);
961        loop {
962            let mut buffer: [u8; 1] = [0; 1];
963            debug!("reading {} bytes", buffer.len());
964            match self.port.read(&mut buffer) {
965                Ok(0) => {
966                    return Err(anyhow!("no data was read from the device"));
967                }
968                Ok(read_bytes) => {
969                    trace!(
970                        "READ FROM SERIAL {} bytes: {:02X?}",
971                        read_bytes,
972                        &buffer[..read_bytes]
973                    );
974                    if buffer[0] == 0x0A {
975                        trace!("EOL detected, result len {}", result.len());
976                        return Ok((result, false));
977                    }
978                    if buffer[0] == 0x0D {
979                        trace!("end of data detected, result len {}", result.len());
980                        return Ok((result, true));
981                    }
982                    result.append(&mut buffer[..read_bytes].to_vec());
983                }
984                Err(err) => {
985                    return Err(err.into());
986                }
987            }
988        }
989    }
990}