V
V
Vladislav Shepilov2015-04-25 04:07:41
linux
Vladislav Shepilov, 2015-04-25 04:07:41

How to read data from USPS Scale(PS-10USB)?

I have such scales PS-10USB , under Windows a program was found on the page , I don’t use windows, but I checked its performance. Under Debian, I took a Python script found on the net:

#!/usr/bin/env python

"""
ID 04d9:8010 Holtek Semiconductor, Inc.
"""
import usb.core
import usb.util as util
from array import array
import sys
from optparse import OptionParser, make_option
import pickle
from struct import unpack

dev = None

VID = 0x04d9
PID = 0x8010

# define HID constants

REQ_HID_GET_REPORT = 0x01
REQ_HID_GET_IDLE = 0x02
REQ_HID_GET_PROTOCOL = 0x03

REQ_HID_SET_REPORT = 0x09
REQ_HID_SET_IDLE = 0x0A
REQ_HID_SET_PROTOCOL = 0x0B

HID_REPORT_TYPE_INPUT = 1 << 8
HID_REPORT_TYPE_OUTPUT = 2 << 8
HID_REPORT_TYPE_FEATURE = 3 << 8


def openDev():
    global dev
    dev = usb.core.find(idVendor=VID, idProduct=PID)
    if dev is None:
        raise ValueError('Device not found')

    if dev.is_kernel_driver_active(0):
        dev.detach_kernel_driver(0)
    # do reset and set active conf. Must be done before claim.
    dev.set_configuration()
    util.claim_interface(dev, None)


def setReport(reportId, data):
    r = dev.ctrl_transfer(
        util.build_request_type(
            util.CTRL_OUT, util.CTRL_TYPE_CLASS, util.CTRL_RECIPIENT_INTERFACE),  # bmRequestType,
        REQ_HID_SET_REPORT,
        HID_REPORT_TYPE_OUTPUT | reportId,
        0,                 # feature_interface_num
        data,              # data
        3000               # timeout (1000 was too small for C_FREE)
    )
    print >> (HID_REPORT_TYPE_OUTPUT)
    return r


def read():
    openDev()
    try:
        dev.read(0x81, 64)  # flush
    except usb.core.USBError:
        pass

    setReport(9, array('B', (0x10, 0, 0, 0, 0, 0, 0, 0)))

    # Every user can have upto 12 variables
    # and additional 8*64 for user data
    r = []
    for i in xrange(120 + 8):
        x = dev.read(0x81, 64)
        if not x:
            print >> sys.stderr, "Read failed"
            exit(1)
        if x[0] == 0xff and (i < 120):
            print >> sys.stderr, "Invalid data", x
            exit(1)
        r.append(x)

    # Each variable can have upto 32 values
    frmt = "!" + "H" * 32
    s = []
    for i in xrange(120):
        x = unpack(frmt, r[i])

        # Variables 5 .. 10 are not available on my scale
        if i > 5 and i < 10:
            err = [item for item in x if item != 0]
        else:
            err = [item for item in x if item == 0xffff]
        if len(err):
            print >> sys.stderr, "INVALID:", err
            exit(1)

        s.append(x)
    return s


def printUser(s, user):
    # Transpose from 12x32 to 32x12 and format

    j = 12 * user
    for i in xrange(32):
        x = s[j + 5][i]  # date
        if not x:
            break
        print "{:d}-{:02d}-{:02d}T07:00:00 {:.1f} {:.1f} {:.1f} {:.1f} {:.1f} {:d} {:d}".format(
            1920 + (x >> 9), x >> 5 & 0xf, x & 0x1f,
            s[j + 0][i] / 10., s[j + 1][i] / 10., s[j + 2][i] / 10., s[j + 3][i] / 10., s[j + 4][i] / 10., s[j + 10][i], s[j + 11][i])


def main():

    option_list = [
        make_option("-c", "--cached", action="store_true", dest="cached"),
        #make_option("-w", "--write",action="store",      dest="output_file"),
        make_option('-u', '--user', action='store',      dest='user'),
    ]

    parser = OptionParser(
        option_list=option_list, usage='Usage: %prog [options]')
    options, args = parser.parse_args()

    if options.cached:
        with open("dump.pickle") as f:
            s = pickle.load(f)
    else:
        s = read()
        with open("dump.pickle", "w") as f:
            pickle.dump(s, f)

    user = 0
    if options.user:
        user = int(options.user) - 1

    printUser(s, user)


if __name__ == '__main__':
    main()

But when I run it, I get this:
Traceback (most recent call last):
  File "test.py", line 145, in <module>
    main()
  File "test.py", line 133, in main
    s = read()
  File "test.py", line 70, in read
    setReport(9, array('B', (0x10, 0, 0, 0, 0, 0, 0, 0)))
  File "test.py", line 57, in setReport
    3000               # timeout (1000 was too small for C_FREE)
  File "/usr/local/lib/python2.7/dist-packages/usb/core.py", line 971, in ctrl_transfer
    self.__get_timeout(timeout))
  File "/usr/local/lib/python2.7/dist-packages/usb/backend/libusb1.py", line 819, in ctrl_transfer
    timeout))
  File "/usr/local/lib/python2.7/dist-packages/usb/backend/libusb1.py", line 552, in _check
    raise USBError(_strerror(ret), ret, _libusb_errno[ret])
usb.core.USBError: [Errno 32] Pipe error

