add dymo400 lsusb

This commit is contained in:
wp
2025-08-09 14:48:52 -05:00
parent 90d30283ac
commit 310de6c2b7
2 changed files with 151 additions and 0 deletions

59
09220019.txt Normal file
View File

@@ -0,0 +1,59 @@
Bus 001 Device 013: ID 0922:0019 Dymo-CoStar Corp. LabelWriter 400
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 0 [unknown]
bDeviceSubClass 0 [unknown]
bDeviceProtocol 0
bMaxPacketSize0 16
idVendor 0x0922 Dymo-CoStar Corp.
idProduct 0x0019 LabelWriter 400
bcdDevice 0.4e
iManufacturer 1 DYMO
iProduct 2 DYMO LabelWriter 400
iSerial 3 05080914235500
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0020
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xc0
Self Powered
MaxPower 2mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 7 Printer
bInterfaceSubClass 1 Printer
bInterfaceProtocol 2 Bidirectional
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Device Status: 0x0001
Self Powered

92
src/dymo.py Normal file
View File

@@ -0,0 +1,92 @@
import usb.core
import usb.util
import sys
import re
dymo_vid = 0x0922 # Dymo vendor ID
dymo_tt_pid = 0x0018 # Dymo Twin Turbo Product ID
dymo_400_pid = 0x0019
dymo_450_pid = 0x0020 # Dymo 450 Product ID
dymo_tt = usb.core.find(idVendor=dymo_vid, idProduct=dymo_tt_pid)
dymo_400 = usb.core.find(idVendor=dymo_vid, idProduct=dymo_400_pid)
dymo_450 = usb.core.find(idVendor=dymo_vid, idProduct=dymo_450_pid)
#dymo_tt.serial_number # Prints device unique ID
#dymo_tt.langids # Returns language IDs (1033,) for english
# Get descriptor for serial number
# fields: dymo_tt - reference to device to get the data from
# 254 - max buffer for received data (254 max, 30 expected for serial number)
# 0x03 - Data type - 0x03 = string data
# dymo_tt.iSerialNumber - index of serial number data (0x03)
# dymo_tt.langids[0] - First item from supported languages (1033)
#usb.control.get_descriptor(dymo_tt, 254, 0x03, dymo_tt.iSerialNumber, dymo_tt.langids[0])
#usb.control.get_descriptor(dymo_450, 254, 0x03, dymo_450.iSerialNumber, dymo_450.langids[0])
dymo_tt_serialdata = usb.control.get_descriptor(dymo_tt, 30, 0x03, 0x03, 1033)
dymo_450_serialdata = usb.control.get_descriptor(dymo_450, 30, 0x03, 0x03, 1033)
#print(dymo_tt_serialdata.hex())
#print(dymo_450_serialdata.hex())
# returns the string representation of the serial number received from the device
#print(dymo_tt_serialdata[2:len(dymo_tt_serialdata)].decode('utf-16-le'))
#print(dymo_450_serialdata[2:30].decode('utf-16-le'))
# returns raw bytes representation of encoded data
#print(dymo_tt_serialdata[2:30].decode('utf-8'))
#print(dymo_450_serialdata[2:30].decode('utf-8'))
def get_serial_raw(dev):
return usb.control.get_descriptor(dev, 254, usb.DT_STRING, dev.iSerialNumber, dev.langids[0])
def get_device_id(dev):
# Get the IEEE 1284 Device ID string
# ref: https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/LegacyCollaterals/01233a.pdf
GET_DEVICE_ID = 0xa1 # USBPRINTER protocol bmRequestType printer protocol request
bRequest = 0x00 # USBPRINTER protocol bRequest get_device_id
GET_PORT_STATUS = 0x01 # USBPRINTER protocol bRequest get_port_status (returns 1 byte)
SOFT_RESET = 0x21 # USBPRINTER protocol bmRequestType soft reset
wValue = 0 # USBPRINTER protocol Config Index
wIndex = 0 # USBPRINTER protocol interface index and alt setting
wLength = 1023 # Max buffer length
# ctrl_transfer(bmRequestType, bRequest, wValue, wIndex, msg or buffsize)
return dev.ctrl_transfer(GET_DEVICE_ID, bRequest, wValue, wIndex, wLength)
def get_serial(dev):
rawserial = get_serial_raw(dev)
# Return just the data portion of the descriptor data
# First byte is length of returned data, second byte is type of returned data (30 and 3 expected)
rawserial = rawserial[2:len(rawserial)].tobytes()
if dev.idVendor == 0x0922 and dev.idProduct == 0x0018:
# Because the Twin Turbo returns invalid serial data, we drop the first 2 bytes
# and decode the remainder as utf-16-be (big-endian)
return rawserial[2:len(rawserial)].decode('utf-16-be')
else:
return rawserial.decode('utf-16-le')
def fix_serial(uri_line):
if not uri_line.startswith("direct usb://DYMO/LabelWriter%20Twin%20Turbo?serial="):
return uri_line
# Extract existing serial
match = re.search(r'serial=([^\s]+)', uri_line)
if not match:
return uri_line
serial = match.group(1)
# If the serial is all question marks, replace it
if set(serial) == {'?'}:
# Generate fallback serial using USB bus/device number from URI line
# CUPS output looks like:
# direct usb://DYMO/... "DYMO LabelWriter Twin Turbo" usb://...
# We'll add a stable dummy fallback here
#dummy_serial = "DYMOFIX-" + str(abs(hash(uri_line)) % 10000)
new_serial = get_serial()
uri_line = uri_line.replace(f"serial={serial}", f"serial={dummy_serial}")
return uri_line
#for line in sys.stdin:
# sys.stdout.write(fix_serial(line))