From charlesreid1

Subpage of USB Scale.

Don't use these instructions. They'll just cause you a headache in the end.

OS X

The setup process for interfacing with the USB scale involves installing a couple of libraries to communicate with the scale. The first was libusb, which is a C library. The second is PyUSB, a python library that uses libusb.

Libusb for OS X

I am on Mac OS X Mavericks, using a Python.org python install.

I originally tried to install libusb using Homebrew. However, when I would build PyUSB, and test it, I would get segmentation faults. When I read the full error message of the system's segmentation message, I saw the segmentation fault was coming from libusb.

Here is a python two-liner that will test out pyusb (and therefore libusb):

import usb
print usb.busses()

I kept digging, not finding much information outside of people who had installed libusb on Ubuntu or on Windows. But eventually, I found this wiki for Pinguino, which linked to a binary version of libusb for Mac OS X: http://wiki.pinguino.cc/index.php/Mac_OS_X#libusb

Once I used the binary version of libusb, everything worked like a charm.

Before:

LibusbBefore.png

After:

LibusbAfter.png

Plug It In and Turn It On

Now you can turn on your scale, plug it into your computer, and away you go.

I'm relying pretty heavily on https://github.com/sparkfun/usb-scale and http://steventsnyder.com/reading-a-dymo-usb-scale-using-python/ for the code and information.

Printing Device Information

We can start by reading the device information, searching for it by vendor and product ID (which are known, based on the scale brand: Dymo M25 25 lb USB Postal Scale).

This script will search through USB devices and find the Dymo scale, if it exists:

import usb.core
import usb.util

VENDOR_ID = 0x0922
PRODUCT_ID = 0x8004

device = usb.core.find(idVendor=VENDOR_ID,
                       idProduct=PRODUCT_ID)
print device

Which should result in:

USBDevice.png

Printing Device Reading: No Exclusive Access

To start reading data from the scale, I modified the scale script to request data. I used the readscript.cgi script from the usb-scale github repo, modified to run for Mac (and be a regular .py script):

import time
import usb.core
import usb.util

VENDOR_ID = 0x0922
PRODUCT_ID = 0x8004
DATA_MODE_GRAMS = 2
DATA_MODE_OUNCES = 11

# find the USB device
device = usb.core.find(idVendor=VENDOR_ID,
                       idProduct=PRODUCT_ID)

# use the first/default configuration
device.set_configuration()
# first endpoint
endpoint = device[0][(0,0)][0]


# for some damn reason this thing holds onto its old
# value for at least 1 or 2 packets after changing
# so burn a few before you take one
preload = 3
while preload > 0:
    device.read(endpoint.bEndpointAddress,
                endpoint.wMaxPacketSize)
    preload -= 1


# read a data packet
attempts = 10
data = None
while data is None and attempts > 0:
    try:
        data = device.read(endpoint.bEndpointAddress,
                           endpoint.wMaxPacketSize)
    except usb.core.USBError as e:
        data = None
        if e.args == ('Operation timed out',):
            attempts -= 10
            continue

raw_weight = data[4] + data[5] * 256

if data[2] == DATA_MODE_OUNCES:
    ounces = raw_weight * 0.1
    weight = ounces
elif data[2] == DATA_MODE_GRAMS:
    grams = raw_weight
    weight = grams * .035274

pounds, ounces = divmod(weight, 16)

# in a word, jsonp
print('here_is_the_weight({pounds:'+str(pounds)+',ounces:'+str(round(ounces, 2))+'})')

When I ran this, I saw an error message about the device not being opened for exclusive access:

charles @ cronus - 10
(Tue Feb 03 17:59:20) ~/pkg/usb-scale $ python scale.py
Traceback (most recent call last):
  File "scale.py", line 13, in <module>
    device.set_configuration()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/usb/core.py", line 819, in set_configuration
    self._ctx.managed_set_configuration(self, configuration)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/usb/core.py", line 129, in managed_set_configuration
    self.backend.set_configuration(self.handle, cfg.bConfigurationValue)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/usb/backend/libusb0.py", line 442, in set_configuration
    _check(_lib.usb_set_configuration(dev_handle, config_value))
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/usb/backend/libusb0.py", line 383, in _check
    raise USBError(errmsg, ret)
usb.core.USBError: [Errno None] usb_set_configuration(SetConfiguration): device not opened for exclusive access

I also saw this error message:

usb_claim_interface: couldn't claim interface

This post on the libusb trac wiki was pretty discouraging: http://www.libusb.org/ticket/89

But then I learned from the libusb FAQ that you can "install a codeless kext kernel driver and then reboot, before you can communicate with the device." http://libusb.org/wiki/FAQ#CanIcreateadriverlessdeviceusingHIDclass

Kext Kernel on Mac OS X

I wasn't sure what a codeless kext kernel driver was. Turns out, when you plug in hardware, there is something that runs from the kernel that automatically claims the hardware and assigns it a code.

The codeless kext kernel driver also runs from the kernel, but takes precedence over the normal code-assigning routine. It claims the hardware, but does not assign a code, leaving it available for libusb and pyusb to use.

From developer.apple.com:

The second group of applications that are affected by the presence of the AppleUSBFTDI kext, are those applications that implement user client drivers to communicate directly with the device from user space. Such applications will fail to open a connection with the hardware, because IOKit will already have matched the AppleUSBFTDI driver to the device. The application will see the exclusive access error 0xE00002C5 when attempting to open a connection with the device.

The recommended long term solution is to modify the application to open the BSD layer serial port for communication with the FTDI hardware. A short term solution is to implement a codeless kext, that will have a higher match priority than the AppleUSBFTDI kext to prevent IOKit from matching the AppleUSBFTDI kernel level driver to the hardware. An important ramification of the codeless kext solution is that an Installer process will be required to install the codeless kext. Under OS X Mavericks, the codeless kext must be signed.

Enclosed is a sample codeless kext project. The project includes a readme file describing the steps to modify that sample to match to your device. There are also instructions for installing the codeless kext to the /System/Library/Extensions/ folder for test purposes only. Under OS X Mavericks, the official location for third party Extension files, is in /Library/Extensions/. OS X Mavericks requires that the kext be signed using a special Developer ID. See the readme file for instructions on requesting this special Developer ID

https://developer.apple.com/library/mac/technotes/tn2315/_index.html

The page design is really awful, though, because the example file is downloaded by clicking this hidden-away little button at the top right. It makes no sense to put the button to download the example there.

Installing Kext Kernel Driver

Next steps, basically, were to download their sample kext kernel driver, modify it, load it in the kernel, and try and make this happen.

I downloaded their sample project from this link: https://developer.apple.com/library/mac/technotes/tn2315/tn2315_SampleUSBFTDICodelessKext.zip

When I opened the project in XCode, there were a number of different files, and as expected, there was a .plist file containing information about the hardware's product and vendor ID.

This was in the Sample USB Codeless Kext project's supporting files, in the .plist file, in the IOKitPersonalities dictionary:

500px

The product and vendor IDs are:

VENDOR_ID = 0x0922
PRODUCT_ID = 0x8003

The dictionary's id_vendor and id_product fields were updated.

Continuing along in the readme, I find out I need to ask Apple for a Developer Key to sign and use this codeless kext.

What a bunch of typical Apple bullshit.

Giving Up on OS X

Thanks to Apple's runaround bullshit and their "genius" ideas about changing hardware, I'm dead in the water getting this scale interfacing with my Mac OS X computer.

Thanks for nothing, Apple.