Source code for de2120_barcode_scanner

#-----------------------------------------------------------------------------
# de2120_barcode_scanner.py
#
# Python library for the SparkFun 2D Barcode Scanner Breakout.
# https://www.sparkfun.com/products/18088
#
#------------------------------------------------------------------------
# Written by Priyanka Makin @ SparkFun Electronics, April 2021
#
# Do you like this library? Help support SparkFun. Buy a board!
#==================================================================================
# Copyright (c) 2020 SparkFun Electronics
#
# Permission is hereby granted, free of charge, to any person obtaining a copy 
# of this software and associated documentation files (the "Software"), to deal 
# in the Software without restriction, including without limitation the rights 
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
# copies of the Software, and to permit persons to whom the Software is 
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all 
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
# SOFTWARE.
#==================================================================================

"""
de2120_barcode_scanner
============
Python module for the 2D Barcode Scanner.

This python package is a port of the exisiting [SparkFun DE2120 Arduino Library](https://github.com/sparkfun/SparkFun_DE2120_Arduino_Library)

"""
#-----------------------------------------------------------------------------------

import serial
import time

_DEFAULT_NAME = "DE2120 Barcode Scanner"

[docs]class DE2120BarcodeScanner(object): """ DE2120BarcodeScanner Initialize the library with the given port. :param hard_port: The port to use to communicate with the module, this is a serial port at 9600 baud rate. :return: The DE2120BarcodeScanner object. :rtype: Object """ # Constructor device_name = _DEFAULT_NAME # DE2120 response DE2120_COMMAND_ACK = 0x06 DE2120_COMMAND_NACK = 0x15 # Send commands # Need to prepend "^_^" and append "." COMMAND_START_SCAN = "SCAN" COMMAND_STOP_SCAN = "SLEEP" COMMAND_SET_DEFAULTS = "DEFALT" COMMAND_GET_VERSION = "DSPYFW" PROPERTY_BUZZER_FREQ = "BEPPWM" # BEPPWM0 - Active Drive # BEPPWM1 - Passive Low Freq # BEPPWM2 - Passive Med Freq (default) # BEPPWM3 - Passive Hi Freq PROPERTY_DECODE_BEEP = "BEPSUC" # BEPSUC1 - ON (default) # BEPSUC0 - OFF PROPERTY_BOOT_BEEP = "BEPPWR" # BEPPWR1 - ON (default) # BEPPWR0 - OFF PROPERTY_FLASH_LIGHT = "LAMENA" # LAMENA1 - ON (default) # LAMENA0 - OFF PROPERTY_AIM_LIGHT = "AIMENA" # AIMENA1 - ON (default) # AIMENA0 - OFF PROPERTY_READING_AREA = "IMGREG" # IMGREG0 - Full Width (default) # IMGREG1 - Center 80% # IMGREG2 - Center 60% # IMGREG3 - Center 40% # IMGREG4 - Center 20% PROPERTY_MIRROR_FLIP = "MIRLRE" # MIRLRE1 - ON # MIRLRE0 - OFF (default) PROPERTY_USB_DATA_FORMAT = "UTFEAN" # UTFEAN0 - GBK (default) # UTFEAN1 - UTF-8 PROPERTY_SERIAL_DATA_FORMAT = "232UTF" # 232UTF0 - GBK (default) # 232UTF1 - UTF-8 # 232UTF2 - Unicode BIG # 232UTF3 - Unicode little PROPERTY_INVOICE_MODE = "SPCINV" # SPCINV1 - ON # SPCINV0 - OFF (default) PROPERTY_VIRTUAL_KEYBOARD = "KBDVIR" # KBDVIR1 - ON (default) # KBDVIR0 - OFF PROPERTY_COMM_MODE = "POR" # PORKBD - USB-KBW Mode # PORHID - USB-HID Mode # PORVIC - USB-COM Mode # POR232 - TTL/RS232 PROPERTY_BAUD_RATE = "232BAD" # 232BAD2 - 1200 bps # 232BAD3 - 2400 bps # 232BAD4 - 4800 bps # 232BAD5 - 9600 bps # 232BAD6 - 19200 bps # 232BAD7 - 38400 bps # 232BAD8 - 57600 bps # 232BAD9 - 115200 bps (default) PROPERTY_READING_MODE = "SCM" # SCMMAN - Manual (default) # SCMCNT - Continuous # SCMMDH - Motion Mode PROPERTY_CONTINUOUS_MODE_INTERVAL = "CNTALW" # CNTALW0 - Output Once # CNTALW1 - Output Continuous No Interval # CNTALW2 - Output Continuous 0.5s Interval # CNTALW3 - Output Continuous 1s Interval PROPERTY_MOTION_SENSITIVITY = "MDTTHR" # MDTTHR15 - Extremely High Sensitivity # MDTTHR20 - High Sensitivity (default) # MDTTHR30 - Highish Sensitivity # MDTTHR50 - Mid Sensitivity # MDTTHR100 - Low Sensitivity PROPERTY_TRANSFER_CODE_ID = "CIDENA" # CIDENA1 - Transfer Code ID # CIDENA0 - Do Not Transfer Code ID (default) PROPERTY_KBD_CASE_CONVERSION = "KBDCNV" # KBDCNV0 - No conversion (default) # KBDCNV1 - ALL CAPS # KBDCNV2 - all lowercase # KBDCNV3 - case-to-case # Barcode Style Enable/Disable PROPERTY_ENABLE_ALL_1D = "ODCENA" PROPERTY_DISABLE_ALL_1D = "ODCDIS" PROPERTY_ENABLE_ALL_2D = "AQRENA" PROPERTY_DISABLE_ALL_2D = "AQRDIS" # Constructor def __init__(self, hard_port = None): if hard_port is None: self.hard_port = serial.Serial("/dev/ttyACM0", 115200, timeout=1) else: self.hard_port = hard_port # -------------------------------------------------------- # begin() # # Initializes the device with basic settings. Returns false # if the device is not detected
[docs] def begin(self): """ Initializes the device with basic settings. Calls the is_connected() function :return: Returns true if initialization was successful :rtype: bool """ if self.is_connected() == False: return False # Clear any remaining incoming chars. This prevents a mis-read # of the first barcode self.hard_port.flush() # We're all setup return True
# --------------------------------------------------------- # is_connected() # # Try to retrieve the firmware verison number as a test to # determine whether the module is connected.
[docs] def is_connected(self): """ Ask the DE2120 for the firmware version. :return: Returns true if the DE2120 responds with an ACK. Retruns false otherwise. :rtype: bool """ # Try sending the firmware version command write_string = "^_^" + chr(4) + "SPYFW." self.hard_port.write(write_string.encode()) # Now, look for module response # If it's an ACK, return true # Otherwise, return false incoming = self.hard_port.read() if ord(incoming) == 0x06: # ACK return True elif ord(incoming) == 0x15: # NACK return False else: return False
# --------------------------------------------------------- # factory_default() # # Returns the DE2120 to factory default settings. This will # disconnect the module from the serial port
[docs] def factory_default(self): """ Send command to put the module back into facory default settings. This will disconnect the module from the serial port. :return: True if command successfully received, false otherwise. :rtype: bool """ return self.send_command(self.COMMAND_SET_DEFAULTS)
# -------------------------------------------------------- # available() # # Returns the number of bytes in the serial receive buffer
[docs] def available(self): """ :return: the number of bytes in the serial receive buffer :rtype: int """ return self.hard_port.in_waiting
# -------------------------------------------------------- # read() # # Read byte from the serial port
[docs] def read(self): """ :return: the first byte on the serial port :rtype: int """ return self.hard_port.read()
# -------------------------------------------------------- # send_command(cmd, arg, max_wait_in_ms) # # Construct a command/parameter and send it to the module.
[docs] def send_command(self, cmd, arg = ""): """ Create command string and send to DE2120 over serial port. Check serial buffer for a response :param cmd: The command name :param arg: The command variation, if there is one :return: True if the response from DE2120 contains the ACK character, false otherwise. :rtype: bool """ start = '^_^' end = '.' command_string = start + cmd + arg + end # Use encode() to turn string into bytes self.hard_port.write(command_string.encode()) incoming = self.hard_port.read() if ord(incoming) == 0x06: return True elif ord(incoming) == 0x15: return False return False
# -------------------------------------------------------- # read_barcode() # # Check the receive buffer for serial data from the barcode # scanner.
[docs] def read_barcode(self): """ Read from the serial buffer until we hit a new line character :return: the string in the serial buffer :rtype: bool """ # Check if there's data available if self.hard_port.in_waiting == False: return False # Read from serial port incoming = self.hard_port.read_until() return incoming.decode()
# ------------------------------------------------------- # change_baud_rate(baud) # # Change the serial baud rate for the barcode module
[docs] def change_baud_rate(self, baud): """ Change the serial baud rate for the barcode module. Default 115200 :param baud: baud rate to change to :return: true if command is successfully sent, false otherwise :rtype: bool """ if baud == 1200: arg = '2' elif baud == 2400: arg = '3' elif baud == 4800: arg = '4' elif baud == 9600: arg = '5' elif baud == 19200: arg = '6' elif baud == 38400: arg = '7' elif baud == 57600: arg = '8' else: # Default at 115200 bps arg = '9' return self.send_command(self.PROPERTY_BAUD_RATE, arg)
# -------------------------------------------------------- # change_buzzer_tone(tone) # # Change the beep frequency between low, med, and high
[docs] def change_buzzer_tone(self, tone): """ Change the buzzer frequency between low, med, and high :param tone: int that's 1 = low, 2 = med, 3 = high frequency :return: true if command is successfully sent, false otherwise :rtype: bool """ # Only change the frequency if a valid value is passes if tone > 0 and tone < 4: return self.send_command(self.PROPERTY_BUZZER_FREQ, str(tone)) return False
# -------------------------------------------------------- # enable_decode_beep() # # Enable buzzer beep on successful read
[docs] def enable_decode_beep(self): """ Enable beep on successful read :return: true if command is successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_DECODE_BEEP, "1")
# --------------------------------------------------------- # disable_decode_beep() # # Disable buzzer beep on successful read
[docs] def disable_decode_beep(self): """ Disable beep on successful read :return: true if command is successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_DECODE_BEEP, "0")
# -------------------------------------------------------- # enable_boot_beep # # Enable buzzer beep on module startup
[docs] def enable_boot_beep(self): """ Enable beep on module startup :return: true if command is successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_BOOT_BEEP, "1")
# -------------------------------------------------------- # disable_boot_beep # # Disable buzzer beep on module startup
[docs] def disable_boot_beep(self): """ Disable beep on module startup :return: true if command successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_BOOT_BEEP, "0")
# --------------------------------------------------------- # light_on() # # Turn white illumination LED on
[docs] def light_on(self): """ Turn white illumination LED on :return: true if command successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_FLASH_LIGHT, "1")
# --------------------------------------------------------- # light_off() # # Turn white illumination LED off
[docs] def light_off(self): """ Turn white illumination LED off :return: true if command successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_FLASH_LIGHT, "0")
# --------------------------------------------------------- # reticle_on() # # Turn red scan line on
[docs] def reticle_on(self): """ Turn red scan line on :return: true if command successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_AIM_LIGHT, "1")
# --------------------------------------------------------- # reticle_off() # # Turn red scan line off
[docs] def reticle_off(self): """ Turn red scan line off :return true if command successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_AIM_LIGHT, "0")
# --------------------------------------------------------- # change_reading_area() # # Change the percentage of the frame to scan for barcodes
[docs] def change_reading_area(self, percent): """ Change the percentage of the frame to scan for barcodes :param percent: Percentage of frame to scan. Valid values are 100, 80, 60, 40, 20 as stated in the DE2120 Scan Setting Manual :return: true if command successfully sent, false otherwise :rtype: bool """ if percent == 80: arg = '1' elif percent == 60: arg = '2' elif percent == 40: arg = '3' elif percent == 20: arg = '4' else: # Default to scanning 100% of the area arg = '0' return self.send_command(self.PROPERTY_READING_AREA, arg)
# --------------------------------------------------------- # enable_image_flipping() # # Enable mirror image reading as defined in the DE2120 Settings Manual
[docs] def enable_image_flipping(self): """ Enable mirror image reading :return: true if the command successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_MIRROR_FLIP, "1")
# -------------------------------------------------------- # disable_image_flipping() # # Disable mirror image reading as defined in the DE2120 Settings Manual
[docs] def disable_image_flipping(self): """ Disable mirror image reading :return: true if the command is successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_MIRROR_FLIP, "0")
# --------------------------------------------------------- # USB_mode(mode) # # Enable USB communication and set the mode # THIS WILL MAKE THE MODULE UNRESPONSIVE ON TTL
[docs] def USB_mode(self, mode): """ Enable USB communication and set the mode. THIS WILL MAKE THE MODULE UNRESPONSIVE ON COM PORT :param mode: string defining what USB mode to set the module in. Valid arguments are "KBD", "HID", "232". :return: true if the command is successfully sent, false otherwise :rtype: bool """ if mode == "KBD" or mode == "HID" or mode == "232": return self.send_command(self.PROPERTY_COMM_MODE, mode) return False
# ---------------------------------------------------------- # enable_continuous_read(repeat_interval) # # Enable continuous reading mode and set the interval for same-code reads
[docs] def enable_continuous_read(self, repeat_interval = 2): """ Enable continuous reading of barcodes and set the time interval for same-code reads :param repeat_interval: int parameter. 0: same code output 1 times 1: continuous output with same code without interval 2: continuous output with same code, 0.5 second interval (default) 3: continuous output with same code, 1 second interval :return: true if the command is successfully sent, false otherwise :rtype: bool """ if repeat_interval < 4 and repeat_interval >= 0: self.send_command(self.PROPERTY_READING_MODE, "CNT") # Wait for command to take effect time.sleep(0.01) return self.send_command(self.PROPERTY_CONTINUOUS_MODE_INTERVAL, str(repeat_interval)) return False
# --------------------------------------------------------- # enable_motion_sense(sensitivity) # # Enable the motion sensitive read mode.
[docs] def enable_motion_sense(self, sensitivity = 20): """ Enable the motion sensitive read mode and set sensitivity level :param sensitivity: int value. The smaller the sensitivity, the more sensitive. Values are taken from the DE2120 settings manual. Valid arguments are: 15 (very high), 20 (high/default), 30 (little high), 50 (general), 100 (low sensitivity) :return: true if command is successfully sent, false otherwise :rtype: bool """ # Reject invalid sensitivity values if sensitivity == 15 or sensitivity == 20 or sensitivity == 30 or sensitivity == 50 or sensitivity == 100: sense = str(sensitivity) self.send_command(self.PROPERTY_READING_MODE, "MDH") # Wait for command to take effect time.sleep(0.01) return self.send_command(self.PROPERTY_COMM_MODE, sense) return False
# --------------------------------------------------------- # enable_manual_trigger() # # Disable the motion sensitive and continuous read mode. # Return to the default trigger mode.
[docs] def enable_manual_trigger(self): """ Disable the motioin sensitive and continuous read mode. Return to the default trigger mode. :return: true if the command is successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_READING_MODE, "MAN")
# --------------------------------------------------------- # enable_all_1D() # # Enable decoding of all 1D symbologies
[docs] def enable_all_1D(self): """ Enable decoding of all 1D symbologies :return: true if the command is successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_ENABLE_ALL_1D)
# --------------------------------------------------------- # disable_all_1D() # # Disable decoding of all 1D symbologies
[docs] def disable_all_1D(self): """ Disable decoding of all 1D symbologies :return: true if the command is successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_DISABLE_ALL_1D)
# --------------------------------------------------------- # enable_all_2D() # # Enable decoding of all 2D symbologies
[docs] def enable_all_2D(self): """ Enable decoding of all 2D symbologies :return: true if the command is successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_ENABLE_ALL_2D)
# -------------------------------------------------------- # disable_all_2D() # # Disable decoding of all 2D symbologies
[docs] def disable_all_2D(self): """ Disable decoding of all 2D symbologies :return: true if the command is successfully sent, false otherwise :rtype: bool """ return self.send_command(self.PROPERTY_DISABLE_ALL_2D)
# --------------------------------------------------------- # start_scan() # # Start reading when in trigger mode (default)
[docs] def start_scan(self): """ Start reading when in trigger mode (default) :return: true if the command is successfully sent, false otherwise :rtype: bool """ return self.send_command(self.COMMAND_START_SCAN)
# ---------------------------------------------------------- # stop_scan() # # Stop reading when in trigger mode. Module will automatically # stop reading after a few seconds
[docs] def stop_scan(self): """ Stop reading when in trigger mode. Module will automatically stop reading after a few seconds :return: true if the command is successfully sent, false otherwise :rtype: bool """ return self.send_command(self.COMMAND_STOP_SCAN)