]> Zhao Yanbai Git Server - minix.git/commitdiff
sht21: driver for the SHT21 humidity & temp sensor 78/778/2
authorThomas Cort <tcort@minix3.org>
Mon, 19 Aug 2013 13:54:20 +0000 (09:54 -0400)
committerThomas Cort <tcort@minix3.org>
Thu, 22 Aug 2013 20:53:57 +0000 (16:53 -0400)
Change-Id: Ia71168e394a7b260019e74973db6c9d75d3d4482

commands/MAKEDEV/MAKEDEV.sh
distrib/sets/lists/minix/md.evbarm
drivers/Makefile
drivers/sht21/Makefile [new file with mode: 0644]
drivers/sht21/README.txt [new file with mode: 0644]
drivers/sht21/sht21.c [new file with mode: 0644]
etc/system.conf
include/minix/dmap.h

index 5322a87cbf98672be18ae86f6d02532f97757a2a..df4f9a0e408af871e1e18c3612f1df86e4949a6a 100644 (file)
@@ -31,7 +31,8 @@ case $#:$1 in
        eepromb2s54 eepromb2s55 eepromb2s56 eepromb2s57 \
        eepromb3s50 eepromb3s51 eepromb3s52 eepromb3s53 \
        eepromb3s54 eepromb3s55 eepromb3s56 eepromb3s57 \
-       tsl2550b1s39 tsl2550b2s39 tsl2550b3s39
+       tsl2550b1s39 tsl2550b2s39 tsl2550b3s39 \
+       sht21b1s40 sht21b2s40 sht21b3s40
     ;;
 0:|1:-\?)
     cat >&2 <<EOF
@@ -41,6 +42,7 @@ Where key is one of the following:
   fb0                    # Make /dev/fb0
   i2c-1 i2c-2 i2c-3       # Make /dev/i2c-[1-3]
   tsl2550b{1,3}s39       # TSL2550 Ambient Light Sensors
+  sht21b{1,3}s40         # SHT21 Relative Humidity and Temperature Sensors
   fd0 fd1 ...            # Floppy devices for drive 0, 1, ...
   fd0p0 fd1p0 ...        # Make floppy partitions fd0p[0-3], fd1p[0-3], ...
   c0d0 c0d1 ...                  # Make disks c0d0, c0d1, ...
@@ -315,6 +317,13 @@ do
        $e mknod tsl2550b${b}s39 c ${m} 0
        $e chmod 444 tsl2550b${b}s39
        ;;
+    sht21b[1-3]s40)
+       b=`expr $dev : 'sht21b\\(.*\\)s40'` #bus number
+       m=`expr ${b} + 49`
+       $e mknod sht21b${b}s40 c ${m} 0
+       $e chmod 444 sht21b${b}s40
+       ;;
+
     *)
        echo "$0: don't know about $dev" >&2
        ex=1
index 679cdce36ecb9f13c8b26a503f2679f27be49581..d301ca958bec48b9c0e9ce83ddb393d386ef9629 100644 (file)
 ./usr/sbin/i2c                         minix-sys
 ./usr/sbin/lan8710a                    minix-sys
 ./usr/sbin/random                      minix-sys
+./usr/sbin/sht21                       minix-sys
 ./usr/sbin/tda19988                    minix-sys
 ./usr/sbin/tps65217                    minix-sys
 ./usr/sbin/tps65950                    minix-sys
index 6f6e220b0dcba492e822d5e95a811540af7c5762..05c8c131bfb7c86674a838f822e8a5d335fa3c08 100644 (file)
@@ -24,7 +24,7 @@ SUBDIR= ahci amddev atl2 at_wini audio dec21140A dp8390 dpeth \
 
 .if ${MACHINE_ARCH} == "earm"
 SUBDIR= cat24c256 fb gpio i2c mmc lan8710a log readclock \
-       tda19988 tps65217 tps65950 tsl2550 tty random
+       sht21 tda19988 tps65217 tps65950 tsl2550 tty random
 .endif
 
 .endif # ${MKIMAGEONLY} != "yes"
