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++)

Reply via email to