From: Gerry <gb...@ge...> - 2015-01-20 11:24:50
|
Sorry for the late reply but I had sent this to the pyusb-users-owner list instead of this list. I had originally included the files as attachments but the list stripped them off so now I am including them in this email. Hopefully someone can find a solution to this problem. -------- Forwarded Message -------- Subject: My Python source code and another's C code Date: Wed, 14 Jan 2015 19:09:35 +0800 From: Gerry <gb...@ge...> To: pyu...@li... Here is my Python code: "#!/usr/bin/python """ Read a MagTek USB HID Swipe Reader in Linux. A description of this code can be found at: http://www.micahcarrick.com/credit-card-reader-pyusb.html You must be using the new PyUSB 1.0 branch and not the 0.x branch. Copyright (c) 2010 - Micah Carrick """ import sys import usb.core #import usb.backend.libusb1 as libusb1 import usb.util VENDOR_ID = 0x24c0 PRODUCT_ID = 0x0003 DATA_SIZE = 50 # find the Acurite Weather Station device = usb.core.find(idVendor=0x24c0, idProduct=0x0003) if device is None: sys.exit("Could not find Acurite weatherstation.") #else: # print("Device FOUND!!", device) # fout = open('device.txt', 'w') # d1 = str(device) # fout.write(d1) # fout.close # make sure the hiddev kernel driver is not active if device.is_kernel_driver_active(0): try: device.detach_kernel_driver(0) except usb.core.USBError as e: sys.exit("Could not detatch kernel driver: %s" % str(e)) # set configuration try: device.set_configuration() device.reset() except usb.core.USBError as e: sys.exit("Could not set configuration: %s" % str(e)) endpoint = device[0][(0,0)][0] #print ("Endpoint = ", endpoint) #epa = endpoint.bEndpointAddress #mps = endpoint.wMaxPacketSize #print ("EPA = ", epa, "MPS= ", mps) data = [] print ("Now starting to read...") *This is where I am getting the errors. I originally had it as "d1 = device.read(..." but after looking at the Pyusb.core code it said it should be "d1 = read(device..." Both ways give the same errors. Hopefully you can find the problem so I can read my weather station...* d1 = read(device, endpoint.bEndpointAddress, endpoint.wMaxPacketSize) print ("D1 =",d1) '''while 1: try: #data += device.read(endpoint.bEndpointAddress, endpoint.wMaxPacketSize) #print("Data = ",data) data += device.read(0x81, 8) print ("Reading...") except usb.core.USBError as e: if e.args == ('Operation timed out',): #and swiped: if len(data) < DATA_SIZE: print ("Bad swipe, try again. (%d bytes)") % len(data) print ("Data: %s" % ''.join(map(chr, data))) data = [] continue else: print ("Data = ",data) break # we got it! ''' The other person's C code: "/* Documentation at desert-home.com Experimentation with a USB interface to the Acu-Rite 5 in 1 Weatherstation specifically for the Raspberry Pi. The code may work on other systems, but I don't have one of those. Contrary to other folk's thinking, I don't care if this ever runs on a Windows PC or an Apple anything. I specifically used a model 2032 display with the sensor that I picked up at one of those warehouse stores. The display has a usb plug on it and I thought it might be possible to read the usb port and massage the data myself. This code represents the result of that effort. I gathered ideas from all over the web. I use the latest (for this second) libusb and about a thousand examples of various things that other people have done and posted about. Frankly, I simply can't remember all of them, so please, don't be offended if you see your ideas somewhere in here and it isn't attributed. I simply lost track of where I found what. This module relies on libusb version 1.0.19 which, at this time, can only be compiled from source on the raspberry pi. Because there likely to be a version of libusb and the associated header file on a Pi, use the command line below to build it since the build of libusb-1.0.19 places things in /usr/local cc -o weatherstation weatherstation.c -L/usr/local/lib -lusb-1.0 * use ldd weatherstation to check which libraries are linked in. If you still have trouble with compilation, remember that cc has a -v parameter that can help you unwind what is happening. */ #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <time.h> #include <unistd.h> #include <sys/time.h> #include <libusb-1.0/libusb.h> // The vendor id and product number for the AcuRite 5 in 1 weather head. #define VENDOR 0x24c0 #define PRODUCT 0x0003 // I store things about the weather device USB connection here. struct { libusb_device *device; libusb_device_handle *handle; int verbose; } weatherStation; // These are the sensors the the 5 in 1 weather head provides struct { float windSpeed; time_t wsTime; int windDirection; time_t wdTime; float temperature; time_t tTime; int humidity; time_t hTime; int rainCounter; time_t rcTime; } weatherData; // This is just a function prototype for the compiler void closeUpAndLeave(); // I want to catch control-C and close down gracefully void sig_handler(int signo) { if (signo == SIGINT) fprintf(stderr,"Shutting down ...\n"); closeUpAndLeave(); } /* This tiny thing simply takes the data and prints it so we can see it */ // Array to translate the integer direction provided to text char *Direction[] = { "NNW", "NW ", "WNW", "W ", "WSW", "SW ", "SSW", "S ", "SSE", "SE ", "ESE", "E ", "ENE", "NE ", "NNE", "N " }; void showit(){ fprintf(stdout, "{\"windSpeed\":{\"WS\":\"%.1f\",\"t\":\"%d\"}," "\"windDirection\":{\"WD\":\"%s\",\"t\":\"%d\"}," "\"temperature\":{\"T\":\"%.1f\",\"t\":\"%d\"}," "\"humidity\":{\"H\":\"%d\",\"t\":\"%d\"}," "\"rainCounter\":{\"RC\":\"%d\",\"t\":\"%d\"}}\n", weatherData.windSpeed, weatherData.wsTime, Direction[weatherData.windDirection],weatherData.wdTime, weatherData.temperature, weatherData.tTime, weatherData.humidity, weatherData.hTime, weatherData.rainCounter, weatherData.rcTime); fflush(stdout); } /* This code translates the data from the 5 in 1 sensors to something that can be used by a human. */ float getWindSpeed(char *data){ int leftSide = (data[3] & 0x1f) << 3; int rightSide = data[4] & 0x70 >> 4; // Yes, I use mph, never got used to kilometers. return((float)(leftSide | rightSide) * 0.62); } int getWindDirection(char *data){ return(data[4] & 0x0f); } float getTemp(char *data){ // This item spans bytes, have to reconstruct it int leftSide = (data[4] & 0x0f) << 7; int rightSide = data[5] & 0x7f; float combined = leftSide | rightSide; return((combined - 400) / 10.0); } int getHumidity(char *data){ int howWet = data[6] &0x7f; return(howWet); } int getRainCount(char *data){ int count = data[6] &0x7f; return(count); } // Now that I have the data from the station, do something useful with it. void decode(char *data, int length, int noisy){ //int i; //for(i=0; i<length; i++){ // fprintf(stderr,"%0.2X ",data[i]); //} //fprintf(stderr,"\n"); time_t seconds = time (NULL); //There are two varieties of data, both of them have wind speed // first variety of the data if ((data[2] & 0x0f) == 1){ // this has wind speed, direction and rainfall if(noisy) fprintf(stderr,"Wind Speed: %.1f ",getWindSpeed(data)); weatherData.windSpeed = getWindSpeed(data); weatherData.wsTime = seconds; if(noisy) fprintf(stderr,"Wind Direction: %s ",Direction[getWindDirection(data)]); weatherData.wdTime = seconds; weatherData.windDirection = getWindDirection(data); if(noisy){ fprintf(stderr,"Rain Counter: %d ",getRainCount(data)); fprintf(stderr,"\n"); } weatherData.rainCounter = getRainCount(data); weatherData.rcTime = seconds; } // this is the other variety if ((data[2] & 0x0f) == 8){ // this has wind speed, temp and relative humidity if(noisy) fprintf(stderr,"Wind Speed: %.1f ",getWindSpeed(data)); weatherData.windSpeed = getWindSpeed(data); weatherData.wsTime = seconds; if(noisy) fprintf(stderr,"Temperature: %.1f ",getTemp(data)); weatherData.temperature = getTemp(data); weatherData.tTime = seconds; if(noisy){ fprintf(stderr,"Humidity: %d ", getHumidity(data)); fprintf(stderr,"\n"); } weatherData.humidity = getHumidity(data); weatherData.hTime = seconds; } } /* This code is related to dealing with the USB device */ // This searches the USB bus tree to find the device int findDevice(libusb_device **devs) { libusb_device *dev; int err = 0, i = 0, j = 0; uint8_t path[8]; while ((dev = devs[i++]) != NULL) { struct libusb_device_descriptor desc; int r = libusb_get_device_descriptor(dev, &desc); if (r < 0) { fprintf(stderr,"Couldn't get device descriptor, %s\n", libusb_strerror(err)); return(1); } fprintf(stderr,"%04x:%04x (bus %d, device %d)", desc.idVendor, desc.idProduct, libusb_get_bus_number(dev), libusb_get_device_address(dev)); //r = libusb_get_port_numbers(dev, path, sizeof(path)); //if (r > 0) { // fprintf(stderr," path: %d", path[0]); // for (j = 1; j < r; j++) // fprintf(stderr,".%d", path[j]); //} //fprintf(stderr,"\n"); if (desc.idVendor == VENDOR && desc.idProduct == PRODUCT){ fprintf(stderr,"Found the one I want\n"); weatherStation.device = dev; return (1); } } return(0); } // to handle testing and try to be clean about closing the USB device, // I'll catch the signal and close off. void closeUpAndLeave(){ //OK, done with it, close off and let it go. fprintf(stderr,"Done with device, release and close it\n"); int err = libusb_release_interface(weatherStation.handle, 0); //release the claimed interface if(err) { fprintf(stderr,"Couldn't release interface, %s\n", libusb_strerror(err)); exit(1); } libusb_close(weatherStation.handle); libusb_exit(NULL); exit(0); } // This is where I read the USB device to get the latest data. unsigned char data[50]; // where we want the data to go int getit(int whichOne, int noisy){ int actual; // how many bytes were actually read // The second parameter is bmRequestType and is a bitfield // See http://www.beyondlogic.org/usbnutshell/usb6.shtml // for the definitions of the various bits. With libusb, the // #defines for these are at: //http://libusb.sourceforge.net/api-1.0/group__misc.html#gga0b0933ae70744726cde11254c39fac91a20eca62c34d2d25be7e1776510184209 *This is where the data is being read from the device.* actual = libusb_control_transfer(weatherStation.handle, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE | LIBUSB_ENDPOINT_IN, //These bytes were stolen with a USB sniffer 0x01,0x0100+whichOne,0, data, 50, 10000); if (actual < 0){ fprintf(stderr,"Read didn't work for report %d, %s\n", whichOne, libusb_strerror(actual)); } else { // If you want both of the reports that the station provides, // just allow for it. Right this second, I've found every thing // I need in report 1. When I look further at report 2, this will // change /*fprintf(stderr,"R%d:%d:", whichOne, actual); int i; for(i=0; i<actual; i++){ fprintf(stderr,"%0.2X ",data[i]); } fprintf(stderr,"\n"); */ if (whichOne == 1) // The actual data starts after the first byte // The first byte is the report number returned by // the usb read. decode(&data[1], actual-1, noisy); } } // I do several things here that aren't strictly necessary. As I learned about // libusb, I tried things and also used various techniques to learn about the // weatherstation's implementation. I left a lot of it in here in case I needed to // use it later. Someone may find it useful to hack into some other device. int main(int argc, char **argv) { char *usage = {"usage: %s -u -n\n"}; int libusbDebug = 0; //This will turn on the DEBUG for libusb int noisy = 0; //This will print the packets as they come in libusb_device **devs; int r, err, c; ssize_t cnt; while ((c = getopt (argc, argv, "unh")) != -1) switch (c){ case 'u': libusbDebug = 1; break; case 'n': noisy = 1; break; case 'h': fprintf(stderr, usage, argv[0]); case '?': exit(1); default: exit(1); } fprintf (stderr,"libusbDebug = %d, noisy = %d\n", libusbDebug, noisy); if (signal(SIGINT, sig_handler) == SIG_ERR) fprintf(stderr,"Couldn't set up signal handler\n"); err = libusb_init(NULL); if (err < 0){ fprintf(stderr,"Couldn't init usblib, %s\n", libusb_strerror(err)); exit(1); } // This is where you can get debug output from libusb. // just set it to LIBUSB_LOG_LEVEL_DEBUG if (libusbDebug) libusb_set_debug(NULL, LIBUSB_LOG_LEVEL_DEBUG); else libusb_set_debug(NULL, LIBUSB_LOG_LEVEL_INFO); cnt = libusb_get_device_list(NULL, &devs); if (cnt < 0){ fprintf(stderr,"Couldn't get device list, %s\n", libusb_strerror(err)); exit(1); } // got get the device; the device handle is saved in weatherStation struct. if (!findDevice(devs)){ fprintf(stderr,"Couldn't find the device\n"); exit(1); } // Now I've found the weather station and can start to try stuff // So, I'll get the device descriptor struct libusb_device_descriptor deviceDesc; err = libusb_get_device_descriptor(weatherStation.device, &deviceDesc); if (err){ fprintf(stderr,"Couldn't get device descriptor, %s\n", libusb_strerror(err)); exit(1); } fprintf(stderr,"Got the device descriptor back\n"); // Open the device and save the handle in the weatherStation struct err = libusb_open(weatherStation.device, &weatherStation.handle); if (err){ fprintf(stderr,"Open failed, %s\n", libusb_strerror(err)); exit(1); } fprintf(stderr,"I was able to open it\n"); // There's a bug in either the usb library, the linux driver or the // device itself. I suspect the usb driver, but don't know for sure. // If you plug and unplug the weather station a few times, it will stop // responding to reads. It also exhibits some strange behaviour to // getting the configuration. I found out after a couple of days of // experimenting that doing a clear-halt on the device while before it // was opened it would clear the problem. So, I have one here and a // little further down after it has been opened. fprintf(stderr,"trying clear halt on endpoint %X ... ", 0x81); // err = libusb_clear_halt(weatherStation.handle, 0x81); if (err){ fprintf(stderr,"clear halt crapped, %s Bug Detector\n", libusb_strerror(err));; } else { fprintf(stderr,"OK\n"); } // Now that it's opened, I can free the list of all devices libusb_free_device_list(devs, 1); // Documentation says to get rid of the list // Once I have the device I need fprintf(stderr,"Released the device list\n"); // Now I have to check to see if the kernal using udev has attached // a driver to the device. If it has, it has to be detached so I can // use the device. if(libusb_kernel_driver_active(weatherStation.handle, 0) == 1) { //find out if kernel driver is attached fprintf(stderr,"Kernal driver active\n"); if(libusb_detach_kernel_driver(weatherStation.handle, 0) == 0) //detach it fprintf(stderr,"Kernel Driver Detached!\n"); } int activeConfig; err =libusb_get_configuration (weatherStation.handle, &activeConfig); if (err){ fprintf(stderr,"Can't get current active configuration, %s\n", libusb_strerror(err));; exit(1); } fprintf(stderr,"Currently active configuration is %d\n", activeConfig); if(activeConfig != 1){ err = libusb_set_configuration (weatherStation.handle, 1); if (err){ fprintf(stderr,"Cannot set configuration, %s\n", libusb_strerror(err));; exit(1); } fprintf(stderr,"Just did the set configuration\n"); } err = libusb_claim_interface(weatherStation.handle, 0); //claim interface 0 (the first) of device (mine had jsut 1) if(err) { fprintf(stderr,"Cannot claim interface, %s\n", libusb_strerror(err)); exit(1); } fprintf(stderr,"Claimed Interface\n"); fprintf(stderr,"Number of configurations: %d\n",deviceDesc.bNumConfigurations); struct libusb_config_descriptor *config; libusb_get_config_descriptor(weatherStation.device, 0, &config); fprintf(stderr,"Number of Interfaces: %d\n",(int)config->bNumInterfaces); // I know, the device only has one interface, but I wanted this code // to serve as a reference for some future hack into some other device, // so I put this loop to show the other interfaces that may // be there. And, like most of this module, I stole the ideas from // somewhere, but I can't remember where (I guess it's google overload) const struct libusb_interface *inter; const struct libusb_interface_descriptor *interdesc; const struct libusb_endpoint_descriptor *epdesc; int i, j, k; for(i=0; i<(int)config->bNumInterfaces; i++) { inter = &config->interface[i]; fprintf(stderr,"Number of alternate settings: %d\n", inter->num_altsetting); for(j=0; j < inter->num_altsetting; j++) { interdesc = &inter->altsetting[j]; fprintf(stderr,"Interface Number: %d\n", (int)interdesc->bInterfaceNumber); fprintf(stderr,"Number of endpoints: %d\n", (int)interdesc->bNumEndpoints); for(k=0; k < (int)interdesc->bNumEndpoints; k++) { epdesc = &interdesc->endpoint[k]; fprintf(stderr,"Descriptor Type: %d\n",(int)epdesc->bDescriptorType); fprintf(stderr,"Endpoint Address: 0x%0.2X\n",(int)epdesc->bEndpointAddress); // Below is how to tell which direction the // endpoint is supposed to work. It's the high order bit // in the endpoint address. I guess they wanted to hide it. fprintf(stderr," Direction is "); if ((int)epdesc->bEndpointAddress & LIBUSB_ENDPOINT_IN != 0) fprintf(stderr," In (device to host)"); else fprintf(stderr," Out (host to device)"); fprintf(stderr,"\n"); } } } fprintf(stderr,"trying clear halt on endpoint %X ... ", (int)epdesc->bEndpointAddress); // err = libusb_clear_halt(weatherStation.handle, (int)epdesc->bEndpointAddress); if (err){ fprintf(stderr,"clear halt crapped, %s SHUCKS\n", libusb_strerror(err));; closeUpAndLeave(); } else { fprintf(stderr,"OK\n"); } // So, for the weather station we now know it has one endpoint and it is set to // send data to the host. Now we can experiment with that. // // I don't want to just hang up and read the reports as fast as I can, so // I'll space them out a bit. It's weather, and it doesn't change very fast. int tickcounter= 0; while(1){ sleep(1); if(tickcounter++ % 10 == 0){ getit(1, noisy); } if(tickcounter % 30 == 0){ getit(2, noisy); } if (tickcounter % 15 == 0){ showit(); } } }" |