On Sun, Jul 05, 2015 at 10:14:39AM +0100, Raf Czlonka wrote: > On Sun, Jul 05, 2015 at 09:10:17AM BST, Joerg Jung wrote: > > > It looks like your newer RDing TEMPERHUM1V1.2 has a different > > chip. As far as Google knows, it seems to be a si7006, which requires > > a slightly different formula with the temperature and humidity > > readings. Also, in contrast to the si7005 (of TEMPERHUM1V1.0), the > > linearization and compensation seems not to be needed. > > Unfortunately there's nothing on the casing which would identify the > chip and I'd rather not take it apart ;^) > > I gather that linearisation and compensation not being needed is a good > thing so it seems that getting this version wasn't all that bad :^) > > > I will try to come up with a better diff making your device work > > correctly. > > I'd be much obliged.
Can you try the diff below please and check if your si7006 is detected and working? Thanks, Regards, Joerg Index: sys/dev/usb/ugold.c =================================================================== RCS file: /cvs/src/sys/dev/usb/ugold.c,v retrieving revision 1.7 diff -u -p -r1.7 ugold.c --- sys/dev/usb/ugold.c 11 Dec 2014 18:39:27 -0000 1.7 +++ sys/dev/usb/ugold.c 11 Jul 2015 07:40:47 -0000 @@ -3,6 +3,7 @@ /* * Copyright (c) 2013 Takayoshi SASANO <[email protected]> * Copyright (c) 2013 Martin Pieuchot <[email protected]> + * Copyright (c) 2015 Joerg Jung <[email protected]> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,7 +18,10 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* Driver for Microdia's HID base TEMPer Temperature sensor */ +/* + * Driver for Microdia's HID base TEMPer and TEMPerHUM temperature and + * humididty sensors + */ #include <sys/param.h> #include <sys/systm.h> @@ -36,14 +40,17 @@ #define UGOLD_INNER 0 #define UGOLD_OUTER 1 +#define UGOLD_HUM 1 #define UGOLD_MAX_SENSORS 2 #define UGOLD_CMD_DATA 0x80 #define UGOLD_CMD_INIT 0x82 +#define UGOLD_TYPE_SI7005 1 +#define UGOLD_TYPE_SI7006 2 + /* - * This driver only uses two of the three known commands for the - * TEMPerV1.2 device. + * This driver uses three known commands for the TEMPerV1.2 device. * * The first byte of the answer corresponds to the command and the * second one seems to be the size (in bytes) of the answer. @@ -59,15 +66,14 @@ */ static uint8_t cmd_data[8] = { 0x01, 0x80, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00 }; static uint8_t cmd_init[8] = { 0x01, 0x82, 0x77, 0x01, 0x00, 0x00, 0x00, 0x00 }; -#if 0 static uint8_t cmd_type[8] = { 0x01, 0x86, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00 }; -#endif struct ugold_softc { struct uhidev sc_hdev; struct usbd_device *sc_udev; int sc_num_sensors; + int sc_type; struct ksensor sc_sensor[UGOLD_MAX_SENSORS]; struct ksensordev sc_sensordev; @@ -76,13 +82,15 @@ struct ugold_softc { const struct usb_devno ugold_devs[] = { { USB_VENDOR_MICRODIA, USB_PRODUCT_MICRODIA_TEMPER }, + { USB_VENDOR_MICRODIA, USB_PRODUCT_MICRODIA_TEMPERHUM }, }; int ugold_match(struct device *, void *, void *); void ugold_attach(struct device *, struct device *, void *); int ugold_detach(struct device *, int); -void ugold_intr(struct uhidev *, void *, u_int); +void ugold_ds75_intr(struct uhidev *, void *, u_int); +void ugold_si700x_intr(struct uhidev *, void *, u_int); void ugold_refresh(void *); int ugold_issue_cmd(struct ugold_softc *, uint8_t *, int); @@ -132,9 +140,16 @@ ugold_attach(struct device *parent, stru void *desc; sc->sc_udev = uha->parent->sc_udev; - sc->sc_hdev.sc_intr = ugold_intr; sc->sc_hdev.sc_parent = uha->parent; sc->sc_hdev.sc_report_id = uha->reportid; + switch (uha->uaa->product) { + case USB_PRODUCT_MICRODIA_TEMPER: + sc->sc_hdev.sc_intr = ugold_ds75_intr; + break; + case USB_PRODUCT_MICRODIA_TEMPERHUM: + sc->sc_hdev.sc_intr = ugold_si700x_intr; + break; + } uhidev_get_report_desc(uha->parent, &desc, &size); repid = uha->reportid; @@ -150,13 +165,26 @@ ugold_attach(struct device *parent, stru strlcpy(sc->sc_sensordev.xname, sc->sc_hdev.sc_dev.dv_xname, sizeof(sc->sc_sensordev.xname)); - sc->sc_sensor[UGOLD_OUTER].type = SENSOR_TEMP; - strlcpy(sc->sc_sensor[UGOLD_OUTER].desc, "outer", - sizeof(sc->sc_sensor[UGOLD_OUTER].desc)); - - sc->sc_sensor[UGOLD_INNER].type = SENSOR_TEMP; - strlcpy(sc->sc_sensor[UGOLD_INNER].desc, "inner", - sizeof(sc->sc_sensor[UGOLD_INNER].desc)); + switch (uha->uaa->product) { + case USB_PRODUCT_MICRODIA_TEMPER: + /* 2 temperature sensors */ + sc->sc_sensor[UGOLD_INNER].type = SENSOR_TEMP; + strlcpy(sc->sc_sensor[UGOLD_INNER].desc, "inner", + sizeof(sc->sc_sensor[UGOLD_INNER].desc)); + sc->sc_sensor[UGOLD_OUTER].type = SENSOR_TEMP; + strlcpy(sc->sc_sensor[UGOLD_OUTER].desc, "outer", + sizeof(sc->sc_sensor[UGOLD_OUTER].desc)); + break; + case USB_PRODUCT_MICRODIA_TEMPERHUM: + /* 1 temperature and 1 humidity sensor */ + sc->sc_sensor[UGOLD_INNER].type = SENSOR_TEMP; + strlcpy(sc->sc_sensor[UGOLD_INNER].desc, "inner", + sizeof(sc->sc_sensor[UGOLD_INNER].desc)); + sc->sc_sensor[UGOLD_HUM].type = SENSOR_HUMIDITY; + strlcpy(sc->sc_sensor[UGOLD_HUM].desc, "RH", + sizeof(sc->sc_sensor[UGOLD_HUM].desc)); + break; + } /* 0.1Hz */ sc->sc_sensortask = sensor_task_register(sc, ugold_refresh, 6); @@ -192,12 +220,12 @@ ugold_detach(struct device *self, int fl static int ugold_ds75_temp(uint8_t msb, uint8_t lsb) { - /* DS75: 12bit precision mode : 0.0625 degrees Celsius ticks */ + /* DS75 12bit precision mode: 0.0625 degrees Celsius ticks */ return (((msb * 100) + ((lsb >> 4) * 25 / 4)) * 10000) + 273150000; } void -ugold_intr(struct uhidev *addr, void *ibuf, u_int len) +ugold_ds75_intr(struct uhidev *addr, void *ibuf, u_int len) { struct ugold_softc *sc = (struct ugold_softc *)addr; uint8_t *buf = ibuf; @@ -237,6 +265,115 @@ ugold_intr(struct uhidev *addr, void *ib } break; default: + if (!sc->sc_type) /* ignore type command result */ + break; + printf("%s: unknown command 0x%02x\n", + sc->sc_hdev.sc_dev.dv_xname, buf[0]); + } +} + +static int +ugold_si700x_temp(int type, uint8_t msb, uint8_t lsb) +{ + int temp = (msb * 256 + lsb) & 0x3fff; /* 14bit si700x */ + + /* convert to mdegC */ + switch (type) { + case UGOLD_TYPE_SI7005: /* 32 codes per degC, 0x0000 = -50 degC */ + temp = ((temp * 1000) / 32) - (50 * 1000); + break; + case UGOLD_TYPE_SI7006: + temp = ((temp * 175720) / 65536) - (46850); + break; + } + return temp; +} + +static int +ugold_si700x_rhum(int type, uint8_t msb, uint8_t lsb, int temp) +{ + int rhum; + + /* convert to m%RH */ + switch (type) { + case UGOLD_TYPE_SI7005: /* 12bit si7005 */ + rhum = (msb * 256 + lsb) & 0x0fff; + /* 16 codes per %RH, 0x0000 = -24%RH */ + rhum = ((rhum * 1000) / 16) - (24 * 1000); +#if 0 /* todo: linearization and temperature compensation */ + rhum -= -0.00393 * rhum * rhum + 0.4008 * rhum - 4.7844; + rhum += (temp - 30) * (0.00237 * rhum + 0.1973); +#endif + break; + case UGOLD_TYPE_SI7006: /* 14bit si7006 */ + rhum = (msb * 256 + lsb) & 0x3fff; + rhum = ((rhum * 125000) / 65536) - (6 * 1000); + break; + } + + /* limit the humidity to valid values */ + if (rhum < 0) + rhum = 0; + else if (rhum > 100000) + rhum = 100000; + return rhum; +} + + +static void +ugold_si700x_type(struct ugold_softc *sc, uint8_t *buf, u_int len) +{ + if (memcmp(buf, "TEMPerHu", len) == 0) + return; /* skip equal first half of the answer */ + + printf("%s: %d sensor%s type ", sc->sc_hdev.sc_dev.dv_xname, + sc->sc_num_sensors, (sc->sc_num_sensors == 1) ? "" : "s"); + + if (memcmp(buf, "mM12V1.0", len) == 0) { + sc->sc_type = UGOLD_TYPE_SI7005; + printf("si7005 (temperature and humidity)\n"); + } else if (memcmp(buf, "mM12V1.2", len) == 0) { + sc->sc_type = UGOLD_TYPE_SI7006; + printf("si7006 (temperature and humidity)\n"); + } else + printf("unknown\n"); +} + +void +ugold_si700x_intr(struct uhidev *addr, void *ibuf, u_int len) +{ + struct ugold_softc *sc = (struct ugold_softc *)addr; + uint8_t *buf = ibuf; + int i, temp, rhum; + + switch (buf[0]) { + case UGOLD_CMD_INIT: + if (sc->sc_num_sensors) + break; + + sc->sc_num_sensors = min(buf[1], UGOLD_MAX_SENSORS) /* XXX */; + + for (i = 0; i < sc->sc_num_sensors; i++) { + sc->sc_sensor[i].flags |= SENSOR_FINVALID; + sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); + } + break; + case UGOLD_CMD_DATA: + if (buf[1] != 4) + printf("%s: invalid data length (%d bytes)\n", + sc->sc_hdev.sc_dev.dv_xname, buf[1]); + temp = ugold_si700x_temp(sc->sc_type, buf[2], buf[3]); + sc->sc_sensor[UGOLD_INNER].value = (temp * 1000) + 273150000; + sc->sc_sensor[UGOLD_INNER].flags &= ~SENSOR_FINVALID; + rhum = ugold_si700x_rhum(sc->sc_type, buf[4], buf[5], temp); + sc->sc_sensor[UGOLD_HUM].value = rhum; + sc->sc_sensor[UGOLD_HUM].flags &= ~SENSOR_FINVALID; + break; + default: + if (!sc->sc_type) { /* type command returns arbitrary string */ + ugold_si700x_type(sc, buf, len); + break; + } printf("%s: unknown command 0x%02x\n", sc->sc_hdev.sc_dev.dv_xname, buf[0]); } @@ -248,8 +385,10 @@ ugold_refresh(void *arg) struct ugold_softc *sc = arg; int i; - if (sc->sc_num_sensors == 0) + if (sc->sc_num_sensors == 0) { ugold_issue_cmd(sc, cmd_init, sizeof(cmd_init)); + ugold_issue_cmd(sc, cmd_type, sizeof(cmd_type)); + } if (ugold_issue_cmd(sc, cmd_data, sizeof(cmd_data))) { for (i = 0; i < sc->sc_num_sensors; i++)