I tried all versions of pyusb (1.0.0a2, 1.0.0a3, 1.0.0b1, 1.0.0b2) that are in pip, installed the latest one with git - zero effect, also tried different backends.
lsusb -v -d 04d9:8010
Bus 001 Device 010: ID 04d9:8010 Holtek Semiconductor, Inc. 
Couldn't open device, some information will be missing
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x04d9 Holtek Semiconductor, Inc.
  idProduct          0x8010 
  bcdDevice            1.00
  iManufacturer           1 
  iProduct                2 
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           34
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.10
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      53
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval

dmesg
[ 8202.703242] usb 1-1.2: new low-speed USB device number 10 using ehci-pci
[ 8202.813391] usb 1-1.2: New USB device found, idVendor=04d9, idProduct=8010
[ 8202.813397] usb 1-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 8202.813400] usb 1-1.2: Product: USB-HID demo code
[ 8202.813403] usb 1-1.2: Manufacturer: Holtek
[ 8202.830331] hid-generic 0003:04D9:8010.0009: hiddev0,hidraw2: USB HID v1.10 Device [Holtek USB-HID demo code] on usb-0000:00:1a.0-1.2/input0

dpkg -l | grep usb
ii  libgusb2:amd64                                              0.1.6-5                             amd64        GLib wrapper around libusb1
ii  libusb-0.1-4:amd64                                          2:0.1.12-25                         amd64        userspace USB programming library
ii  libusb-1.0-0:amd64                                          2:1.0.19-1                          amd64        userspace USB programming library
ii  libusb-1.0-0-dev:amd64                                      2:1.0.19-1                          amd64        userspace USB programming library development files
ii  libusb-1.0-doc                                              2:1.0.19-1                          all          documentation for userspace USB programming
ii  libusbmuxd2:amd64                                           1.0.9-1                             amd64        USB multiplexor daemon for iPhone and iPod Touch devices - library
ii  libusbredirparser1:amd64                                    0.7-1                               amd64        Parser for the usbredir protocol (runtime)
ii  usb-modeswitch                                              2.2.0+repack0-2                     amd64        mode switching tool for controlling "flip flop" USB devices
ii  usb-modeswitch-data                                         20150115-1                          all          mode switching data for usb-modeswitch
ii  usbutils                                                    1:007-2                             amd64        Linux USB utilities
ii  xserver-xorg-video-sisusb                                   1:0.9.6-2+b2                        amd64        X.Org X server -- SiS USB display driver

pip freeze | grep usb
libusb1==1.3.0
pyusb==1.0.0b2

/etc/hidraw2and /etc/usb/hiddev0always empty, nothing is written in them.
Help to read at least some data from these scales.
usbscale also tried - hangs for a long time and returns
Error in USB transfer

Answer the question

In order to leave comments, you need to log in

2 answer(s)
C
coolynx, 2016-05-05
@kripton3000

I also use this script on CentOS and Raspbian on RaspberryPi. Different devices have different problems.
But it seems that the problem here is that there is no access to the data:

Couldn't open device, some information will be missing
...
Report Descriptors:
** UNAVAILABLE **
Here is what I havelsusb -v -d 04d9:8010
idVendor 0x04d9 Holtek Semiconductor, Inc.
idProduct 0x8010
bcdDevice 1.00
iManufacturer 0
iProduct 2 Scale
...
Report Descriptor: (length is 53)
Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
(null)
Item(Local ): Usage, data= [ 0x01 ] 1
(null)
Item(Main ): Collection, data= [ 0x01 ] 1
Application
On Python 2.7.x you need to change.
on the
Unfortunately, it won't work on a Mac.

M
monah_tuk, 2015-04-25
@monah_tuk

And what about C++? In general, libusb likes to return PIPE ERROR when a device Stalls a request, indicating an error processing the request or that the request is not supported. This is indirectly confirmed by this:

Report Descriptors: 
           ** UNAVAILABLE **

and at the same time setReport is done
Further, judging by the descriptors, this is a normal HID device. Try to reach him with: www.signal11.us/oss/hidapi/:
stupid question, but did you add your VID:PID here:
https://github.com/erjiang/usbscale/blob/master/sc...
?
Also, here: https://github.com/erjiang/usbscale/blob/master/us... at this location:
// 
        // If the data transfer succeeded, then we pass along the data we
        // received tot **print_scale_data**.
        //
        if(r == 0) {

they check the error code for 0, which is correct, but it is not clear what kind of error the request ends with. Judging by what you say ("hangs for a long time"), they use a large timeout there (10 seconds), the error code is LIBUSB_ERROR_TIMEOUT, and the documentation says:
Also check transferred when dealing with a timeout error code. libusb may have to split your transfer into a number of chunks to satisfy the underlying O/S requirements, meaning that the timeout may expire after the first few chunks have completed. libusb is careful not to lose any data that may have been transferred; do not assume that timeout conditions indicate a complete lack of I/O.
they expect a block of size WEIGH_REPORT_SIZE (6 bytes), what if it happens that your scales have a smaller size? 5 bytes? Those. it is necessary, for starters, to correct the program and log the error code and the value of the len variable. If this is really a timeout, and not PIPE ERROR, then check the value of len at the output, if it is greater than zero, try to process this data. Only processing, most likely, should be different.
The main difference from the Python program is that setReport is not given. As a consequence, you can try commenting out this line in your Python script as a quick test.
The final chord could be the reversal of communication between the scales and the Windows program using Wireshark :-)
If you can’t do it yourself, you can place an order for me, if you are interested - write to the mail (in the profile).

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question