diff --git a/drivers/sht21/Makefile b/drivers/sht21/Makefile
new file mode 100644 (file)
index 0000000..03d248d
--- /dev/null
@@ -0,0 +1,14 @@
+# Makefile for the sht21 humidity and temp sensor found on the Weather Cape.
+PROG=  sht21
+SRCS=  sht21.c
+
+DPADD+=        ${LIBI2CDRIVER} ${LIBCHARDRIVER} ${LIBSYS} ${LIBTIMERS}
+LDADD+=        -li2cdriver -lchardriver -lsys -ltimers
+
+MAN=
+
+BINDIR?= /usr/sbin
+
+CPPFLAGS+=     -I${NETBSDSRCDIR}
+
+.include <minix.service.mk>
diff --git a/drivers/sht21/README.txt b/drivers/sht21/README.txt
new file mode 100644 (file)
index 0000000..fd3cba3
--- /dev/null
@@ -0,0 +1,67 @@
+SHT21 Driver (Relative Humidity and Temperature Sensor)
+=======================================================
+
+Overview
+--------
+
+This is the driver for the relative humidity and temperature sensor commonly
+found on the WeatherCape expansion board for the BeagleBone.
+
+Interface
+---------
+
+This driver implements the character device interface. It supports reading
+through /dev/sht21b{1,3}s40. When read from, it returns a string containing
+a data label, a colon, and the sensor value.
+
+Example output of `cat /dev/sht21b3s40`:
+
+TEMPERATURE     : 35.014
+HUMIDITY        : 25.181
+
+Temperature is expressed in Celsius (a.k.a. centigrade). Valid values are
+-40.000 to 125.000.
+
+Humidity is expressed as a percentage. Valid values are 0.000 to 100.000.
+
+Limitations
+-----------
+
+Intense activity causes the chip to heat up, affecting the temperature reading.
+In order to prevent the chip from self-heating more than 0.1C, the sensor
+values will only be read once per second. Subsequent reads within the same
+second will return cached temperature and humidity values.
+
+The measurement resolution is configurable in the chip, but this driver just
+uses the default maximum resolutions (12-bit for Humidity, 14-bit for
+temperature). It could probably be implemented with an ioctl() or by passing
+an argument via the service command, but it doesn't seem too useful at this
+time. See the data sheet for the trade-off between faster conversion time and
+lower resolution.
+
+In testing, the temperature sensor reported a value several degrees higher
+than an indoor thermometer placed nearby. It doesn't appear to be a bug in the
+driver as the Linux driver reports similar temperature. Additionally, the
+BMP085 temperature sensor on the same cape reports a temperature about 2
+degrees lower than the SHT21. This could be due to heat produced by the
+BeagleBone heating the cape slightly or maybe just a bad chip on the test
+board.
+
+Testing the Code
+----------------
+
+The driver should have been started by a script in /etc/rc.capes/ If not,
+this is how you start up an instance:
+
+cd /dev && MAKEDEV sht21b3s40
+/bin/service up /usr/sbin/sht21 -label sht21.3.40 -dev /dev/sht21b3s40 \
+       -args 'bus=3 address=0x40'
+
+Getting the sensor value:
+
+cat /dev/sht21b3s40
+
+Killing an instance:
+
+/bin/service down sht21.3.40
+
diff --git a/drivers/sht21/sht21.c b/drivers/sht21/sht21.c
new file mode 100644 (file)
index 0000000..cb9f327
--- /dev/null
@@ -0,0 +1,618 @@
+/* Driver for the SHT21 Relative Humidity and Temperature Sensor */
+
+#include <minix/ds.h>
+#include <minix/drivers.h>
+#include <minix/i2c.h>
+#include <minix/i2cdriver.h>
+#include <minix/chardriver.h>
+#include <minix/log.h>
+
+#include <time.h>
+
+/*
+ * Device Commands
+ */
+
+/*
+ * The trigger commands start a measurement. 'Hold' ties up the bus while the
+ * measurement is being performed while 'no hold' requires the driver to poll
+ * the chip until the data is ready. Hold is faster and requires less message
+ * passing while no hold frees up the bus while the measurement is in progress.
+ * The worst case conversion times are 85 ms for temperature and 29 ms for
+ * humidity. Typical conversion times are about 75% of the worst case times.
+ *
+ * The driver uses the 'hold' versions of the trigger commands.
+ */
+#define CMD_TRIG_T_HOLD 0xe3
+#define CMD_TRIG_RH_HOLD 0xe5
+#define CMD_TRIG_T_NOHOLD 0xf3
+#define CMD_TRIG_RH_NOHOLD 0xf5
+
+/* Read and write the user register contents */
+#define CMD_WR_USR_REG 0xe6
+#define CMD_RD_USR_REG 0xe7
+
+/* Resets the chip */
+#define CMD_SOFT_RESET 0xfe
+
+/* Status bits included in the measurement need to be masked in calculation */
+#define STATUS_BITS_MASK 0x0003
+
+/*
+ * The user register has some reserved bits that the device changes over
+ * time. The driver must preserve the value of those bits when writing to
+ * the user register.
+ */
+#define USR_REG_RESERVED_MASK ((1<<3)|(1<<4)|(1<<5))
+
+/* End of Battery flag is set when the voltage drops below 2.25V. */
+#define USR_REG_EOB_MASK (1<<6)
+
+/* When powered up and communicating, the register should have only the
+ * 'Disable OTP Reload' bit set
+ */
+#define EXPECTED_PWR_UP_TEST_VAL (1<<1)
+
+/* Define some constants for the different sensor types on the chip. */
+enum sht21_sensors
+{ SHT21_T, SHT21_RH };
+
+/* logging - use with log_warn(), log_info(), log_debug(), log_trace(), etc */
+static struct log log = {
+       .name = "sht21",
+       .log_level = LEVEL_INFO,
+       .log_func = default_log
+};
+
+/* device slave address is fixed at 0x40 */
+static i2c_addr_t valid_addrs[2] = {
+       0x40, 0x00
+};
+
+/* Buffer to store output string returned when reading from device file. */
+#define BUFFER_LEN 64
+char buffer[BUFFER_LEN + 1];
+
+/* the bus that this device is on (counting starting at 1) */
+static uint32_t bus;
+
+/* slave address of the device */
+static i2c_addr_t address;
+
+/* endpoint for the driver for the bus itself. */
+static endpoint_t bus_endpoint;
+
+/* Sampling causes self-heating. To limit the self-heating to < 0.1C, the
+ * data sheet suggests limiting sampling to 2 samples per second. Since
+ * the driver samples temperature and relative humidity at the same time,
+ * it's measure function does at most 1 pair of samples per second. It uses
+ * this timestamp to see if a measurement was taken less than 1 second ago.
+ */
+static time_t last_sample_time = 0;
+
+/*
+ * Cache temperature and relative humidity readings. These values are returned
+ * when the last_sample_time == current_time to keep the chip activity below
+ * 10% to help prevent self-heating.
+ */
+static int32_t cached_t = 0.0;
+static int32_t cached_rh = 0.0;
+
+/*
+ * An 8-bit CRC is used to validate the readings.
+ */
+#define CRC8_POLYNOMIAL 0x131
+#define CRC8_INITIAL_CRC 0x00
+
+/* main driver functions */
+static int sht21_init(void);
+static int soft_reset(void);
+static int usr_reg_read(uint8_t * usr_reg_val);
+static int sensor_read(enum sht21_sensors sensor, int32_t * measurement);
+static int measure(void);
+
+/* CRC functions */
+static uint8_t crc8(uint8_t crc, uint8_t byte);
+static int checksum(uint8_t * bytes, int nbytes, uint8_t expected_crc);
+
+/* libchardriver callbacks */
+static struct device *sht21_prepare(dev_t UNUSED(dev));
+static int sht21_transfer(endpoint_t endpt, int opcode, u64_t position,
+    iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
+    unsigned int UNUSED(flags));
+static int sht21_other(message * m);
+
+/* SEF functions */
+static int sef_cb_lu_state_save(int);
+static int lu_state_restore(void);
+static int sef_cb_init(int type, sef_init_info_t * info);
+static void sef_local_startup(void);
+
+/* Entry points to this driver from libchardriver. */
+static struct chardriver sht21_tab = {
+       .cdr_open = do_nop,
+       .cdr_close = do_nop,
+       .cdr_ioctl = nop_ioctl,
+       .cdr_prepare = sht21_prepare,
+       .cdr_transfer = sht21_transfer,
+       .cdr_cleanup = nop_cleanup,
+       .cdr_alarm = nop_alarm,
+       .cdr_cancel = nop_cancel,
+       .cdr_select = nop_select,
+       .cdr_other = sht21_other
+};
+
+static struct device sht21_device = {
+       .dv_base = 0,
+       .dv_size = 0
+};
+
+/*
+ * Sends the chip a soft reset command and waits 15 ms for the chip to reset.
+ */
+static int
+soft_reset(void)
+{
+       int r;
+       minix_i2c_ioctl_exec_t ioctl_exec;
+
+       memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
+
+       /* Write to chip */
+       ioctl_exec.iie_op = I2C_OP_WRITE_WITH_STOP;
+       ioctl_exec.iie_addr = address;
+
+       /* No command bytes for writing to this chip */
+       ioctl_exec.iie_cmdlen = 0;
+
+       /* Set the byte to write */
+       ioctl_exec.iie_buf[0] = CMD_SOFT_RESET;
+       ioctl_exec.iie_buflen = 1;
+
+       r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
+       if (r != OK) {
+               log_warn(&log, "soft_reset() failed (r=%d)\n", r);
+               return -1;
+       }
+
+       /* soft reset takes up to 15 ms to complete. */
+       micro_delay(15000);
+
+       log_debug(&log, "Soft Reset Complete\n");
+
+       return OK;
+}
+
+/*
+ * Obtain the contents of the usr register and store it in usr_reg_val.
+ */
+static int
+usr_reg_read(uint8_t * usr_reg_val)
+{
+       int r;
+       minix_i2c_ioctl_exec_t ioctl_exec;
+
+       if (usr_reg_val == NULL) {
+               log_warn(&log, "usr_reg_read() called with NULL pointer\n");
+               return -1;
+       }
+
+       memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
+
+       /* Read from chip */
+       ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
+       ioctl_exec.iie_addr = address;
+
+       /* Send the read from user register command */
+       ioctl_exec.iie_cmd[0] = CMD_RD_USR_REG;
+       ioctl_exec.iie_cmdlen = 1;
+
+       /* Read the register contents into iie_buf */
+       ioctl_exec.iie_buflen = 1;
+
+       r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
+       if (r != OK) {
+               log_warn(&log, "usr_reg_read() failed (r=%d)\n", r);
+               return -1;
+       }
+
+       *usr_reg_val = ioctl_exec.iie_buf[0];
+
+       log_trace(&log, "Read 0x%x from USR_REG\n", *usr_reg_val);
+
+       return OK;
+}
+
+/*
+ * Performs a soft reset and reads the contents of the user register to ensure
+ * that the chip is in a good state and working properly.
+ */
+static int
+sht21_init(void)
+{
+       int r;
+       uint8_t usr_reg_val;
+
+       r = soft_reset();
+       if (r != OK) {
+               return -1;
+       }
+
+       r = usr_reg_read(&usr_reg_val);
+       if (r != OK) {
+               return -1;
+       }
+
+       /* Check for End of Battery flag. */
+       if ((usr_reg_val & USR_REG_EOB_MASK) == USR_REG_EOB_MASK) {
+               log_warn(&log, "End of Battery Alarm\n");
+               return -1;
+       }
+
+       /* Check that the non-reserved bits are in the default state. */
+       if ((usr_reg_val & ~USR_REG_RESERVED_MASK) != EXPECTED_PWR_UP_TEST_VAL) {
+               log_warn(&log, "USR_REG has non-default values after reset\n");
+               log_warn(&log, "Expected 0x%x | Actual 0x%x",
+                   EXPECTED_PWR_UP_TEST_VAL,
+                   (usr_reg_val & ~USR_REG_RESERVED_MASK));
+               return -1;
+       }
+
+       return OK;
+}
+
+/*
+ * Read from the sensor, check the CRC, convert the ADC value into the final
+ * representation, and store the result in measurement.
+ */
+static int
+sensor_read(enum sht21_sensors sensor, int32_t * measurement)
+{
+       int r;
+       uint8_t cmd;
+       uint8_t val_hi, val_lo;
+       uint16_t val;
+       uint8_t expected_crc;
+       minix_i2c_ioctl_exec_t ioctl_exec;
+
+       switch (sensor) {
+       case SHT21_T:
+               cmd = CMD_TRIG_T_HOLD;
+               break;
+       case SHT21_RH:
+               cmd = CMD_TRIG_RH_HOLD;
+               break;
+       default:
+               log_warn(&log, "sensor_read() called with bad sensor type.\n");
+               return -1;
+       }
+
+       if (measurement == NULL) {
+               log_warn(&log, "sensor_read() called with NULL pointer\n");
+               return -1;
+       }
+
+       memset(&ioctl_exec, '\0', sizeof(minix_i2c_ioctl_exec_t));
+
+       /* Read from chip */
+       ioctl_exec.iie_op = I2C_OP_READ_WITH_STOP;
+       ioctl_exec.iie_addr = address;
+
+       /* Send the trigger command */
+       ioctl_exec.iie_cmd[0] = cmd;
+       ioctl_exec.iie_cmdlen = 1;
+
+       /* Read the results */
+       ioctl_exec.iie_buflen = 3;
+
+       r = i2cdriver_exec(bus_endpoint, &ioctl_exec);
+       if (r != OK) {
+               log_warn(&log, "sensor_read() failed (r=%d)\n", r);
+               return -1;
+       }
+
+       expected_crc = ioctl_exec.iie_buf[2];
+
+       r = checksum(ioctl_exec.iie_buf, 2, expected_crc);
+       if (r != OK) {
+               return -1;
+       }
+
+       val_hi = ioctl_exec.iie_buf[0];
+       val_lo = ioctl_exec.iie_buf[1];
+       val = ((val_hi << 8) | val_lo);
+
+       val &= ~STATUS_BITS_MASK;       /* clear status bits */
+
+       log_debug(&log, "Read VAL:0x%x CRC:0x%x\n", val, expected_crc);
+
+       /* Convert the ADC value to the actual value. */
+       if (cmd == CMD_TRIG_T_HOLD) {
+               *measurement = (int32_t)
+                   ((-46.85 + ((175.72 / 65536) * ((float) val))) * 1000.0);
+               log_debug(&log, "Measured Temperature %d mC\n", *measurement);
+       } else if (cmd == CMD_TRIG_RH_HOLD) {
+               *measurement =
+                   (int32_t) ((-6.0 +
+                       ((125.0 / 65536) * ((float) val))) * 1000.0);
+               log_debug(&log, "Measured Humidity %d m%%\n", *measurement);
+       }
+
+       return OK;
+}
+
+static int
+measure(void)
+{
+       int r;
+       time_t sample_time;
+       int32_t t, rh;
+
+       log_debug(&log, "Taking a measurement...");
+
+       sample_time = time(NULL);
+       if (sample_time == last_sample_time) {
+               log_debug(&log, "measure() called too soon, using cache.\n");
+               return OK;
+       }
+
+       r = sensor_read(SHT21_T, &t);
+       if (r != OK) {
+               return -1;
+       }
+
+       r = sensor_read(SHT21_RH, &rh);
+       if (r != OK) {
+               return -1;
+       }
+
+       /* save measured values */
+       cached_t = t;
+       cached_rh = rh;
+       last_sample_time = time(NULL);
+
+       log_debug(&log, "Measurement completed\n");
+
+       return OK;
+}
+
+/*
+ * Return an updated checksum for the given crc and byte.
+ */
+static uint8_t
+crc8(uint8_t crc, uint8_t byte)
+{
+       int i;
+
+       crc ^= byte;
+
+       for (i = 0; i < 8; i++) {
+
+               if ((crc & 0x80) == 0x80) {
+                       crc = (crc << 1) ^ CRC8_POLYNOMIAL;
+               } else {
+                       crc <<= 1;
+               }
+       }
+
+       return crc;
+}
+
+/*
+ * Compute the CRC of an array of bytes and compare it to expected_crc.
+ * If the computed CRC matches expected_crc, then return OK, otherwise EINVAL.
+ */
+static int
+checksum(uint8_t * bytes, int nbytes, uint8_t expected_crc)
+{
+       int i;
+       uint8_t crc;
+
+       crc = CRC8_INITIAL_CRC;
+
+       log_debug(&log, "Checking CRC\n");
+
+       for (i = 0; i < nbytes; i++) {
+               crc = crc8(crc, bytes[i]);
+       }
+
+       if (crc == expected_crc) {
+               log_debug(&log, "CRC OK\n");
+               return OK;
+       } else {
+               log_warn(&log,
+                   "Bad CRC -- Computed CRC: 0x%x | Expected CRC: 0x%x\n",
+                   crc, expected_crc);
+               return EINVAL;
+       }
+}
+
+static struct device *
+sht21_prepare(dev_t UNUSED(dev))
+{
+       return &sht21_device;
+}
+
+static int
+sht21_transfer(endpoint_t endpt, int opcode, u64_t position,
+    iovec_t * iov, unsigned nr_req, endpoint_t UNUSED(user_endpt),
+    unsigned int UNUSED(flags))
+{
+       int bytes, r;
+
+       r = measure();
+       if (r != OK) {
+               return EIO;
+       }
+
+       memset(buffer, '\0', BUFFER_LEN + 1);
+       snprintf(buffer, BUFFER_LEN, "%-16s: %d.%03d\n%-16s: %d.%03d\n",
+           "TEMPERATURE", cached_t / 1000, cached_t % 1000, "HUMIDITY",
+           cached_rh / 1000, cached_rh % 1000);
+
+       log_trace(&log, "%s", buffer);
+
+       bytes = strlen(buffer) - position < iov->iov_size ?
+           strlen(buffer) - position : iov->iov_size;
+
+       if (bytes <= 0) {
+               return OK;
+       }
+
+       switch (opcode) {
+       case DEV_GATHER_S:
+               r = sys_safecopyto(endpt, (cp_grant_id_t) iov->iov_addr, 0,
+                   (vir_bytes) (buffer + position), bytes);
+               iov->iov_size -= bytes;
+               break;
+       default:
+               return EINVAL;
+       }
+
+       return r;
+}
+
+static int
+sht21_other(message * m)
+{
+       int r;
+
+       switch (m->m_type) {
+       case NOTIFY_MESSAGE:
+               if (m->m_source == DS_PROC_NR) {
+                       log_debug(&log,
+                           "bus driver changed state, update endpoint\n");
+                       i2cdriver_handle_bus_update(&bus_endpoint, bus,
+                           address);
+               }
+               r = OK;
+               break;
+       default:
+               log_warn(&log, "Invalid message type (0x%x)\n", m->m_type);
+               r = EINVAL;
+               break;
+       }
+
+       return r;
+}
+
+static int
+sef_cb_lu_state_save(int UNUSED(state))
+{
+       ds_publish_u32("bus", bus, DSF_OVERWRITE);
+       ds_publish_u32("address", address, DSF_OVERWRITE);
+       return OK;
+}
+
+static int
+lu_state_restore(void)
+{
+       /* Restore the state. */
+       u32_t value;
+
+       ds_retrieve_u32("bus", &value);
+       ds_delete_u32("bus");
+       bus = (int) value;
+
+       ds_retrieve_u32("address", &value);
+       ds_delete_u32("address");
+       address = (int) value;
+
+       return OK;
+}
+
+static int
+sef_cb_init(int type, sef_init_info_t * UNUSED(info))
+{
+       int r;
+
+       if (type == SEF_INIT_LU) {
+               /* Restore the state. */
+               lu_state_restore();
+       }
+
+       /* look-up the endpoint for the bus driver */
+       bus_endpoint = i2cdriver_bus_endpoint(bus);
+       if (bus_endpoint == 0) {
+               log_warn(&log, "Couldn't find bus driver.\n");
+               return EXIT_FAILURE;
+       }
+
+       /* claim the device */
+       r = i2cdriver_reserve_device(bus_endpoint, address);
+       if (r != OK) {
+               log_warn(&log, "Couldn't reserve device 0x%x (r=%d)\n",
+                   address, r);
+               return EXIT_FAILURE;
+       }
+
+       r = sht21_init();
+       if (r != OK) {
+               log_warn(&log, "Device Init Failed\n");
+               return EXIT_FAILURE;
+       }
+
+       if (type != SEF_INIT_LU) {
+
+               /* sign up for updates about the i2c bus going down/up */
+               r = i2cdriver_subscribe_bus_updates(bus);
+               if (r != OK) {
+                       log_warn(&log, "Couldn't subscribe to bus updates\n");
+                       return EXIT_FAILURE;
+               }
+
+               i2cdriver_announce(bus);
+               log_debug(&log, "announced\n");
+       }
+
+       return OK;
+}
+
+static void
+sef_local_startup(void)
+{
+       /*
+        * Register init callbacks. Use the same function for all event types
+        */
+       sef_setcb_init_fresh(sef_cb_init);
+       sef_setcb_init_lu(sef_cb_init);
+       sef_setcb_init_restart(sef_cb_init);
+
+       /*
+        * Register live update callbacks.
+        */
+       /* Agree to update immediately when LU is requested in a valid state. */
+       sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
+       /* Support live update starting from any standard state. */
+       sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard);
+       /* Register a custom routine to save the state. */
+       sef_setcb_lu_state_save(sef_cb_lu_state_save);
+
+       /* Let SEF perform startup. */
+       sef_startup();
+}
+
+int
+main(int argc, char *argv[])
+{
+       int r;
+
+       env_setargs(argc, argv);
+
+       r = i2cdriver_env_parse(&bus, &address, valid_addrs);
+       if (r < 0) {
+               log_warn(&log, "Expecting -args 'bus=X address=0xYY'\n");
+               log_warn(&log, "Example -args 'bus=1 address=0x40'\n");
+               return EXIT_FAILURE;
+       } else if (r > 0) {
+               log_warn(&log,
+                   "Invalid slave address for device, expecting 0x40\n");
+               return EXIT_FAILURE;
+       }
+
+       sef_local_startup();
+
+       chardriver_task(&sht21_tab, CHARDRIVER_SYNC);
+
+       return 0;
+}
index d37739e5ab1007db86e5d670ee22d58b3eeaf219..e46d183ebe515f04a129d25d2eea04a306019e26 100644 (file)
@@ -641,6 +641,11 @@ service tsl2550
        ipc SYSTEM RS DS i2c;
 };
 
+service sht21
+{
+       ipc SYSTEM RS DS i2c;
+};
+
 service vbox
 {
        system
index 73ef35c22a710f1bdd18abb2d643494d5b809d1f..9a1c2f5a35ced9bbe63ba94ac6bade5682c63cfe 100644 (file)
@@ -69,6 +69,9 @@ enum dev_style { STYLE_NDEV, STYLE_DEV, STYLE_DEVA, STYLE_TTY, STYLE_CTTY,
 #define TSL2550B1S39_MAJOR       47    /* 47 = /dev/tsl2550b1s39 (tsl2550)   */
 #define TSL2550B2S39_MAJOR       48    /* 48 = /dev/tsl2550b2s39 (tsl2550)   */
 #define TSL2550B3S39_MAJOR       49    /* 49 = /dev/tsl2550b3s39 (tsl2550)   */
+#define SHT21B1S40_MAJOR         50    /* 50 = /dev/sht21b1s40 (sht21)       */
+#define SHT21B2S40_MAJOR         51    /* 51 = /dev/sht21b2s40 (sht21)       */
+#define SHT21B3S40_MAJOR         52    /* 52 = /dev/sht21b3s40 (sht21)       */
 
 
 /* Minor device numbers for memory driver. */