Barcode scanner: Add buzzer, adjust USB timings, add scan engine configuration, fix UART code

This commit is contained in:
Skylar Ittner 2026-03-01 01:24:00 -07:00
parent ec85621f9e
commit 681b17741f
4 changed files with 114 additions and 36 deletions

View File

@ -37,11 +37,12 @@
UART_ID = 0 # TX/RX: UART 0: 0/1, 12/13, or 16/17; UART 1: 4/5 or 8/9 UART_ID = 0 # TX/RX: UART 0: 0/1, 12/13, or 16/17; UART 1: 4/5 or 8/9
UART_TX_PIN=0 UART_TX_PIN=0
UART_RX_PIN=1 UART_RX_PIN=1
BUZZER_PWM_PIN = 11 # Pin for passive buzzer PWM
TRIGGER_BUTTON_PIN = 12 # Pin to read for scan trigger button, connect trigger button between this and ground TRIGGER_BUTTON_PIN = 12 # Pin to read for scan trigger button, connect trigger button between this and ground
TRIGGER_PIN = 13 # Pin that connects to the scan module's trigger line, pulls the line low while the user is pressing the trigger button TRIGGER_PIN = 13 # Pin that connects to the scan module's trigger line, pulls the line low while the user is pressing the trigger button
UP_BUTTON_PIN = 14 # Pin to read for navigation up button UP_BUTTON_PIN = 14 # Pin to read for navigation up button
DOWN_BUTTON_PIN = 15 # Pin to read for navigation down button DOWN_BUTTON_PIN = 15 # Pin to read for navigation down button
LED_PIN = "LED" # 3 in prod LED_PIN = 3 # "LED" for testing, 3 for prod
FIRMWARE_VERSION = "0.0.1" FIRMWARE_VERSION = "0.0.1"
# #
@ -49,7 +50,7 @@ FIRMWARE_VERSION = "0.0.1"
# #
SCAN_GAP_MS = 50 # Amount of time to wait for more characters from the scan engine before sending a barcode SCAN_GAP_MS = 50 # Amount of time to wait for more characters from the scan engine before sending a barcode
MAX_BARCODE_LENGTH = 8192 # Barcodes longer than this from the scan engine are assumed to be a glitch MAX_BARCODE_LENGTH = 8192 # Barcodes longer than this from the scan engine are assumed to be a glitch
TESTMODE = True # Sends a simulated barcode scan every 5 seconds TESTMODE = False # Sends a simulated barcode scan every 5 seconds
# #
# USB configuration # USB configuration

View File

@ -30,12 +30,77 @@
# WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
# THE POSSIBILITY OF SUCH DAMAGE. # THE POSSIBILITY OF SUCH DAMAGE.
from machine import Pin from machine import Pin, PWM
from time import sleep_us import machine
from time import sleep_us, sleep_ms
import config import config
from oledscreen import iconDisplay, centerText from oledscreen import iconDisplay, centerText
import _thread
onboardLED = Pin(config.LED_PIN, Pin.OUT) onboardLED = Pin(config.LED_PIN, Pin.OUT)
buzzerPin = PWM(Pin(config.BUZZER_PWM_PIN))
ledSequence = []
ledLock = _thread.allocate_lock()
# Run LED on the second core so it doesn't slow down the main process
def ledThreadFn():
global feedbackType, ledSequence
while True:
ledLock.acquire()
if not ledSequence:
ledLock.release()
sleep_ms(1)
continue
seq = ledSequence
ledSequence = []
ledLock.release()
for speed in seq:
pulseLED(speed)
ledThread = None
# Run in main.py during boot
def createLEDThread():
global ledThread
ledThread = _thread.start_new_thread(ledThreadFn, ())
def doFeedback(mode):
global ledSequence
if mode == "SCAN":
ledLock.acquire()
ledSequence = ["fast"]
ledLock.release()
passiveBuzzer(1047, 100)
elif mode == "OK":
ledLock.acquire()
ledSequence = ["fast"]
ledLock.release()
passiveBuzzer(1175, 100)
elif mode == "ERR":
ledLock.acquire()
ledSequence = ["fast", "fast", "fast"]
ledLock.release()
passiveBuzzer(440, 100)
sleep_ms(50)
passiveBuzzer(440, 100)
sleep_ms(50)
passiveBuzzer(440, 100)
elif mode == "POW":
ledLock.acquire()
ledSequence = ["normal"]
ledLock.release()
passiveBuzzer(880, 100)
passiveBuzzer(988, 100)
passiveBuzzer(1047, 100)
elif mode == "NAF":
ledLock.acquire()
ledSequence = ["normal", "fast", "fast", "normal"]
ledLock.release()
passiveBuzzer(440, 100)
passiveBuzzer(494, 100)
passiveBuzzer(440, 200)
# Pulse the LED on and off with brightness fade # Pulse the LED on and off with brightness fade
def pulseLED(speed): def pulseLED(speed):
@ -58,24 +123,17 @@ def pulseLED(speed):
onboardLED.off() onboardLED.off()
sleep_us(i) sleep_us(i)
def passiveBuzzer(frequency, duration):
global buzzerPin
buzzerPin.duty_u16(int(65536*0.2))
buzzerPin.freq(frequency)
sleep_ms(duration)
buzzerPin.duty_u16(int(0))
def firmwareUpdateMessage(): def firmwareUpdateMessage():
centerText("Firmware Update", False, True) centerText("Firmware Update", False, True)
def feedbackBuzzer(feedback): def feedbackBuzzer(feedback, onMain = False):
if feedback == "OK": if feedback == "POW":
iconDisplay("OK")
pulseLED("fast")
elif feedback == "ERR":
iconDisplay("ERR")
pulseLED("fast")
pulseLED("fast")
pulseLED("fast")
elif feedback == "POW":
iconDisplay("POW") iconDisplay("POW")
#pulseLED("normal") doFeedback(feedback)
elif feedback == "NAF":
iconDisplay("NAF")
pulseLED("normal")
pulseLED("fast")
pulseLED("fast")
pulseLED("normal")

