summaryrefslogtreecommitdiff
path: root/sys/dev/usb/uthum.c
diff options
context:
space:
mode:
authorYojiro Uo <yuo@cvs.openbsd.org>2010-04-15 09:42:52 +0000
committerYojiro Uo <yuo@cvs.openbsd.org>2010-04-15 09:42:52 +0000
commit63d7be1d8c75efdff08a1e0019a38b658bdfad88 (patch)
tree50cc63fe32b9555f8e2b1e1e2146aa2ce778c162 /sys/dev/usb/uthum.c
parent236bc00af72440eff6bb011c46f762ba0b328804 (diff)
use SENSOR_HUMIDITY instead of SENSOR_PERCENT.
support new TEMPer sensors: TEMPer, TEMPer1, TEMPer2, TEMPerNTC ok jsg@, deraadt@
Diffstat (limited to 'sys/dev/usb/uthum.c')
-rw-r--r--sys/dev/usb/uthum.c680
1 files changed, 568 insertions, 112 deletions
diff --git a/sys/dev/usb/uthum.c b/sys/dev/usb/uthum.c
index 7bda0030e72..48a7f7ab396 100644
--- a/sys/dev/usb/uthum.c
+++ b/sys/dev/usb/uthum.c
@@ -1,7 +1,7 @@
-/* $OpenBSD: uthum.c,v 1.8 2010/02/18 23:34:05 deraadt Exp $ */
+/* $OpenBSD: uthum.c,v 1.9 2010/04/15 09:42:51 yuo Exp $ */
/*
- * Copyright (c) 2009 Yojiro UO <yuo@nui.org>
+ * Copyright (c) 2009, 2010 Yojiro UO <yuo@nui.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -16,7 +16,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* Driver for TEMPerHUM HID */
+/* Driver for HID base TEMPer seriese Temperature(/Humidity) sensors */
#include <sys/param.h>
#include <sys/proc.h>
@@ -48,29 +48,78 @@ int uthumdebug = 0;
#define DPRINTF(x) DPRINTFN(0, x)
+/* Device types */
+#define UTHUM_TYPE_TEMPERHUM 0x535a
+#define UTHUM_TYPE_TEMPER1 0x5758 /* TEMPer1 and HID TEMPer */
+#define UTHUM_TYPE_TEMPER2 0x5759
+#define UTHUM_TYPE_TEMPERNTC 0x575b
+#define UTHUM_TYPE_UNKNOWN 0xffff
-/* TEMPerHUM */
-#define CMD_DEVTYPE 0x52 /* XXX */
-#define CMD_GETDATA 0x48 /* XXX */
-static uint8_t cmd_start[8] =
+/* Common */
+#define UTHUM_CAL_OFFSET 0x14
+#define UTHUM_MAX_SENSORS 2
+#define CMD_DEVTYPE 0x52
+#define DEVTYPE_EOF 0x53
+
+/* query commands */
+#define CMD_GETDATA_NTC 0x41 /* TEMPerNTC NTC part */
+#define CMD_RESET0 0x43 /* TEMPer, TEMPer[12], TEMPerNTC */
+#define CMD_RESET1 0x44 /* TEMPer, TEMPer[12] */
+#define CMD_GETDATA 0x48 /* TEMPerHUM */
+#define CMD_GETDATA_OUTER 0x53 /* TEMPer, TEMPer[12], TEMPerNTC */
+#define CMD_GETDATA_INNER 0x54 /* TEMPer, TEMPer[12], TEMPerNTC */
+#define CMD_GETDATA_EOF 0x31
+#define CMD_GETDATA_EOF2 0xaa
+
+/* temperntc mode */
+#define TEMPERNTC_MODE_BASE 0x61 /* 0x61 - 0x68 */
+#define TEMPERNTC_MODE_MAX 0x68
+#define CMD_TEMPERNTC_MODE_DONE 0x69
+#define UTHUM_NTC_MIN_THRESHOLD 0xb300
+#define UTHUM_NTC_MAX_THRESHOLD 0xf200
+
+/* sensor name */
+#define UTHUM_TEMPER_INNER 0
+#define UTHUM_TEMPER_OUTER 1
+#define UTHUM_TEMPER_NTC 1
+#define UTHUM_TEMPERHUM_TEMP 0
+#define UTHUM_TEMPERHUM_HUM 1
+
+enum uthum_sensor_type {
+ UTHUM_SENSOR_UNKNOWN,
+ UTHUM_SENSOR_SHT1X,
+ UTHUM_SENSOR_DS75,
+ UTHUM_SENSOR_NTC,
+ UTHUM_SENSOR_MAXTYPES,
+};
+
+static const char * const uthum_sensor_type_s[UTHUM_SENSOR_MAXTYPES] = {
+ "unknown",
+ "sht1x",
+ "ds75/12bit",
+ "NTC"
+};
+
+static uint8_t cmd_issue[8] =
{ 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00, 0x02, 0x00 };
-static uint8_t cmd_end[8] =
+static uint8_t cmd_query[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
+struct uthum_sensor {
+ struct ksensor sensor;
+ int cal_offset; /* mC or m%RH */
+ int attached;
+ enum uthum_sensor_type dev_type;
+ int cur_state; /* for TEMPerNTC */
+};
struct uthum_softc {
struct uhidev sc_hdev;
usbd_device_handle sc_udev;
u_char sc_dying;
uint16_t sc_flag;
- int sc_sensortype;
+ int sc_device_type;
+ int sc_num_sensors;
/* uhidev parameters */
size_t sc_flen; /* feature report length */
@@ -78,32 +127,40 @@ struct uthum_softc {
size_t sc_olen; /* output report length */
/* sensor framework */
- struct ksensor sc_sensor[UTHUM_MAX_SENSORS];
+ struct uthum_sensor sc_sensor[UTHUM_MAX_SENSORS];
struct ksensordev sc_sensordev;
struct sensor_task *sc_sensortask;
-
- uint8_t sc_num_sensors;
};
-
const struct usb_devno uthum_devs[] = {
- /* XXX: various TEMPer variants using same VID/PID */
+ /* XXX: various TEMPer variants are 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(struct device *, void *, void *);
+int uthum_match(struct device *, void *, void *);
void uthum_attach(struct device *, struct device *, void *);
-int uthum_detach(struct device *, int);
-int uthum_activate(struct device *, int);
+int uthum_detach(struct device *, int);
+int uthum_activate(struct device *, int);
-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);
+int uthum_issue_cmd(struct uthum_softc *, uint8_t, int);
+int uthum_read_data(struct uthum_softc *, uint8_t, uint8_t *, size_t, int);
+int uthum_check_device_info(struct uthum_softc *);
+void uthum_setup_sensors(struct uthum_softc *);
void uthum_intr(struct uhidev *, void *, u_int);
void uthum_refresh(void *);
+void uthum_refresh_temper(struct uthum_softc *, int);
+void uthum_refresh_temperhum(struct uthum_softc *);
+void uthum_refresh_temperntc(struct uthum_softc *, int);
+
+int uthum_ntc_getdata(struct uthum_softc *, int *);
+int uthum_ntc_tuning(struct uthum_softc *, int, int *);
+int64_t uthum_ntc_temp(int64_t, int);
+int uthum_sht1x_temp(uint8_t, uint8_t);
+int uthum_sht1x_rh(uint8_t, uint8_t, int);
+int uthum_ds75_temp(uint8_t, uint8_t);
+void uthum_print_sensorinfo(struct uthum_softc *, int);
struct cfdriver uthum_cd = {
NULL, "uthum", DV_DULL
@@ -147,7 +204,7 @@ uthum_attach(struct device *parent, struct device *self, void *aux)
struct usb_attach_arg *uaa = aux;
struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
usbd_device_handle dev = uha->parent->sc_udev;
- int size, repid;
+ int i, size, repid;
void *desc;
sc->sc_udev = dev;
@@ -171,35 +228,30 @@ uthum_attach(struct device *parent, struct device *self, void *aux)
return;
}
- sc->sc_sensortype = uthum_check_sensortype(sc);
+ /* maybe unsupported device */
+ if (uthum_check_device_info(sc) < 0) {
+ DPRINTF(("uthum: unknown device\n"));
+ return;
+ };
/* attach sensor */
strlcpy(sc->sc_sensordev.xname, sc->sc_hdev.sc_dev.dv_xname,
sizeof(sc->sc_sensordev.xname));
-
- switch (sc->sc_sensortype) {
- case UTHUM_TYPE_SHT1x:
- sc->sc_sensor[UTHUM_TEMP].type = SENSOR_TEMP;
- sc->sc_sensor[UTHUM_TEMP].flags = SENSOR_FINVALID;
-
- strlcpy(sc->sc_sensor[UTHUM_HUMIDITY].desc, "humidity",
- sizeof(sc->sc_sensor[UTHUM_HUMIDITY].desc));
- sc->sc_sensor[UTHUM_HUMIDITY].type = SENSOR_PERCENT;
- sc->sc_sensor[UTHUM_HUMIDITY].flags = SENSOR_FINVALID;
-
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[UTHUM_TEMP]);
- sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[UTHUM_HUMIDITY]);
- sc->sc_num_sensors = 2;
- DPRINTF(("%s: sensor type: SHT1x\n"));
- break;
- case UTHUM_TYPE_UNKNOWN:
- DPRINTF(("%s: sensor type: unknown, give up to attach sensors\n"));
- default:
- break;
+ uthum_setup_sensors(sc);
+
+ /* attach sensors */
+ for (i = 0; i < UTHUM_MAX_SENSORS; i++) {
+ if (sc->sc_sensor[i].dev_type == UTHUM_SENSOR_UNKNOWN)
+ continue;
+ uthum_print_sensorinfo(sc, i);
+ sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i].sensor);
+ sc->sc_sensor[i].attached = 1;
+ sc->sc_num_sensors++;
}
if (sc->sc_num_sensors > 0) {
- sc->sc_sensortask = sensor_task_register(sc, uthum_refresh, 20);
+ /* 0.1Hz */
+ sc->sc_sensortask = sensor_task_register(sc, uthum_refresh, 6);
if (sc->sc_sensortask == NULL) {
printf(", unable to register update task\n");
return;
@@ -221,8 +273,11 @@ uthum_detach(struct device *self, int flags)
if (sc->sc_num_sensors > 0) {
wakeup(&sc->sc_sensortask);
sensordev_deinstall(&sc->sc_sensordev);
- for (i = 0; i < sc->sc_num_sensors; i++)
- sensor_detach(&sc->sc_sensordev, &sc->sc_sensor[i]);
+ for (i = 0; i < UTHUM_MAX_SENSORS; i++) {
+ if (sc->sc_sensor[i].attached)
+ sensor_detach(&sc->sc_sensordev,
+ &sc->sc_sensor[i].sensor);
+ }
if (sc->sc_sensortask != NULL)
sensor_task_unregister(sc->sc_sensortask);
}
@@ -256,19 +311,13 @@ uthum_intr(struct uhidev *addr, void *ibuf, u_int len)
}
int
-uthum_read_data(struct uthum_softc *sc, uint8_t target_cmd, uint8_t *buf,
- size_t len, int delay)
+uthum_issue_cmd(struct uthum_softc *sc, uint8_t target_cmd, int delay)
{
int i;
- uint8_t cmdbuf[32], report[256];
+ uint8_t cmdbuf[32];
- /* 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));
+ memcpy(cmdbuf, cmd_issue, sizeof(cmd_issue));
if (uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT,
cmdbuf, sc->sc_olen))
return EIO;
@@ -285,7 +334,29 @@ uthum_read_data(struct uthum_softc *sc, uint8_t target_cmd, uint8_t *buf,
cmdbuf, sc->sc_olen))
return EIO;
}
- memcpy(cmdbuf, cmd_end, sizeof(cmd_end));
+
+ /* wait if required */
+ if (delay > 0)
+ tsleep(&sc->sc_sensortask, 0, "uthum", (delay*hz+999)/1000 + 1);
+
+ return 0;
+}
+
+int
+uthum_read_data(struct uthum_softc *sc, uint8_t target_cmd, uint8_t *buf,
+ size_t len, int delay)
+{
+ uint8_t cmdbuf[32], report[256];
+
+ /* if return buffer is null, do nothing */
+ if ((buf == NULL) || len == 0)
+ return 0;
+
+ if (uthum_issue_cmd(sc, target_cmd, 50))
+ return 0;
+
+ bzero(cmdbuf, sizeof(cmdbuf));
+ memcpy(cmdbuf, cmd_query, sizeof(cmd_query));
if (uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT,
cmdbuf, sc->sc_olen))
return EIO;
@@ -303,91 +374,476 @@ uthum_read_data(struct uthum_softc *sc, uint8_t target_cmd, uint8_t *buf,
}
int
-uthum_check_sensortype(struct uthum_softc *sc)
+uthum_check_device_info(struct uthum_softc *sc)
{
- uint8_t buf[8];
- static uint8_t sht1x_sig[] =
- { 0x57, 0x5a, 0x13, 0x00, 0x14, 0x00, 0x53, 0x00 };
+ struct uthum_dev_info {
+ uint16_t dev_type;
+ uint8_t cal[2][2]; /* calibration offsets */
+ uint8_t footer;
+ uint8_t padding[25];
+ } dinfo;
+ int val, dev_type;
+ int retry = 3;
+
+ /* issue query to device */
+ while (retry) {
+ if (uthum_read_data(sc, CMD_DEVTYPE, (void *)&dinfo,
+ sizeof(struct uthum_dev_info), 0) != 0) {
+ DPRINTF(("uthum: device information query fail.\n"));
+ retry--;
+ continue;
+ }
+ if (dinfo.footer != DEVTYPE_EOF) {
+ /* it will be a bogus entry, retry. */
+ retry--;
+ } else
+ break;
+ }
+
+ if (retry < 0)
+ return EIO;
- if (uthum_read_data(sc, CMD_DEVTYPE, buf, sizeof(buf), 0) != 0) {
- DPRINTF(("uthum: read fail\n"));
- return UTHUM_TYPE_UNKNOWN;
+ dev_type = betoh16(dinfo.dev_type);
+
+ /* check device type and calibration offset*/
+ switch (dev_type) {
+ case UTHUM_TYPE_TEMPER2:
+ case UTHUM_TYPE_TEMPERHUM:
+ case UTHUM_TYPE_TEMPERNTC:
+ val = (dinfo.cal[1][0] - UTHUM_CAL_OFFSET) * 100;
+ val += dinfo.cal[1][1] * 10;
+ sc->sc_sensor[1].cal_offset = val;
+ /* fall down, don't break */
+ case UTHUM_TYPE_TEMPER1:
+ val = (dinfo.cal[0][0] - UTHUM_CAL_OFFSET) * 100;
+ val += dinfo.cal[0][1] * 10;
+ sc->sc_sensor[0].cal_offset = val;
+ sc->sc_device_type = dev_type;
+ break;
+ default:
+ sc->sc_device_type = UTHUM_TYPE_UNKNOWN;
+ printf("uthum: unknown device (devtype = 0x%.2x)\n",
+ dev_type);
+ return EIO;
}
- /*
- * 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 }
- */
- if (memcmp(buf, sht1x_sig, sizeof(sht1x_sig)))
- return UTHUM_TYPE_SHT1x;
+ /* device specific init process */
+ switch (dev_type) {
+ case UTHUM_TYPE_TEMPER1:
+ case UTHUM_TYPE_TEMPERNTC:
+ uthum_issue_cmd(sc, CMD_RESET0, 200);
+ break;
+ case UTHUM_TYPE_TEMPER2:
+ uthum_issue_cmd(sc, CMD_RESET0, 200);
+ uthum_issue_cmd(sc, CMD_RESET1, 200);
+ break;
+ case UTHUM_TYPE_TEMPERHUM:
+ sc->sc_sensor[UTHUM_TEMPER_NTC].cur_state = 0;
+ break;
+ };
+
+ return 0;
+};
+
+void
+uthum_setup_sensors(struct uthum_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < UTHUM_MAX_SENSORS; i++)
+ sc->sc_sensor[i].dev_type = UTHUM_SENSOR_UNKNOWN;
+
+ switch (sc->sc_device_type) {
+ case UTHUM_TYPE_TEMPER2: /* 2 temperature sensors */
+ sc->sc_sensor[UTHUM_TEMPER_OUTER].dev_type =
+ UTHUM_SENSOR_DS75;
+ sc->sc_sensor[UTHUM_TEMPER_OUTER].sensor.type =
+ SENSOR_TEMP;
+ strlcpy(sc->sc_sensor[UTHUM_TEMPER_OUTER].sensor.desc,
+ "outer",
+ sizeof(sc->sc_sensor[UTHUM_TEMPER_OUTER].sensor.desc));
+ /* fall down */
+ case UTHUM_TYPE_TEMPER1: /* 1 temperature sensor */
+ sc->sc_sensor[UTHUM_TEMPER_INNER].dev_type =
+ UTHUM_SENSOR_DS75;
+ sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.type =
+ SENSOR_TEMP;
+ strlcpy(sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.desc,
+ "inner",
+ sizeof(sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.desc));
+ break;
+ case UTHUM_TYPE_TEMPERHUM:
+ /* 1 temperature sensor and 1 humidity sensor */
+ for (i = 0; i < 2; i++)
+ sc->sc_sensor[i].dev_type = UTHUM_SENSOR_SHT1X;
+ sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].sensor.type = SENSOR_TEMP;
+ sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.type =
+ SENSOR_HUMIDITY;
+ strlcpy(sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.desc,
+ "RH",
+ sizeof(sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.desc));
+ break;
+ case UTHUM_TYPE_TEMPERNTC:
+ /* 2 temperature sensors */
+ for (i = 0; i < 2; i++)
+ sc->sc_sensor[i].sensor.type = SENSOR_TEMP;
+ sc->sc_sensor[UTHUM_TEMPER_INNER].dev_type =
+ UTHUM_SENSOR_DS75;
+ sc->sc_sensor[UTHUM_TEMPER_NTC].dev_type =
+ UTHUM_SENSOR_NTC;
+ strlcpy(sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.desc,
+ "inner",
+ sizeof(sc->sc_sensor[UTHUM_TEMPER_INNER].sensor.desc));
+ strlcpy(sc->sc_sensor[UTHUM_TEMPER_NTC].sensor.desc,
+ "outer/ntc",
+ sizeof(sc->sc_sensor[UTHUM_TEMPER_NTC].sensor.desc));
+
+ /* sensor state tuning */
+ for (i = 0; i < 4; i++)
+ uthum_issue_cmd(sc, TEMPERNTC_MODE_BASE, 50);
+ sc->sc_sensor[UTHUM_TEMPER_NTC].cur_state = TEMPERNTC_MODE_BASE;
+ if (uthum_ntc_tuning(sc, UTHUM_TEMPER_NTC, NULL))
+ DPRINTF(("uthum: NTC sensor tuning failed\n"));
+ uthum_issue_cmd(sc, CMD_TEMPERNTC_MODE_DONE, 100);
+ break;
+ default:
+ /* do nothing */
+ ;;
+ }
+}
+
+int
+uthum_ntc_getdata(struct uthum_softc *sc, int *val)
+{
+ uint8_t buf[8];
+
+ if (val == NULL)
+ return EIO;
+
+ /* get sensor value */
+ if (uthum_read_data(sc, CMD_GETDATA_NTC, buf, sizeof(buf), 10) != 0) {
+ DPRINTF(("uthum: data read fail\n"));
+ return EIO;
+ }
+
+ /* check data integrity */
+ if (buf[2] != CMD_GETDATA_EOF2) {
+ DPRINTF(("uthum: broken ntc data 0x%.2x 0x%.2x 0x%.2x\n",
+ buf[0], buf[1], buf[2]));
+ return EIO;
+ }
- return UTHUM_TYPE_UNKNOWN;
+ *val = (buf[0] << 8) + buf[1];
+ return 0;
}
+int
+uthum_ntc_tuning(struct uthum_softc *sc, int sensor, int *val)
+{
+ struct uthum_sensor *s;
+ int done, state, ostate, curval;
+ int retry = 3;
+
+ s = &sc->sc_sensor[sensor];
+ state = s->cur_state;
+
+ /* get current sensor value */
+ if (val == NULL) {
+ while (retry) {
+ if (uthum_ntc_getdata(sc, &curval)) {
+ retry--;
+ continue;
+ } else
+ break;
+ }
+ if (retry < 0)
+ return EIO;
+ } else {
+ curval = *val;
+ }
+
+ /* no state change is required */
+ if ((curval >= UTHUM_NTC_MIN_THRESHOLD) &&
+ (curval <= UTHUM_NTC_MAX_THRESHOLD)) {
+ return 0;
+ }
+
+ if (((curval < UTHUM_NTC_MIN_THRESHOLD) &&
+ (state == TEMPERNTC_MODE_MAX)) ||
+ ((curval > UTHUM_NTC_MAX_THRESHOLD) &&
+ (state == TEMPERNTC_MODE_BASE)))
+ return 0;
+
+ DPRINTF(("uthum: ntc tuning start. cur state = 0x%.2x, val = 0x%.4x\n",
+ state, curval));
+
+ /* tuning loop */
+ ostate = state;
+ done = 0;
+ while (!done) {
+ if (curval < UTHUM_NTC_MIN_THRESHOLD) {
+ if (state == TEMPERNTC_MODE_MAX)
+ done++;
+ else
+ state++;
+ } else if (curval > UTHUM_NTC_MAX_THRESHOLD) {
+ if (state == TEMPERNTC_MODE_BASE)
+ done++;
+ else
+ state--;
+ } else {
+ uthum_ntc_getdata(sc, &curval);
+ if ((curval >= UTHUM_NTC_MIN_THRESHOLD) &&
+ (curval <= UTHUM_NTC_MAX_THRESHOLD))
+ done++;
+ }
+
+ /* update state */
+ if (state != ostate) {
+ uthum_issue_cmd(sc, state, 50);
+ uthum_issue_cmd(sc, state, 50);
+ uthum_ntc_getdata(sc, &curval);
+ }
+ ostate = state;
+ }
+
+ DPRINTF(("uthum: ntc tuning done. state change: 0x%.2x->0x%.2x\n",
+ s->cur_state, state));
+ s->cur_state = state;
+ if (val != NULL)
+ *val = curval;
+
+ return 0;
+}
void
uthum_refresh(void *arg)
{
struct uthum_softc *sc = arg;
+ int i;
+
+ switch (sc->sc_device_type) {
+ case UTHUM_TYPE_TEMPER1:
+ case UTHUM_TYPE_TEMPER2:
+ case UTHUM_TYPE_TEMPERNTC:
+ for (i = 0; i < sc->sc_num_sensors; i++) {
+ if (sc->sc_sensor[i].dev_type == UTHUM_SENSOR_DS75)
+ uthum_refresh_temper(sc, i);
+ else if (sc->sc_sensor[i].dev_type == UTHUM_SENSOR_NTC)
+ uthum_refresh_temperntc(sc, i);
+ }
+ break;
+ case UTHUM_TYPE_TEMPERHUM:
+ uthum_refresh_temperhum(sc);
+ break;
+ default:
+ break;
+ /* never reach */
+ }
+}
+
+void
+uthum_refresh_temperhum(struct uthum_softc *sc)
+{
uint8_t buf[8];
- unsigned int temp_tick, humidity_tick;
int temp, rh;
if (uthum_read_data(sc, CMD_GETDATA, buf, sizeof(buf), 1000) != 0) {
DPRINTF(("uthum: data read fail\n"));
- sc->sc_sensor[UTHUM_TEMP].flags |= SENSOR_FINVALID;
- sc->sc_sensor[UTHUM_HUMIDITY].flags |= SENSOR_FINVALID;
+ sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].sensor.flags
+ |= SENSOR_FINVALID;
+ sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.flags
+ |= SENSOR_FINVALID;
return;
}
- switch (sc->sc_sensortype) {
- case UTHUM_TYPE_SHT1x:
- temp_tick = (buf[0] * 256 + buf[1]) & 0x3fff;
- humidity_tick = (buf[2] * 256 + buf[3]) & 0x0fff;
+ temp = uthum_sht1x_temp(buf[0], buf[1]);
+ rh = uthum_sht1x_rh(buf[2], buf[3], temp);
- temp = uthum_sht1x_temp(temp_tick);
- rh = uthum_sht1x_rh(humidity_tick, temp);
- break;
- default:
- /* do nothing */
+ /* apply calibration offsets */
+ temp += sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].cal_offset;
+ rh += sc->sc_sensor[UTHUM_TEMPERHUM_HUM].cal_offset;
+
+ sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].sensor.value =
+ (temp * 10000) + 273150000;
+ sc->sc_sensor[UTHUM_TEMPERHUM_TEMP].sensor.flags &= ~SENSOR_FINVALID;
+ sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.value = rh;
+ sc->sc_sensor[UTHUM_TEMPERHUM_HUM].sensor.flags &= ~SENSOR_FINVALID;
+}
+
+void
+uthum_refresh_temper(struct uthum_softc *sc, int sensor)
+{
+ uint8_t buf[8];
+ uint8_t cmd;
+ int temp;
+
+ if (sensor == UTHUM_TEMPER_INNER)
+ cmd = CMD_GETDATA_INNER;
+ else if (sensor == UTHUM_TEMPER_OUTER)
+ cmd = CMD_GETDATA_OUTER;
+ else
+ return;
+
+ /* get sensor value */
+ if (uthum_read_data(sc, cmd, buf, sizeof(buf), 1000) != 0) {
+ DPRINTF(("uthum: data read fail\n"));
+ sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID;
+ return;
+ }
+
+ /* check integrity */
+ if (buf[2] != CMD_GETDATA_EOF) {
+ DPRINTF(("uthum: broken ds75 data: 0x%.2x 0x%.2x 0x%.2x\n",
+ buf[0], buf[1], buf[2]));
+ sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID;
return;
}
+ temp = uthum_ds75_temp(buf[0], buf[1]);
+
+ /* apply calibration offset */
+ temp += sc->sc_sensor[sensor].cal_offset;
- sc->sc_sensor[UTHUM_TEMP].value = (temp * 10000) + 273150000;
- sc->sc_sensor[UTHUM_TEMP].flags &= ~SENSOR_FINVALID;
- sc->sc_sensor[UTHUM_HUMIDITY].value = rh;
- sc->sc_sensor[UTHUM_HUMIDITY].flags &= ~SENSOR_FINVALID;
+ sc->sc_sensor[sensor].sensor.value = (temp * 10000) + 273150000;
+ sc->sc_sensor[sensor].sensor.flags &= ~SENSOR_FINVALID;
}
-/* return C-degree * 100 value */
+void
+uthum_refresh_temperntc(struct uthum_softc *sc, int sensor)
+{
+ int val;
+ int64_t temp;
+
+ /* get sensor data */
+ if (uthum_ntc_getdata(sc, &val)) {
+ DPRINTF(("uthum: ntc data read fail\n"));
+ sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID;
+ return;
+ }
+
+ /* adjust sensor state */
+ if ((val < UTHUM_NTC_MIN_THRESHOLD) ||
+ (val > UTHUM_NTC_MAX_THRESHOLD)) {
+ if (uthum_ntc_tuning(sc, UTHUM_TEMPER_NTC, &val)) {
+ DPRINTF(("uthum: NTC sensor tuning failed\n"));
+ sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID;
+ return;
+ }
+ }
+
+ temp = uthum_ntc_temp(val, sc->sc_sensor[sensor].cur_state);
+ if (temp == 0) {
+ /* XXX: work around. */
+ sc->sc_sensor[sensor].sensor.flags |= SENSOR_FINVALID;
+ } else {
+ /* apply calibration offset */
+ temp += sc->sc_sensor[sensor].cal_offset * 10000;
+ sc->sc_sensor[sensor].sensor.value = temp;
+ sc->sc_sensor[sensor].sensor.flags &= ~SENSOR_FINVALID;
+ }
+}
+
+/* return C-degree * 100 value */
int
-uthum_sht1x_temp(unsigned int ticks)
+uthum_ds75_temp(uint8_t msb, uint8_t lsb)
{
- /*
- * VDD constant
- *-----------------------
- * 5.0V -4010
- * 4.0V -3980
- * 3.5V -3970
- * 3.0V -3960
- * 2.5V -3940
- */
- /*
+ /* DS75: 12bit precision mode : 0.0625 degrees Celsius ticks */
+ return (msb * 100) + ((lsb >> 4) * 25 / 4);
+}
+
+/* return C-degree * 100 value */
+int
+uthum_sht1x_temp(uint8_t msb, uint8_t lsb)
+{
+ int ticks;
+
+ /* sensor device VDD-bias value table
+ * ----------------------------------------------
+ * VDD 2.5V 3.0V 3.5V 4.0V 5.0V
+ * bias -3940 -3960 -3970 -3980 -4010
+ * ----------------------------------------------
+ *
* as the VDD of the SHT10 on my TEMPerHUM is 3.43V +/- 0.05V,
- * I choose -3970 as the constant of this formula.
+ * bias -3970 will be best for that device.
*/
+
+ ticks = (msb * 256 + lsb) & 0x3fff;
return (ticks - 3970);
}
/* return %RH * 1000 */
int
-uthum_sht1x_rh(unsigned int ticks, int temp)
+uthum_sht1x_rh(uint8_t msb, uint8_t lsb, int temp)
{
- int rh_l, rh;
+ int ticks, rh_l;
+ ticks = (msb * 256 + lsb) & 0x0fff;
rh_l = (-40000 + 405 * ticks) - ((7 * ticks * ticks) / 250);
- rh = ((temp - 2500) * (1 + (ticks >> 7)) + rh_l) / 10;
- return rh;
+
+ return ((temp - 2500) * (1 + (ticks >> 7)) + rh_l) / 10;
+}
+
+/* return muK */
+int64_t
+uthum_ntc_temp(int64_t val, int state)
+{
+ int64_t temp = 0;
+
+ switch (state) {
+ case TEMPERNTC_MODE_BASE: /* 0x61 */
+ case TEMPERNTC_MODE_BASE+1: /* 0x62 */
+ case TEMPERNTC_MODE_BASE+2: /* 0x63 */
+ case TEMPERNTC_MODE_BASE+3: /* 0x64 */
+ /* XXX, no data */
+ temp = -273150000;
+ break;
+ case TEMPERNTC_MODE_BASE+4: /* 0x65 */
+ temp = ((val * val * 2977) / 100000) - (val * 4300) + 152450000;
+ break;
+ case TEMPERNTC_MODE_BASE+5: /* 0x66 */
+ temp = ((val * val * 3887) / 100000) - (val * 5300) + 197590000;
+ break;
+ case TEMPERNTC_MODE_BASE+6: /* 0x67 */
+ temp = ((val * val * 3495) / 100000) - (val * 5000) + 210590000;
+ break;
+ case TEMPERNTC_MODE_BASE+7: /* 0x68 */
+ if (val < UTHUM_NTC_MIN_THRESHOLD)
+ temp = (val * -1700) + 149630000;
+ else
+ temp = ((val * val * 3257) / 100000) - (val * 4900) +
+ 230470000;
+ break;
+ default:
+ DPRINTF(("NTC state error, unknown state 0x%.2x\n", state));
+ ;;
+ };
+
+ /* convert muC->muK value */
+ return temp + 273150000;
+}
+
+void
+uthum_print_sensorinfo(struct uthum_softc *sc, int num)
+{
+ struct uthum_sensor *s;
+ s = &sc->sc_sensor[num];
+
+ printf("%s: sensor%d: ", sc->sc_hdev.sc_dev.dv_xname, num);
+ switch(s->sensor.type) {
+ case SENSOR_TEMP:
+ printf("Temperature sensor (%s), ",
+ uthum_sensor_type_s[s->dev_type]);
+ printf("calibration offset = %d.%d deg-C",
+ s->cal_offset / 100, abs(s->cal_offset % 100));
+ break;
+ case SENSOR_HUMIDITY:
+ printf("Humidity sensor (%s), ",
+ uthum_sensor_type_s[s->dev_type]);
+ printf("calibration offset = %d.%d %%RH",
+ s->cal_offset / 100, abs(s->cal_offset % 100));
+ break;
+ default:
+ printf("unknown");
+ }
+ printf("\n");
}