diff --git a/.gitignore b/.gitignore index d18fbf3..ee159ea 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ src/pcsensor +src/sensorapi.o +*~ diff --git a/src/Makefile b/src/Makefile index 992b41c..bcb885d 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,12 +1,21 @@ all: pcsensor -CFLAGS = -O2 -Wall -pcsensor: pcsensor.c - ${CC} -DUNIT_TEST -o $@ $^ -lusb +CFLAGS := -g -O2 -Wall -Wfloat-equal -Wwrite-strings -Wendif-labels +OBJS := sensorapi.o + + +%.o: %.c %.h + $(CC) -c $(CFLAGS) -o $@ $< + + +pcsensor: pcsensor.c $(OBJS) + $(CC) $(CFLAGS) -o $@ $^ -lusb clean: - rm -f pcsensor *.o + rm -f pcsensor $(OBJS) + rules-install: # must be superuser to do this cp ../udev/99-tempsensor.rules /etc/udev/rules.d + diff --git a/src/pcsensor.c b/src/pcsensor.c index 56fb787..857011b 100644 --- a/src/pcsensor.c +++ b/src/pcsensor.c @@ -15,451 +15,188 @@ * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - * THIS SOFTWARE IS PROVIDED BY Philipp Adelt (and other contributors) ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Philipp Adelt (or other contributors) BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * + * THIS SOFTWARE IS PROVIDED BY Philipp Adelt (and other contributors) ''AS + * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Philipp Adelt (or other + * contributors) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include #include - +#include #include -#include #include - - -#define VERSION "1.0.0" - -#define VENDOR_ID 0x0c45 -#define PRODUCT_ID 0x7401 - -#define INTERFACE1 0x00 -#define INTERFACE2 0x01 - -const static int reqIntLen=8; -const static int reqBulkLen=8; -const static int endpoint_Int_in=0x82; /* endpoint 0x81 address for IN */ -const static int endpoint_Int_out=0x00; /* endpoint 1 address for OUT */ -const static int endpoint_Bulk_in=0x82; /* endpoint 0x81 address for IN */ -const static int endpoint_Bulk_out=0x00; /* endpoint 1 address for OUT */ -const static int timeout=5000; /* timeout in ms */ - -const static char uTemperatura[] = { 0x01, 0x80, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00 }; -const static char uIni1[] = { 0x01, 0x82, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00 }; -const static char uIni2[] = { 0x01, 0x86, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00 }; - -static int bsalir=1; -static int debug=0; -static int seconds=5; -static int formato=0; -static int mrtg=0; -static int calibration=0; +#include "sensorapi.h" -void bad(const char *why) { - fprintf(stderr,"Fatal error> %s\n",why); - exit(17); -} - - -usb_dev_handle *find_lvr_winusb(); - -void usb_detach(usb_dev_handle *lvr_winusb, int iInterface) { - int ret; - - ret = usb_detach_kernel_driver_np(lvr_winusb, iInterface); - if(ret) { - if(errno == ENODATA) { - if(debug) { - printf("Device already detached\n"); - } - } else { - if(debug) { - printf("Detach failed: %s[%d]\n", - strerror(errno), errno); - printf("Continuing anyway\n"); - } - } - } else { - if(debug) { - printf("detach successful\n"); - } - } -} - -usb_dev_handle* setup_libusb_access(int devicenum) { - usb_dev_handle *lvr_winusb; - - if(debug) { - usb_set_debug(255); - } else { - usb_set_debug(0); - } - usb_init(); - usb_find_busses(); - usb_find_devices(); - - - if(!(lvr_winusb = find_lvr_winusb(devicenum))) { - printf("Couldn't find the USB device, Exiting\n"); - return NULL; - } - - - usb_detach(lvr_winusb, INTERFACE1); - - - usb_detach(lvr_winusb, INTERFACE2); - - - if (usb_set_configuration(lvr_winusb, 0x01) < 0) { - printf("Could not set configuration 1\n"); - return NULL; - } +#define VERSION "1.0.0" +static int bsalir=1; - // Microdia tiene 2 interfaces - if (usb_claim_interface(lvr_winusb, INTERFACE1) < 0) { - printf("Could not claim interface\n"); - return NULL; - } - - if (usb_claim_interface(lvr_winusb, INTERFACE2) < 0) { - printf("Could not claim interface\n"); - return NULL; - } - return lvr_winusb; +void ex_program(int sig) +{ + bsalir=1; + (void) signal(SIGINT, SIG_DFL); } - - - -usb_dev_handle *find_lvr_winusb(int devicenum) { - // iterates to the devicenum'th device for installations with multiple sensors - struct usb_bus *bus; - struct usb_device *dev; - - for (bus = usb_busses; bus; bus = bus->next) { - for (dev = bus->devices; dev; dev = dev->next) { - if (dev->descriptor.idVendor == VENDOR_ID && - dev->descriptor.idProduct == PRODUCT_ID ) { - if (devicenum>0) { - devicenum--; - continue; - } - usb_dev_handle *handle; - if(debug) { - printf("lvr_winusb with Vendor Id: %x and Product Id: %x found.\n", VENDOR_ID, PRODUCT_ID); - } - - if (!(handle = usb_open(dev))) { - printf("Could not open USB device\n"); - return NULL; - } - return handle; - } - } - } - return NULL; -} - - -void ini_control_transfer(usb_dev_handle *dev) { - int r,i; - char question[] = { 0x01,0x01 }; - - r = usb_control_msg(dev, 0x21, 0x09, 0x0201, 0x00, (char *) question, 2, timeout); - if( r < 0 ) - { - perror("USB control write"); bad("USB write failed"); - } - - - if(debug) { - for (i=0;i\n" + " ARGUMENTS:\n" + " OPTIONS:\n" + " -h help\n" + " -v verbose\n" + " -n[i] use device number i (0 is the first one found on the bus)\n" + " -l[n] loop every 'n' seconds, default value is 300\n" + " -c output only in Celsius\n" + " -f output only in Fahrenheit\n" + " -a[n] increase or decrease temperature in 'n' degrees for device calibration\n" + " -m output for mrtg integration\n" + , VERSION + , progname + ); } - -void control_transfer(usb_dev_handle *dev, const char *pquestion) { - int r,i; - char question[reqIntLen]; - - memcpy(question, pquestion, sizeof question); +int main( int argc, char **argv) +{ + usb_temper_t usb_temper; + float tempc; + int c; + struct tm *local; + time_t t; + int devicenum = 0; + int debug=0; + int seconds=5; + int formato=0; + int mrtg=0; + int calibration=0; + + while ((c = getopt (argc, argv, "mfcvhn:l::a:")) != -1) + switch (c) + { + case 'v': + debug = 1; + break; + case 'n': + if (optarg != NULL) { + if (!sscanf(optarg,"%i",&devicenum)==1) { + fprintf (stderr, "Error: '%s' is not numeric.\n", optarg); + exit(EXIT_FAILURE); + } + } + break; + case 'c': + formato=1; //Celsius + break; + case 'f': + formato=2; //Fahrenheit + break; + case 'm': + mrtg=1; + break; + case 'l': + if (optarg!=NULL){ + if (!sscanf(optarg,"%i",&seconds)==1) { + fprintf (stderr, "Error: '%s' is not numeric.\n", optarg); + exit(EXIT_FAILURE); + } else { + bsalir = 0; + break; + } + } else { + bsalir = 0; + seconds = 5; + break; + } + case 'a': + if (!sscanf(optarg,"%i",&calibration)==1) { + fprintf (stderr, "Error: '%s' is not numeric.\n", optarg); + exit(EXIT_FAILURE); + } else { + break; + } + case '?': + case 'h': + usage(argv[0]); + exit(EXIT_FAILURE); + default: + if (isprint (optopt)) + fprintf (stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf (stderr, + "Unknown option character `\\x%x'.\n", + optopt); + exit(EXIT_FAILURE); + } - r = usb_control_msg(dev, 0x21, 0x09, 0x0200, 0x01, (char *) question, reqIntLen, timeout); - if( r < 0 ) + if (optind < argc) { - perror("USB control write"); bad("USB write failed"); + fprintf(stderr, "Non-option ARGV-elements, try -h for help.\n"); + exit(EXIT_FAILURE); } - if(debug) { - for (i=0;itm_hour, + local->tm_min); -} + printf("pcsensor\n"); + } else { + printf("%04d/%02d/%02d %02d:%02d:%02d ", + local->tm_year +1900, + local->tm_mon + 1, + local->tm_mday, + local->tm_hour, + local->tm_min, + local->tm_sec); -void bulk_transfer(usb_dev_handle *dev) { - - int r,i; - char answer[reqBulkLen]; + if (formato==2) { + printf("Temperature %.2fF\n", (9.0 / 5.0 * tempc + 32.0)); + } else if (formato==1) { + printf("Temperature %.2fC\n", tempc); + } else { + printf("Temperature %.2fF %.2fC\n", (9.0 / 5.0 * tempc + 32.0), tempc); + } + } - r = usb_bulk_write(dev, endpoint_Bulk_out, NULL, 0, timeout); - if( r < 0 ) - { - perror("USB bulk write"); bad("USB write failed"); - } - r = usb_bulk_read(dev, endpoint_Bulk_in, answer, reqBulkLen, timeout); - if( r != reqBulkLen ) - { - perror("USB bulk read"); bad("USB read failed"); + if (!bsalir) { sleep(seconds); } } + while (!bsalir); + usb_temper_finish(&usb_temper); - if(debug) { - for (i=0;itm_hour, - local->tm_min); - - printf("pcsensor\n"); - } else { - printf("%04d/%02d/%02d %02d:%02d:%02d ", - local->tm_year +1900, - local->tm_mon + 1, - local->tm_mday, - local->tm_hour, - local->tm_min, - local->tm_sec); - - if (formato==2) { - printf("Temperature %.2fF\n", (9.0 / 5.0 * tempc + 32.0)); - } else if (formato==1) { - printf("Temperature %.2fC\n", tempc); - } else { - printf("Temperature %.2fF %.2fC\n", (9.0 / 5.0 * tempc + 32.0), tempc); - } - } - - if (!bsalir) - sleep(seconds); - } while (!bsalir); - - usb_release_interface(lvr_winusb, INTERFACE1); - usb_release_interface(lvr_winusb, INTERFACE2); - - usb_close(lvr_winusb); - - return 0; -} diff --git a/src/sensorapi.c b/src/sensorapi.c new file mode 100644 index 0000000..0aad20f --- /dev/null +++ b/src/sensorapi.c @@ -0,0 +1,369 @@ +/* + * pcsensor.c by Philipp Adelt (c) 2012 (info@philipp.adelt.net) + * based on Juan Carlos Perez (c) 2011 (cray@isp-sl.com) + * based on Temper.c by Robert Kavaler (c) 2009 (relavak.com) + * All rights reserved. + * + * Temper driver for linux. This program can be compiled either as a library + * or as a standalone program (-DUNIT_TEST). The driver will work with some + * TEMPer usb devices from RDing (www.PCsensor.com). + * + * This driver works with USB devices presenting ID 0c45:7401. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY Philipp Adelt (and other contributors) ''AS + * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Philipp Adelt (or other + * contributors) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "sensorapi.h" + +#include +#include +#include + + +#define USB_TEMPER_INTERFACE1 (0x00) +#define USB_TEMPER_INTERFACE2 (0x01) +#define USB_TEMPER_VENDOR_ID (0x0c45) +#define USB_TEMPER_PRODUCT_ID (0x7401) + + +static const char uTemperatura[] = { 0x01, 0x80, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00 }; +static const char uIni1[] = { 0x01, 0x82, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00 }; +static const char uIni2[] = { 0x01, 0x86, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00 }; + + +const static int reqIntLen=8; +const static int reqBulkLen=8; +const static int endpoint_Int_in=0x82; /* endpoint 0x81 address for IN */ +const static int endpoint_Int_out=0x00; /* endpoint 1 address for OUT */ +const static int endpoint_Bulk_in=0x82; /* endpoint 0x81 address for IN */ +const static int endpoint_Bulk_out=0x00; /* endpoint 1 address for OUT */ +const static int timeout=5000; /* timeout in ms */ + +static int DEBUG=0; +static int CALIBRATION=0; + + +void bad(const char *why) +{ + fprintf(stderr, "Fatal error> %s\n", why); + exit(17); +} + +usb_dev_handle *find_lvr_winusb(); + +void usb_detach(usb_dev_handle *lvr_winusb, int iInterface) +{ + int ret; + ret = usb_detach_kernel_driver_np(lvr_winusb, iInterface); + if(ret) { + if(errno == ENODATA) { + if(DEBUG) { + printf("Device already detached\n"); + } + } else { + if(DEBUG) { + printf("Detach failed: %s[%d]\n", + strerror(errno), errno); + printf("Continuing anyway\n"); + } + } + } else { + if(DEBUG) { + printf("detach successful\n"); + } + } +} + +usb_dev_handle* setup_libusb_access(int devicenum) +{ + usb_dev_handle *lvr_winusb; + + if(DEBUG) { + usb_set_debug(255); + } else { + usb_set_debug(0); + } + usb_init(); + usb_find_busses(); + usb_find_devices(); + + + if(!(lvr_winusb = find_lvr_winusb(devicenum))) { + printf("Couldn't find the USB device, Exiting\n"); + return NULL; + } + + + usb_detach(lvr_winusb, USB_TEMPER_INTERFACE1); + + usb_detach(lvr_winusb, USB_TEMPER_INTERFACE2); + + if (usb_set_configuration(lvr_winusb, 0x01) < 0) { + printf("Could not set configuration 1\n"); + return NULL; + } + + + // Microdia tiene 2 interfaces + if (usb_claim_interface(lvr_winusb, USB_TEMPER_INTERFACE1) < 0) { + printf("Could not claim interface\n"); + return NULL; + } + + if (usb_claim_interface(lvr_winusb, USB_TEMPER_INTERFACE2) < 0) { + printf("Could not claim interface\n"); + return NULL; + } + + return lvr_winusb; +} + + +usb_dev_handle *find_lvr_winusb(int devicenum) +{ + // iterates to the devicenum'th device for installations with multiple sensors + struct usb_bus *bus; + struct usb_device *dev; + + for (bus = usb_busses; bus; bus = bus->next) { + for (dev = bus->devices; dev; dev = dev->next) { + if (dev->descriptor.idVendor == USB_TEMPER_VENDOR_ID && + dev->descriptor.idProduct == USB_TEMPER_PRODUCT_ID ) { + if (devicenum>0) { + devicenum--; + continue; + } + usb_dev_handle *handle; + if(DEBUG) { + printf("lvr_winusb with Vendor Id: %x and Product Id: %x found.\n", USB_TEMPER_VENDOR_ID, USB_TEMPER_PRODUCT_ID); + } + + if (!(handle = usb_open(dev))) { + printf("Could not open USB device\n"); + return NULL; + } + return handle; + } + } + } + return NULL; +} + +void ini_control_transfer(usb_dev_handle *dev) +{ + int r,i; + + char question[] = { 0x01,0x01 }; + + r = usb_control_msg(dev, 0x21, 0x09, 0x0201, 0x00, (char *) question, 2, timeout); + if ( r < 0 ) + { + perror("USB control write"); bad("USB write failed"); + } + + if (DEBUG) { + for (i=0; i<(sizeof(question)/sizeof(question[0])); i++) { + printf("%02x ",question[i] & 0xFF); + } + printf("\n"); + } +} + +void control_transfer(usb_dev_handle *dev, const char *pquestion) +{ + int r,i; + + char question[reqIntLen]; + + memcpy(question, pquestion, sizeof question); + + r = usb_control_msg(dev, 0x21, 0x09, 0x0200, 0x01, (char *) question, reqIntLen, timeout); + if( r < 0 ) + { + perror("USB control write"); bad("USB write failed"); + } + + if(DEBUG) { + for (i=0;iusb_handle = usb_handle; + usb_temper->devicenum = devicenum; + + DEBUG = debug; + CALIBRATION = calibration; + + return usb_temper; +} + +float usb_temper_get_tempc(usb_temper_t usb_temper) +{ + // return an impossible temperature (absolute zero = -273.15) if bad + // inputs or some other failure + float tempc = -9999.99; + + if (usb_temper && usb_temper->usb_handle) + { + control_transfer(usb_temper->usb_handle, uTemperatura ); + interrupt_read_temperatura(usb_temper->usb_handle, &tempc); + } + + return tempc; +} + +int usb_temper_finish(usb_temper_t* usb_temper) +{ + if (usb_temper && (*usb_temper) && (*usb_temper)->usb_handle) + { + usb_release_interface((*usb_temper)->usb_handle, USB_TEMPER_INTERFACE1); + usb_release_interface((*usb_temper)->usb_handle, USB_TEMPER_INTERFACE2); + usb_close((*usb_temper)->usb_handle); + free(*usb_temper); + *usb_temper = NULL; + } + + return 0; +} + diff --git a/src/sensorapi.h b/src/sensorapi.h new file mode 100644 index 0000000..816e1cb --- /dev/null +++ b/src/sensorapi.h @@ -0,0 +1,54 @@ +#ifndef SENSOR_API_H__ +#define SENSOR_API_H__ + +/* + * pcsensor.c by Philipp Adelt (c) 2012 (info@philipp.adelt.net) + * based on Juan Carlos Perez (c) 2011 (cray@isp-sl.com) + * based on Temper.c by Robert Kavaler (c) 2009 (relavak.com) + * All rights reserved. + * + * Temper driver for linux. This program can be compiled either as a library + * or as a standalone program (-DUNIT_TEST). The driver will work with some + * TEMPer usb devices from RDing (www.PCsensor.com). + * + * This driver works with USB devices presenting ID 0c45:7401. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * THIS SOFTWARE IS PROVIDED BY Philipp Adelt (and other contributors) ''AS + * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Philipp Adelt (or other + * contributors) BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#define MALLOC(n) malloc_wrapper((n), __FILE__, __LINE__) + +struct usb_temper +{ + usb_dev_handle* usb_handle; + int devicenum; + int debug; +}; + +typedef struct usb_temper* usb_temper_t; + +usb_temper_t usb_temper_init(int devicenum, int debug, int calibration); +float usb_temper_get_tempc(usb_temper_t usb_temper); +int usb_temper_finish(usb_temper_t* usb_temper); + +void* malloc_wrapper(size_t nbytes, const char* file, int line); + +#endif // SENSOR_API_H__ +