View File

@ -31,7 +31,7 @@
# THE POSSIBILITY OF SUCH DAMAGE. # THE POSSIBILITY OF SUCH DAMAGE.
from sys import stdin, exit from sys import stdin, exit, print_exception
import machine import machine
from machine import Pin, USBDevice, UART from machine import Pin, USBDevice, UART
from utime import sleep, sleep_ms, sleep_us from utime import sleep, sleep_ms, sleep_us
@ -41,7 +41,7 @@ import time
from config import * from config import *
from oledscreen import bootDisplay, clearDisplay, brightDisplay, mainDisplay, centerText from oledscreen import bootDisplay, clearDisplay, brightDisplay, mainDisplay, centerText
from scannerusb import initUSBHID, createAndSendBarcodeReports from scannerusb import initUSBHID, createAndSendBarcodeReports
from feedback import feedbackBuzzer from feedback import feedbackBuzzer, createLEDThread
from scanmode import isScanInhibited, setModeID, getCurrentModeID, processNewListUSBReport from scanmode import isScanInhibited, setModeID, getCurrentModeID, processNewListUSBReport
from watchdog import startwatchdog, feedwatchdog from watchdog import startwatchdog, feedwatchdog
@ -92,13 +92,26 @@ menuUpButton.irq(handler=menuUpButtonHandler, trigger=Pin.IRQ_FALLING)
menuDownButton.irq(handler=menuDownButtonHandler, trigger=Pin.IRQ_FALLING) menuDownButton.irq(handler=menuDownButtonHandler, trigger=Pin.IRQ_FALLING)
# #
# Send scan engine configuration commands over UART
# #
# uart.write(b'\x7E\x00\x08\x01\x00\xD9\x50\xAB\xCD') # Restore factory defaults
# TODO: Send scan engine configuration commands over UART uart.write(b'\x7E\x00\x08\x01\x00\x00\xC4\xAB\xCD') # 11000100 (LED settings)
# uart.write(b'\x7E\x00\x08\x01\x00\x01\x90\xAB\xCD') # 10010000 (trigger settings)
# uart.write(b'\x7E\x00\x08\x01\x00\x03\x03\xAB\xCD') # 00000011 (setup barcode settings)
# uart.write(b'\x7E\x00\x08\x01\x00\x05\x05\xAB\xCD') # 500ms timeout between decodes of same barcode
uart.write(b'\x7E\x00\x08\x01\x00\x07\x00\xAB\xCD') # Disable deep sleep mode
uart.write(b'\x7E\x00\x08\x01\x00\x0D\x00\xAB\xCD') # Disable invoicing and virtual keyboard, set TTL232 output
uart.write(b'\x7E\x00\x08\x01\x00\x16\x01\xAB\xCD') # Try harder to decode bad barcodes
uart.write(b'\x7E\x00\x08\x01\x00\x17\x00\xAB\xCD') # Disable code128 prefix and GS replacement
uart.write(b'\x7E\x00\x08\x01\x00\x18\x1D\xAB\xCD') # Set GS replacement char to GS char just in case
uart.write(b'\x7E\x00\x08\x01\x00\x2C\x02\xAB\xCD') # Enable all symbologies
uart.write(b'\x7E\x00\x08\x01\x00\x33\x41\xAB\xCD') # Disable parentheses on Code128 AI, enable Code128
uart.write(b'\x7E\x00\x08\x01\x00\x3F\x61\xAB\xCD') # Disable parentheses on QR/DataMatrix AI, enable QR
uart.write(b'\x7E\x00\x08\x01\x00\xD9\x56\xAB\xCD') # Save as custom defaults
feedwatchdog()
createLEDThread()
feedwatchdog() feedwatchdog()
feedbackBuzzer("POW") feedbackBuzzer("POW")
feedwatchdog() feedwatchdog()
@ -155,7 +168,7 @@ while True:
uartBuffer.extend(data) uartBuffer.extend(data)
lastBufferActivity = time.ticks_ms() lastBufferActivity = time.ticks_ms()
if len(uartBuffer) > MAX_BARCODE_LENGTH: if len(uartBuffer) > MAX_BARCODE_LENGTH:
uartBuffer.clear() uartBuffer[:] = b'' # clear buffer
bufferOverflow = True bufferOverflow = True
lastBufferActivity = None lastBufferActivity = None
@ -163,8 +176,8 @@ while True:
if lastBufferActivity is not None and time.ticks_diff(time.ticks_ms(), lastBufferActivity) > SCAN_GAP_MS: if lastBufferActivity is not None and time.ticks_diff(time.ticks_ms(), lastBufferActivity) > SCAN_GAP_MS:
if not isScanInhibited() and uartBuffer and not bufferOverflow: if not isScanInhibited() and uartBuffer and not bufferOverflow:
createAndSendBarcodeReports(bytes(uartBuffer)) createAndSendBarcodeReports(bytes(uartBuffer))
feedbackBuzzer("OK") feedbackBuzzer("SCAN", True)
uartBuffer.clear() uartBuffer[:] = b'' # clear buffer
lastBufferActivity = None lastBufferActivity = None
bufferOverflow = False bufferOverflow = False
@ -172,7 +185,7 @@ while True:
if TESTMODE and time.ticks_diff(time.ticks_ms(), lastTestSend) > 5000: if TESTMODE and time.ticks_diff(time.ticks_ms(), lastTestSend) > 5000:
createAndSendBarcodeReports(b'test barcode 12345') createAndSendBarcodeReports(b'test barcode 12345')
feedbackBuzzer("OK") feedbackBuzzer("SCAN")
lastTestSend = time.ticks_ms() lastTestSend = time.ticks_ms()
feedwatchdog() feedwatchdog()
@ -185,5 +198,5 @@ while True:
machine.idle() machine.idle()
except Exception as e: except Exception as e:
# Dump exceptions over serial for debugging # Dump exceptions over serial for debugging
print(e) print_exception(e)
machine.reset() machine.reset()

