Hi, I just recieved a PCSensor TEMPer usb thermometer, like this one: http://www.pcsensor.com/http-//www-pcsensor-com/uploadFile/APPsoftware/Hid-TEMPer-20V10-1-zip/prod_15.html It exposes a uhid device, and i was lucky adapting the openbsd uthum(4) driver for TEMPerHUM to this device. The attached patch contains the modified driver, which should work for both TERMPerHUM and TERMPer devices, and declare them to sysmon. Best regards, antoine
? uthum.c Index: files.usb =================================================================== RCS file: /cvsroot/src/sys/dev/usb/files.usb,v retrieving revision 1.92 diff -u -r1.92 files.usb --- files.usb 30 Nov 2009 16:18:34 -0000 1.92 +++ files.usb 31 Jan 2010 15:30:39 -0000 @@ -185,6 +185,10 @@ attach udsbr at usbdevif file dev/usb/udsbr.c udsbr +# TEMPerHUM HID +device uthum: hid +attach uthum at uhidbus +file dev/usb/uthum.c uthum # Ethernet adapters # ADMtek AN986 Pegasus Index: usbdevs =================================================================== RCS file: /cvsroot/src/sys/dev/usb/usbdevs,v retrieving revision 1.538 diff -u -r1.538 usbdevs --- usbdevs 12 Dec 2009 14:01:54 -0000 1.538 +++ usbdevs 31 Jan 2010 15:30:39 -0000 @@ -432,6 +432,7 @@ vendor PLX 0x10b5 PLX vendor ASANTE 0x10bd Asante vendor SILABS 0x10c4 Silicon Labs +vendor TENX 0x1130 Ten X Technology, Inc. vendor JRC 0x1145 Japan Radio Company vendor SPHAIRON 0x114b Sphairon Access Systems GmbH vendor DELORME 0x1163 DeLorme @@ -2312,6 +2313,10 @@ /* Telex Communications products */ product TELEX MIC1 0x0001 Enhanced USB Microphone +/* Ten X Technology, Inc. */ +product TENX MISSILE 0x0202 Missile Launcher +product TENX TEMPER 0x660c TEMPer sensor + /* Texas Intel products */ product TI UTUSB41 0x1446 UT-USB41 hub product TI TUSB2046 0x2046 TUSB2046 hub Index: usbdevs.h =================================================================== RCS file: /cvsroot/src/sys/dev/usb/usbdevs.h,v retrieving revision 1.533 diff -u -r1.533 usbdevs.h --- usbdevs.h 12 Dec 2009 14:30:59 -0000 1.533 +++ usbdevs.h 31 Jan 2010 15:30:40 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: usbdevs.h,v 1.533 2009/12/12 14:30:59 cherry Exp $ */ +/* $NetBSD$ */ /* * THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. @@ -439,6 +439,7 @@ #define USB_VENDOR_PLX 0x10b5 /* PLX */ #define USB_VENDOR_ASANTE 0x10bd /* Asante */ #define USB_VENDOR_SILABS 0x10c4 /* Silicon Labs */ +#define USB_VENDOR_TENX 0x1130 /* Ten X Technology, Inc. */ #define USB_VENDOR_JRC 0x1145 /* Japan Radio Company */ #define USB_VENDOR_SPHAIRON 0x114b /* Sphairon Access Systems GmbH */ #define USB_VENDOR_DELORME 0x1163 /* DeLorme */ @@ -2319,6 +2320,10 @@ /* Telex Communications products */ #define USB_PRODUCT_TELEX_MIC1 0x0001 /* Enhanced USB Microphone */ +/* Ten X Technology, Inc. */ +#define USB_PRODUCT_TENX_MISSILE 0x0202 /* Missile Launcher */ +#define USB_PRODUCT_TENX_TEMPER 0x660c /* TEMPer sensor */ + /* Texas Intel products */ #define USB_PRODUCT_TI_UTUSB41 0x1446 /* UT-USB41 hub */ #define USB_PRODUCT_TI_TUSB2046 0x2046 /* TUSB2046 hub */ Index: usbdevs_data.h =================================================================== RCS file: /cvsroot/src/sys/dev/usb/usbdevs_data.h,v retrieving revision 1.534 diff -u -r1.534 usbdevs_data.h --- usbdevs_data.h 12 Dec 2009 14:30:59 -0000 1.534 +++ usbdevs_data.h 31 Jan 2010 15:30:40 -0000 @@ -1,4 +1,4 @@ -/* $NetBSD: usbdevs_data.h,v 1.534 2009/12/12 14:30:59 cherry Exp $ */ +/* $NetBSD$ */ /* * THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. @@ -1535,6 +1535,10 @@ "Silicon Labs", }, { + USB_VENDOR_TENX, + "Ten X Technology, Inc.", + }, + { USB_VENDOR_JRC, "Japan Radio Company", }, @@ -1891,7 +1895,7 @@ "GNU Radio USRP", }, }; -const int usb_nvendors = 463; +const int usb_nvendors = 464; const struct usb_product usb_products[] = { { @@ -6655,6 +6659,14 @@ "Enhanced USB Microphone", }, { + USB_VENDOR_TENX, USB_PRODUCT_TENX_MISSILE, + "Missile Launcher", + }, + { + USB_VENDOR_TENX, USB_PRODUCT_TENX_TEMPER, + "TEMPer sensor", + }, + { USB_VENDOR_TI, USB_PRODUCT_TI_UTUSB41, "UT-USB41 hub", }, @@ -7031,4 +7043,4 @@ "Prestige", }, }; -const int usb_nproducts = 1284; +const int usb_nproducts = 1286; --- /dev/null 2010-01-31 16:23:47.000000000 +0100 +++ uthum.c 2010-01-31 16:14:55.000000000 +0100 @@ -0,0 +1,382 @@ +/* $OpenBSD: uthum.c,v 1.6 2010/01/03 18:43:02 deraadt Exp $ */ + +/* + * Copyright (c) 2009 Yojiro UO <yuo%nui.org@localhost> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* Driver for TEMPerHUM HID */ + +#include <sys/param.h> +#include <sys/proc.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/device.h> +#include <sys/conf.h> + +#include <dev/sysmon/sysmonvar.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbhid.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdi_util.h> +#include <dev/usb/usbdevs.h> +#include <dev/usb/uhidev.h> +#include <dev/usb/hid.h> + +#ifdef USB_DEBUG +#define UTHUM_DEBUG +#endif + +#ifdef UTHUM_DEBUG +int uthumdebug = 0; +#define DPRINTFN(n, x) do { if (uthumdebug > (n)) printf x; } while (0) +#else +#define DPRINTFN(n, x) +#endif + +#define DPRINTF(x) DPRINTFN(0, x) + + +/* TEMPerHUM */ +#define CMD_DEVTYPE 0x52 /* XXX */ +#define CMD_GETDATA 0x48 /* XXX */ +#define CMD_GETTEMP 0x54 /* XXX */ +static uint8_t cmd_start[8] = + { 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00, 0x02, 0x00 }; +static uint8_t cmd_end[8] = + { 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00, 0x01, 0x00 }; + +/* sensors */ +#define UTHUM_TEMP 0 +#define UTHUM_HUMIDITY 1 +#define UTHUM_MAX_SENSORS 2 + +#define UTHUM_TYPE_UNKNOWN 0 +#define UTHUM_TYPE_SHT1x 1 +#define UTHUM_TYPE_TEMPER 2 + +struct uthum_softc { + struct uhidev sc_hdev; + usbd_device_handle sc_udev; + u_char sc_dying; + uint16_t sc_flag; + int sc_sensortype; + + /* uhidev parameters */ + size_t sc_flen; /* feature report length */ + size_t sc_ilen; /* input report length */ + size_t sc_olen; /* output report length */ + + /* sensor framework */ + struct sysmon_envsys *sc_sme; + envsys_data_t sc_sensor[UTHUM_MAX_SENSORS]; + + uint8_t sc_num_sensors; +}; + + +const struct usb_devno uthum_devs[] = { + /* XXX: various TEMPer variants using same VID/PID */ + { USB_VENDOR_TENX, USB_PRODUCT_TENX_TEMPER}, +}; +#define uthum_lookup(v, p) usb_lookup(uthum_devs, v, p) + +int uthum_match(device_t, cfdata_t, void *); +void uthum_attach(device_t, device_t, void *); +void uthum_childdet(device_t, device_t); +int uthum_detach(device_t, int); +int uthum_activate(device_t, enum devact); + +int uthum_read_data(struct uthum_softc *, uint8_t, uint8_t *, size_t, int); +int uthum_check_sensortype(struct uthum_softc *); +int uthum_sht1x_temp(unsigned int); +int uthum_sht1x_rh(unsigned int, int); + +void uthum_intr(struct uhidev *, void *, u_int); +static void uthum_refresh(struct sysmon_envsys *, envsys_data_t *); + +extern struct cfdriver uthum_cd; +CFATTACH_DECL_NEW(uthum, sizeof(struct uthum_softc), uthum_match, uthum_attach, + uthum_detach, uthum_activate); + +USB_MATCH(uthum) +{ + USB_MATCH_START(uthum, uaa); + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; + + return (uthum_lookup(uha->uaa->vendor, uha->uaa->product) != NULL ? + UMATCH_VENDOR_PRODUCT : UMATCH_NONE); +} + +USB_ATTACH(uthum) +{ + USB_ATTACH_START(uthum, sc, uaa); + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; + usbd_device_handle dev = uha->parent->sc_udev; + int size, repid; + void *desc; + + sc->sc_udev = dev; + sc->sc_hdev.sc_dev = self; + sc->sc_hdev.sc_intr = uthum_intr; + sc->sc_hdev.sc_parent = uha->parent; + sc->sc_hdev.sc_report_id = uha->reportid; + sc->sc_num_sensors = 0; + + uhidev_get_report_desc(uha->parent, &desc, &size); + repid = uha->reportid; + sc->sc_ilen = hid_report_size(desc, size, hid_input, repid); + sc->sc_olen = hid_report_size(desc, size, hid_output, repid); + sc->sc_flen = hid_report_size(desc, size, hid_feature, repid); + + usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, + sc->sc_hdev.sc_dev); + + if (sc->sc_flen < 32) { + /* not sensor interface, just attach */ + return; + } + + sc->sc_sensortype = uthum_check_sensortype(sc); + + /* attach sensor */ + sc->sc_sme = sysmon_envsys_create(); + sc->sc_sme->sme_name = device_xname(self); + + switch (sc->sc_sensortype) { + case UTHUM_TYPE_SHT1x: + (void)strlcpy(sc->sc_sensor[UTHUM_TEMP].desc, "temp", + sizeof(sc->sc_sensor[UTHUM_TEMP].desc)); + sc->sc_sensor[UTHUM_TEMP].units = ENVSYS_STEMP; + sc->sc_sensor[UTHUM_TEMP].state = ENVSYS_SINVALID; + + (void)strlcpy(sc->sc_sensor[UTHUM_HUMIDITY].desc, "humidity", + sizeof(sc->sc_sensor[UTHUM_HUMIDITY].desc)); + sc->sc_sensor[UTHUM_HUMIDITY].units = ENVSYS_INTEGER; + sc->sc_sensor[UTHUM_HUMIDITY].value_cur = 0; + sc->sc_sensor[UTHUM_HUMIDITY].state = ENVSYS_SINVALID; + + sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[UTHUM_TEMP]); + sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[UTHUM_HUMIDITY]); + sc->sc_num_sensors = 2; + DPRINTF(("sensor type: SHT1x\n")); + break; + case UTHUM_TYPE_TEMPER: + (void)strlcpy(sc->sc_sensor[UTHUM_TEMP].desc, "temp", + sizeof(sc->sc_sensor[UTHUM_TEMP].desc)); + sc->sc_sensor[UTHUM_TEMP].units = ENVSYS_STEMP; + sc->sc_sensor[UTHUM_TEMP].state = ENVSYS_SINVALID; + + sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor[UTHUM_TEMP]); + sc->sc_num_sensors = 1; + DPRINTF(("sensor type: TEMPer\n")); + break; + case UTHUM_TYPE_UNKNOWN: + DPRINTF(("sensor type: unknown, give up to attach sensors\n")); + default: + break; + } + + if (sc->sc_num_sensors > 0) { + sc->sc_sme->sme_cookie = sc; + sc->sc_sme->sme_refresh = uthum_refresh; + + if (sysmon_envsys_register(sc->sc_sme)) { + aprint_error_dev(self, "unable to register with sysmon\n"); + sysmon_envsys_destroy(sc->sc_sme); + } + } else { + sysmon_envsys_destroy(sc->sc_sme); + } + + DPRINTF(("uthum_attach: complete\n")); +} + +USB_DETACH(uthum) +{ + USB_DETACH_START(uthum, sc); + int rv = 0; + + sc->sc_dying = 1; + + if (sc->sc_num_sensors > 0) { + sysmon_envsys_unregister(sc->sc_sme); + } + + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, + sc->sc_hdev.sc_dev); + + return (rv); +} + +int +uthum_activate(device_t self, enum devact act) +{ + struct uthum_softc *sc = device_private(self); + + switch (act) { + case DVACT_DEACTIVATE: + sc->sc_dying = 1; + break; + } + return (0); +} + +void +uthum_intr(struct uhidev *addr, void *ibuf, u_int len) +{ + /* do nothing */ +} + +int +uthum_read_data(struct uthum_softc *sc, uint8_t target_cmd, uint8_t *buf, + size_t len, int delay) +{ + int i; + uint8_t cmdbuf[32], report[256]; + + /* if return buffer is null, do nothing */ + if ((buf == NULL) || len == 0) + return 0; + + /* issue query */ + bzero(cmdbuf, sizeof(cmdbuf)); + memcpy(cmdbuf, cmd_start, sizeof(cmd_start)); + if (uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT, + cmdbuf, sc->sc_olen)) + return EIO; + + bzero(cmdbuf, sizeof(cmdbuf)); + cmdbuf[0] = target_cmd; + if (uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT, + cmdbuf, sc->sc_olen)) + return EIO; + + bzero(cmdbuf, sizeof(cmdbuf)); + for (i = 0; i < 7; i++) { + if (uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT, + cmdbuf, sc->sc_olen)) + return EIO; + } + memcpy(cmdbuf, cmd_end, sizeof(cmd_end)); + if (uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT, + cmdbuf, sc->sc_olen)) + return EIO; + + /* wait if required */ + if (delay > 1) + tsleep(&sc->sc_sme, 0, "uthum", (delay*hz+999)/1000 + 1); + + /* get answer */ + if (uhidev_get_report(&sc->sc_hdev, UHID_FEATURE_REPORT, + report, sc->sc_flen)) + return EIO; + memcpy(buf, report, len); + return 0; +} + +int +uthum_check_sensortype(struct uthum_softc *sc) +{ + uint8_t buf[8]; + static uint8_t sht1x_sig[] = + { 0x57, 0x5a, 0x13, 0x00, 0x14, 0x00, 0x53, 0x00 }; + static uint8_t temper_sig[] = + { 0x57, 0x58, 0x14, 0x00, 0x14, 0x00, 0x53, 0x00 }; + + if (uthum_read_data(sc, CMD_DEVTYPE, buf, sizeof(buf), 0) != 0) { + DPRINTF(("uthum: read fail\n")); + return UTHUM_TYPE_UNKNOWN; + } + + /* + * currently we have not enough information about the return value, + * therefore, compare full bytes. + * TEMPerHUM HID (SHT1x version) will return: + * { 0x57, 0x5a, 0x13, 0x00, 0x14, 0x00, 0x53, 0x00 } + * TEMPer HID (SHT1x version) will return: + * { 0x57, 0x58, 0x14, 0x00, 0x14, 0x00, 0x53, 0x00 } + */ + if (0 == memcmp(buf, sht1x_sig, sizeof(sht1x_sig))) + return UTHUM_TYPE_SHT1x; + if (0 == memcmp(buf, temper_sig, sizeof(temper_sig))) + return UTHUM_TYPE_TEMPER; + + return UTHUM_TYPE_UNKNOWN; +} + + +static void +uthum_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) +{ + struct uthum_softc *sc = sme->sme_cookie; + uint8_t buf[8]; + unsigned int temp_tick, humidity_tick; + int temp, rh; + + switch (sc->sc_sensortype) { + case UTHUM_TYPE_SHT1x: + if (uthum_read_data(sc, CMD_GETDATA, buf, sizeof(buf), 1000) != 0) { + DPRINTF(("uthum: data read fail\n")); + sc->sc_sensor[UTHUM_TEMP].state = ENVSYS_SINVALID; + sc->sc_sensor[UTHUM_HUMIDITY].state = ENVSYS_SINVALID; + return; + } + + temp_tick = (buf[0] * 256 + buf[1]) & 0x3fff; + humidity_tick = (buf[2] * 256 + buf[3]) & 0x0fff; + + temp = uthum_sht1x_temp(temp_tick); + rh = uthum_sht1x_rh(humidity_tick, temp); + + sc->sc_sensor[UTHUM_HUMIDITY].value_cur = rh; + sc->sc_sensor[UTHUM_HUMIDITY].state = ENVSYS_SVALID; + break; + case UTHUM_TYPE_TEMPER: + if (uthum_read_data(sc, CMD_GETTEMP, buf, sizeof(buf), 0) != 0) { + DPRINTF(("uthum: data read fail\n")); + sc->sc_sensor[UTHUM_TEMP].state = ENVSYS_SINVALID; + return; + } + temp_tick = (buf[0] * 256 + buf[1]) & 0xffff; + temp = uthum_sht1x_temp(temp_tick); + break; + default: + /* do nothing */ + return; + } + + sc->sc_sensor[UTHUM_TEMP].value_cur = (temp * 10000) + 273150000; + sc->sc_sensor[UTHUM_TEMP].state = ENVSYS_SVALID; +} + +/* return C-degree * 100 value */ +int +uthum_sht1x_temp(unsigned int ticks) +{ + return (ticks - 4010); +} + +/* return %RH * 1000 */ +int +uthum_sht1x_rh(unsigned int ticks, int temp) +{ + int rh_l, rh; + + rh_l = (-40000 + 405 * ticks) - ((7 * ticks * ticks) / 250); + rh = ((temp - 2500) * (1 + (ticks >> 7)) + rh_l) / 10; + return rh; +}
Attachment:
pgpAMyhq_9W5K.pgp
Description: PGP signature