mirror of
https://github.com/erjiang/usbscale.git
synced 2025-06-28 00:50:59 -06:00
Try using every scale found
This commit is contained in:
parent
1d3a7f5ea5
commit
a26fd9eb55
2
Makefile
2
Makefile
@ -1,5 +1,5 @@
|
|||||||
LDLIBS=-lm -lusb-1.0
|
LDLIBS=-lm -lusb-1.0
|
||||||
CFLAGS=-Os -Wall
|
CFLAGS=-Os -Wall -Wextra
|
||||||
DOCCO=docco
|
DOCCO=docco
|
||||||
|
|
||||||
usbscale: usbscale.c scales.h
|
usbscale: usbscale.c scales.h
|
||||||
|
362
usbscale.c
362
usbscale.c
@ -25,6 +25,8 @@ GNU General Public License for more details.
|
|||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -54,10 +56,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#define CONTROL_REPORT_SIZE 2
|
#define CONTROL_REPORT_SIZE 2
|
||||||
|
|
||||||
//
|
//
|
||||||
// **find_scale** takes a libusb device list and finds the first USB device
|
// **is_scale** takes a libusb device list and finds the first USB device
|
||||||
// that matches a device listed in scales.h.
|
// that matches a device listed in scales.h.
|
||||||
//
|
//
|
||||||
static libusb_device* find_scale(libusb_device**);
|
static bool is_scale(libusb_device*);
|
||||||
//
|
//
|
||||||
// **print_scale_data** takes the 6-byte output from the scale and interprets
|
// **print_scale_data** takes the 6-byte output from the scale and interprets
|
||||||
// it, printing out the result to the screen. It also returns a 1 if the
|
// it, printing out the result to the screen. It also returns a 1 if the
|
||||||
@ -103,6 +105,7 @@ int main(int argc, char **argv)
|
|||||||
ssize_t cnt;
|
ssize_t cnt;
|
||||||
libusb_device* dev;
|
libusb_device* dev;
|
||||||
libusb_device_handle* handle;
|
libusb_device_handle* handle;
|
||||||
|
bool found_scale = false;
|
||||||
|
|
||||||
int weigh_count = WEIGH_COUNT -1;
|
int weigh_count = WEIGH_COUNT -1;
|
||||||
|
|
||||||
@ -127,154 +130,167 @@ int main(int argc, char **argv)
|
|||||||
return (int) cnt;
|
return (int) cnt;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Once we have the list, we use **find_scale** to loop through and match
|
// Once we have the list, we use **is_scale** to loop through and match
|
||||||
// every device against the scales.h list. **find_scale** will return the
|
// every device against the scales.h list. **is_scale** will return the
|
||||||
// first device that matches, or 0 if none of them matched.
|
// first device that matches, or 0 if none of them matched.
|
||||||
//
|
//
|
||||||
dev = find_scale(devs);
|
|
||||||
if(dev == 0) {
|
|
||||||
fprintf(stderr, "No USB scale found on this computer.\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
int i = 0;
|
||||||
// Once we have a pointer to the USB scale in question, we open it.
|
while ((dev = devs[i++]) != NULL) {
|
||||||
//
|
if (!is_scale(dev)) {
|
||||||
r = libusb_open(dev, &handle);
|
continue;
|
||||||
//
|
|
||||||
// Note that this requires that we have permission to access this device.
|
|
||||||
// If you get the "permission denied" error, check your udev rules.
|
|
||||||
//
|
|
||||||
if(r < 0) {
|
|
||||||
if(r == LIBUSB_ERROR_ACCESS) {
|
|
||||||
fprintf(stderr, "Permission denied to scale.\n");
|
|
||||||
}
|
}
|
||||||
else if(r == LIBUSB_ERROR_NO_DEVICE) {
|
found_scale = true;
|
||||||
fprintf(stderr, "Scale has been disconnected.\n");
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// On Linux, we typically need to detach the kernel driver so that we can
|
|
||||||
// handle this USB device. We are a userspace tool, after all.
|
|
||||||
//
|
|
||||||
#ifdef __linux__
|
|
||||||
libusb_detach_kernel_driver(handle, 0);
|
|
||||||
#endif
|
|
||||||
//
|
|
||||||
// Finally, we can claim the interface to this device and begin I/O.
|
|
||||||
//
|
|
||||||
libusb_claim_interface(handle, 0);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to transfer data about status
|
|
||||||
*
|
|
||||||
* http://rowsandcolumns.blogspot.com/2011/02/read-from-magtek-card-swipe-reader-in.html
|
|
||||||
*/
|
|
||||||
unsigned char data[WEIGH_REPORT_SIZE];
|
|
||||||
int len;
|
|
||||||
len = 0;
|
|
||||||
int scale_result = -1;
|
|
||||||
|
|
||||||
// lowest bit is Enforced Zero Return, second bit is Zero Scale
|
|
||||||
unsigned char tare_report[] = {0x02, 0x02};
|
|
||||||
|
|
||||||
if (argc > 1 && strncmp(argv[1], "zero", 5) == 0) {
|
|
||||||
r = libusb_interrupt_transfer(
|
|
||||||
handle,
|
|
||||||
LIBUSB_ENDPOINT_OUT + 2, // direction=host to device, type=standard, recipient=device
|
|
||||||
tare_report,
|
|
||||||
CONTROL_REPORT_SIZE,
|
|
||||||
&len,
|
|
||||||
10000
|
|
||||||
);
|
|
||||||
|
|
||||||
if (r != 0) {
|
|
||||||
fprintf(stderr, "errno=%s r=%d (%s) transferred %d bytes\n", strerror(errno), r, libusb_error_name(r), len);
|
|
||||||
} else {
|
|
||||||
fprintf(stderr, "tared\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// For some reason, we get old data the first time, so let's just get that
|
|
||||||
// out of the way now. It can't hurt to grab another packet from the scale.
|
|
||||||
//
|
|
||||||
r = libusb_interrupt_transfer(
|
|
||||||
handle,
|
|
||||||
//bmRequestType => direction: in, type: class,
|
|
||||||
// recipient: interface
|
|
||||||
LIBUSB_ENDPOINT_IN + 1,
|
|
||||||
data,
|
|
||||||
WEIGH_REPORT_SIZE, // length of data
|
|
||||||
&len,
|
|
||||||
10000 //timeout => 10 sec
|
|
||||||
);
|
|
||||||
//
|
|
||||||
// We read data from the scale in an infinite loop, stopping when
|
|
||||||
// **print_scale_data** tells us that it's successfully gotten the weight
|
|
||||||
// from the scale, or if the scale or transmissions indicates an error.
|
|
||||||
//
|
|
||||||
for(;;) {
|
|
||||||
//
|
//
|
||||||
// A `libusb_interrupt_transfer` of 6 bytes from the scale is the
|
// Once we have a pointer to the USB scale in question, we open it.
|
||||||
// typical scale data packet, and the usage is laid out in *HID Point
|
//
|
||||||
// of Sale Usage Tables*, version 1.02.
|
r = libusb_open(dev, &handle);
|
||||||
|
//
|
||||||
|
// Note that this requires that we have permission to access this device.
|
||||||
|
// If you get the "permission denied" error, check your udev rules.
|
||||||
|
//
|
||||||
|
if(r < 0) {
|
||||||
|
if(r == LIBUSB_ERROR_ACCESS) {
|
||||||
|
fprintf(stderr, "Permission denied to scale.\n");
|
||||||
|
}
|
||||||
|
else if(r == LIBUSB_ERROR_NO_DEVICE) {
|
||||||
|
fprintf(stderr, "Scale has been disconnected.\n");
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// On Linux, we typically need to detach the kernel driver so that we can
|
||||||
|
// handle this USB device. We are a userspace tool, after all.
|
||||||
|
//
|
||||||
|
#ifdef __linux__
|
||||||
|
libusb_detach_kernel_driver(handle, 0);
|
||||||
|
#endif
|
||||||
|
//
|
||||||
|
// Finally, we can claim the interface to this device and begin I/O.
|
||||||
|
//
|
||||||
|
libusb_claim_interface(handle, 0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to transfer data about status
|
||||||
|
*
|
||||||
|
* http://rowsandcolumns.blogspot.com/2011/02/read-from-magtek-card-swipe-reader-in.html
|
||||||
|
*/
|
||||||
|
unsigned char data[WEIGH_REPORT_SIZE];
|
||||||
|
int len;
|
||||||
|
len = 0;
|
||||||
|
int scale_result = -1;
|
||||||
|
|
||||||
|
// lowest bit is Enforced Zero Return, second bit is Zero Scale
|
||||||
|
unsigned char tare_report[] = {0x02, 0x02};
|
||||||
|
|
||||||
|
if (argc > 1 && strncmp(argv[1], "zero", 5) == 0) {
|
||||||
|
r = libusb_interrupt_transfer(
|
||||||
|
handle,
|
||||||
|
LIBUSB_ENDPOINT_OUT + 2, // direction=host to device, type=standard, recipient=device
|
||||||
|
tare_report,
|
||||||
|
CONTROL_REPORT_SIZE,
|
||||||
|
&len,
|
||||||
|
10000
|
||||||
|
);
|
||||||
|
|
||||||
|
if (r != 0) {
|
||||||
|
fprintf(stderr, "errno=%s r=%d (%s) transferred %d bytes\n", strerror(errno), r, libusb_error_name(r), len);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "tared\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// For some reason, we get old data the first time, so let's just get that
|
||||||
|
// out of the way now. It can't hurt to grab another packet from the scale.
|
||||||
//
|
//
|
||||||
r = libusb_interrupt_transfer(
|
r = libusb_interrupt_transfer(
|
||||||
handle,
|
handle,
|
||||||
//bmRequestType => direction: in, type: class,
|
//bmRequestType => direction: in, type: class,
|
||||||
// recipient: interface
|
// recipient: interface
|
||||||
get_first_endpoint_address(dev),
|
LIBUSB_ENDPOINT_IN + 1,
|
||||||
data,
|
data,
|
||||||
WEIGH_REPORT_SIZE, // length of data
|
WEIGH_REPORT_SIZE, // length of data
|
||||||
&len,
|
&len,
|
||||||
10000 //timeout => 10 sec
|
10000 //timeout => 10 sec
|
||||||
);
|
);
|
||||||
//
|
//
|
||||||
// If the data transfer succeeded, then we pass along the data we
|
// We read data from the scale in an infinite loop, stopping when
|
||||||
// received to **print_scale_data**.
|
// **print_scale_data** tells us that it's successfully gotten the weight
|
||||||
|
// from the scale, or if the scale or transmissions indicates an error.
|
||||||
//
|
//
|
||||||
if(r == 0) {
|
for(;;) {
|
||||||
#ifdef DEBUG
|
//
|
||||||
int i;
|
// A `libusb_interrupt_transfer` of 6 bytes from the scale is the
|
||||||
for(i = 0; i < WEIGH_REPORT_SIZE; i++) {
|
// typical scale data packet, and the usage is laid out in *HID Point
|
||||||
printf("%x\n", data[i]);
|
// of Sale Usage Tables*, version 1.02.
|
||||||
|
//
|
||||||
|
r = libusb_interrupt_transfer(
|
||||||
|
handle,
|
||||||
|
//bmRequestType => direction: in, type: class,
|
||||||
|
// recipient: interface
|
||||||
|
get_first_endpoint_address(dev),
|
||||||
|
data,
|
||||||
|
WEIGH_REPORT_SIZE, // length of data
|
||||||
|
&len,
|
||||||
|
10000 //timeout => 10 sec
|
||||||
|
);
|
||||||
|
//
|
||||||
|
// If the data transfer succeeded, then we pass along the data we
|
||||||
|
// received to **print_scale_data**.
|
||||||
|
//
|
||||||
|
if(r == 0) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < WEIGH_REPORT_SIZE; i++) {
|
||||||
|
printf("%x\n", data[i]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (weigh_count < 1) {
|
||||||
|
scale_result = print_scale_data(data);
|
||||||
|
if(scale_result != 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
weigh_count--;
|
||||||
}
|
}
|
||||||
#endif
|
else {
|
||||||
if (weigh_count < 1) {
|
fprintf(stderr, "Error in USB transfer\n");
|
||||||
scale_result = print_scale_data(data);
|
scale_result = -1;
|
||||||
if(scale_result != 1)
|
break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
weigh_count--;
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
fprintf(stderr, "Error in USB transfer\n");
|
//
|
||||||
scale_result = -1;
|
// At the end, we make sure that we reattach the kernel driver that we
|
||||||
break;
|
// detached earlier, close the handle to the device, free the device list
|
||||||
|
// that we retrieved, and exit libusb.
|
||||||
|
//
|
||||||
|
#ifdef __linux__
|
||||||
|
libusb_attach_kernel_driver(handle, 0);
|
||||||
|
#endif
|
||||||
|
libusb_close(handle);
|
||||||
|
libusb_free_device_list(devs, 1);
|
||||||
|
libusb_exit(NULL);
|
||||||
|
|
||||||
|
//
|
||||||
|
// The return code will be 0 for success or -1 for errors (see
|
||||||
|
// `libusb_init` above if it's neither 0 nor -1).
|
||||||
|
//
|
||||||
|
if (scale_result != 0) {
|
||||||
|
return scale_result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// At the end, we make sure that we reattach the kernel driver that we
|
// if no scales were found, make sure to show a message
|
||||||
// detached earlier, close the handle to the device, free the device list
|
|
||||||
// that we retrieved, and exit libusb.
|
|
||||||
//
|
//
|
||||||
#ifdef __linux__
|
if(!found_scale) {
|
||||||
libusb_attach_kernel_driver(handle, 0);
|
fprintf(stderr, "No USB scale found on this computer.\n");
|
||||||
#endif
|
return -1;
|
||||||
libusb_close(handle);
|
}
|
||||||
libusb_free_device_list(devs, 1);
|
return 0;
|
||||||
libusb_exit(NULL);
|
|
||||||
|
|
||||||
//
|
|
||||||
// The return code will be 0 for success or -1 for errors (see
|
|
||||||
// `libusb_init` above if it's neither 0 nor -1).
|
|
||||||
//
|
|
||||||
return scale_result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -372,75 +388,65 @@ static int print_scale_data(unsigned char* dat) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// find_scale
|
// is_scale
|
||||||
// ----------
|
// ----------
|
||||||
//
|
//
|
||||||
// **find_scale** takes a `libusb_device\*\*` list and loop through it,
|
// **is_scale** takes a `libusb_device\*\*` list and loop through it,
|
||||||
// matching each device's vendor and product IDs to the scales.h list. It
|
// matching each device's vendor and product IDs to the scales.h list. It
|
||||||
// return the first matching `libusb_device\*` or 0 if no matching device is
|
// return the first matching `libusb_device\*` or 0 if no matching device is
|
||||||
// found.
|
// found.
|
||||||
//
|
//
|
||||||
static libusb_device* find_scale(libusb_device **devs)
|
static bool is_scale(libusb_device *dev)
|
||||||
{
|
{
|
||||||
|
|
||||||
int i = 0;
|
struct libusb_device_descriptor desc;
|
||||||
libusb_device* dev = 0;
|
int r = libusb_get_device_descriptor(dev, &desc);
|
||||||
|
if (r < 0) {
|
||||||
//
|
fprintf(stderr, "failed to get device descriptor");
|
||||||
// Loop through each USB device, and for each device, loop through the
|
return NULL;
|
||||||
// scales list to see if it's one of our listed scales.
|
}
|
||||||
//
|
int i;
|
||||||
while ((dev = devs[i++]) != NULL) {
|
for (i = 0; i < NSCALES; i++) {
|
||||||
struct libusb_device_descriptor desc;
|
if(desc.idVendor == scales[i][0] &&
|
||||||
int r = libusb_get_device_descriptor(dev, &desc);
|
desc.idProduct == scales[i][1]) {
|
||||||
if (r < 0) {
|
/*
|
||||||
fprintf(stderr, "failed to get device descriptor");
|
* Debugging data about found scale
|
||||||
return NULL;
|
*/
|
||||||
}
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < NSCALES; i++) {
|
|
||||||
if(desc.idVendor == scales[i][0] &&
|
|
||||||
desc.idProduct == scales[i][1]) {
|
|
||||||
/*
|
|
||||||
* Debugging data about found scale
|
|
||||||
*/
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Found scale %04x:%04x (bus %d, device %d)\n",
|
"Found scale %04x:%04x (bus %d, device %d)\n",
|
||||||
desc.idVendor,
|
desc.idVendor,
|
||||||
desc.idProduct,
|
desc.idProduct,
|
||||||
libusb_get_bus_number(dev),
|
libusb_get_bus_number(dev),
|
||||||
libusb_get_device_address(dev));
|
libusb_get_device_address(dev));
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"It has descriptors:\n\tmanufc: %d\n\tprodct: %d\n\tserial: %d\n\tclass: %d\n\tsubclass: %d\n",
|
"It has descriptors:\n\tmanufc: %d\n\tprodct: %d\n\tserial: %d\n\tclass: %d\n\tsubclass: %d\n",
|
||||||
desc.iManufacturer,
|
desc.iManufacturer,
|
||||||
desc.iProduct,
|
desc.iProduct,
|
||||||
desc.iSerialNumber,
|
desc.iSerialNumber,
|
||||||
desc.bDeviceClass,
|
desc.bDeviceClass,
|
||||||
desc.bDeviceSubClass);
|
desc.bDeviceSubClass);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A char buffer to pull string descriptors in from the device
|
* A char buffer to pull string descriptors in from the device
|
||||||
*/
|
*/
|
||||||
unsigned char string[256];
|
unsigned char string[256];
|
||||||
libusb_device_handle* hand;
|
libusb_device_handle* hand;
|
||||||
libusb_open(dev, &hand);
|
libusb_open(dev, &hand);
|
||||||
|
|
||||||
r = libusb_get_string_descriptor_ascii(hand, desc.iManufacturer,
|
r = libusb_get_string_descriptor_ascii(hand, desc.iManufacturer,
|
||||||
string, 256);
|
string, 256);
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Manufacturer: %s\n", string);
|
"Manufacturer: %s\n", string);
|
||||||
libusb_close(hand);
|
libusb_close(hand);
|
||||||
#endif
|
#endif
|
||||||
return dev;
|
return true;
|
||||||
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t get_first_endpoint_address(libusb_device* dev)
|
uint8_t get_first_endpoint_address(libusb_device* dev)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user