View File

@ -39,6 +39,7 @@ from feedback import feedbackBuzzer, firmwareUpdateMessage
from watchdog import feedwatchdog from watchdog import feedwatchdog
import time import time
from sys import stdout from sys import stdout
from utime import sleep_ms
usbinterface = None usbinterface = None
@ -225,7 +226,7 @@ class USBHIDInterface(HIDInterface):
while self.busy(): while self.busy():
# Wait for queue to open up, but drop this report on timeout # Wait for queue to open up, but drop this report on timeout
# because the host isn't paying attention to us and this will deadlock if we wait forever # because the host isn't paying attention to us and this will deadlock if we wait forever
if time.ticks_diff(time.ticks_ms(), start) > 5: if time.ticks_diff(time.ticks_ms(), start) > 10:
return False return False
machine.idle() machine.idle()
self.send_report(data) self.send_report(data)
@ -250,12 +251,17 @@ def createAndSendBarcodeReports(barcodeData):
global usbinterface global usbinterface
chunks = split(barcodeData, 56) chunks = split(barcodeData, 56)
for i, chunk in enumerate(chunks): for i, chunk in enumerate(chunks):
isLastReport = len(chunks) - 1 == i
lastByte = b'\x01' lastByte = b'\x01'
if len(chunks) - 1 == i: if isLastReport:
lastByte = b'\x00' lastByte = b'\x00'
report = b'\x02' + bytes([len(chunk)]) + b'\x00\x00\x00' + pad_data(chunk, 56) + b'\x00' + bytes([getCurrentModeID()]) + lastByte report = b'\x02' + bytes([len(chunk)]) + b'\x00\x00\x00' + pad_data(chunk, 56) + b'\x00' + bytes([getCurrentModeID()]) + lastByte
if USBHID_ENABLED: if USBHID_ENABLED:
if not usbinterface.send_data(report): if usbinterface.send_data(report):
if not isLastReport:
sleep_ms(50) # Wait a few milliseconds before sending the next report so it won't get dropped
print(report)
else:
break # Stop sending barcode over USB, the host didn't get this chunk but it might get the next and only have half a barcode break # Stop sending barcode over USB, the host didn't get this chunk but it might get the next and only have half a barcode
feedwatchdog() feedwatchdog()
# Write barcode data to serial out for non-HID system compatibility # Write barcode data to serial out for non-HID system compatibility