This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new c15b900a88 sensors/sht4x: Converted SHT4X driver to UORB framework.
c15b900a88 is described below

commit c15b900a8807fdc41c1f04731cbe4eca877e9089
Author: Matteo Golin <matteo.go...@gmail.com>
AuthorDate: Wed Jan 15 20:30:12 2025 -0500

    sensors/sht4x: Converted SHT4X driver to UORB framework.
---
 .../components/drivers/special/sensors/sht4x.rst   | 103 ++--
 .../arm/rp2040/common/src/rp2040_common_bringup.c  |   4 +-
 drivers/sensors/CMakeLists.txt                     |   2 +-
 drivers/sensors/Kconfig                            |  21 +-
 drivers/sensors/Make.defs                          |   2 +-
 drivers/sensors/{sht4x.c => sht4x_uorb.c}          | 626 ++++++++++++---------
 include/nuttx/sensors/sht4x.h                      |  17 +-
 7 files changed, 403 insertions(+), 372 deletions(-)

diff --git a/Documentation/components/drivers/special/sensors/sht4x.rst 
b/Documentation/components/drivers/special/sensors/sht4x.rst
index 56991b3061..a2d99ad793 100644
--- a/Documentation/components/drivers/special/sensors/sht4x.rst
+++ b/Documentation/components/drivers/special/sensors/sht4x.rst
@@ -1,3 +1,4 @@
+=====
 SHT4X
 =====
 
@@ -7,7 +8,8 @@ The SHT4x is a family of temperature and humidity sensors 
created by Sensirion
 which operates over I2C. They include a small heating element.
 
 The driver provided allows interfacing with the sensor over I2C. It has been
-tested against the SHT41.
+tested against the SHT41. This driver uses the :doc:`uorb
+</components/drivers/special/sensors/sensors_uorb>` interface.
 
 Application Programming Interface
 =================================
@@ -16,42 +18,48 @@ The header file for the SHT4X driver interface can be 
included using:
 
 .. code-block:: c
 
-   # include <nuttx/sensors/sht4x.h>
+   #include <nuttx/sensors/sht4x.h>
+
+The SHT4x registration function allows the driver to be registered as a UORB
+driver.
 
-The SHT4x registration function allows the driver to be registered as a POSIX
-character driver.
+The SHT4x measures both ambient temperature and humidity, so registering this
+driver will cause two new UORB topics to appear: ``sensor_humi<n>`` and
+``sensor_temp<n>``.
 
-The standard POSIX `read()` operation will return the temperature and humidity
-measurements in plain-text, which is useful when debugging/testing the driver
-using `cat` from the shell.
+.. code-block:: c
 
-The `write()` operation is not implemented for this sensor.
+   int err;
+   err = sht4x_register(i2c_master, 0, 0x44);
+   if (err < 0)
+   {
+     syslog(LOG_ERR, "Couldn't register SHT4X driver at 0x44: %d\n", err);
+   }
 
-Specific operations the sensor offers can be performed via the POSIX `ioctl`
-operation. The supported commands are:
+To debug this device, you can include the ``uorb_listener`` in your build with
+debugging enabled. Running it will show the sensor measurements.
 
- * :c:macro:`SNIOC_RESET`
- * :c:macro:`SNIOC_WHO_AM_I`
- * :c:macro:`SNIOC_READ_RAW_DATA`
- * :c:macro:`SNIOC_MEASURE`
- * :c:macro:`SNIOC_READ_CONVERT_DATA`
- * :c:macro:`SNIOC_HEAT`
- * :c:macro:`SNIOC_CONFIGURE`
+This sensor also offers some addition control commands for using the onboard
+heater and checking the serial number. These control commands can be used on
+either topic (humidity or temperature), since they control the device as a
+whole.
 
-.. c:macro:: SNIOC_RESET
+``SNIOC_RESET``
+----------------
 
-   This will perform the SHT4X's soft reset command.
+This will perform the SHT4X's soft reset command.
 
 .. code-block:: c
 
-  err = ioctl(sensor, SNIOC_RESET);
+  err = orb_ioctl(sensor, SNIOC_RESET);
   if (err) {
     fprintf(stderr, "SNIOC_RESET: %s\n", strerror(errno));
   } else {
     puts("RESET success!");
   }
 
-.. c:macro:: SNIOC_WHO_AM_I
+``SNIOC_WHO_AM_I``
+------------------
 
 This command reads the serial number of the SHT4X sensor. The serial number is
 returned in the argument to the command, which must be a `uint32_t` pointer.
@@ -59,49 +67,15 @@ returned in the argument to the command, which must be a 
`uint32_t` pointer.
 .. code-block:: c
 
   uint32_t serialno = 0;
-  err = ioctl(sensor, SNIOC_WHO_AM_I, &serialno);
-
-.. c:macro:: SNIOC_READ_RAW_DATA
-
-This command allows the caller to read the raw data returned from the sensor,
-without the driver performing any calculation to convert it into familiar units
-(i.e. degrees Celsius for temperature).
-
-The argument to this command must be a pointer to a `struct sht4x_raw_data_s`
-structure. The raw data will be returned here.
-
-.. code-block:: c
-
-  struct sht4x_raw_data_s raw;
-  err = ioctl(sensor, SNIOC_READ_RAW_DATA, &raw);
-
-.. c:macro:: SNIOC_MEASURE
-
-This command will measure temperature and humidity, and return it in familiar
-units to the user. Temperature will be in degrees (Fahrenheit or Celsius 
depends
-on the Kconfig options selected during compilation) and humidity will be %RH.
-
-The argument to this command must be a pointer to a `struct sht4x_conv_data_s`.
-This is where the converted data will be returned.
-
-.. code-block:: c
-
-  struct sht4x_conv_data_s data;
-  err = ioctl(sensor, SNIOC_MEASURE, &data);
-
-.. c:macro:: SNIOC_READ_CONVERT_DATA
-
-Same as `SNIOC_MEASURE`.
+  err = orb_ioctl(sensor, SNIOC_WHO_AM_I, &serialno);
 
-.. c:macro:: SNIOC_HEAT
+``SNIOC_HEAT``
+--------------
 
 This command will instruct the SHT4X to turn on its heater unit for the
-specified time. Afterwards, a measurement of temperature and humidity is taken,
-and the converted data is returned to the caller.
+specified time.
 
-The argument to this command must be a pointer to a `struct sht4x_conv_data_s`.
-This is where the converted data will be returned. The `temperature` field of
-the struct must contain a value from the `enum sht4x_heater_e`, which will
+The argument to this command must be of type `enum sht4x_heater_e`, which will
 indicate the duration the heater is on and the power used.
 
 Heating commands are not allowed more than once per second to avoid damaging 
the
@@ -110,11 +84,10 @@ sensor. If a command is issued before this one second 
cool-down period is over,
 
 .. code-block:: c
 
-  struct sht4x_conv_data_s data;
-  data.temp = SHT4X_HEATER_200MW_1;
-  err = ioctl(sensor, SNIOC_HEAT, &data);
+  err = orb_ioctl(sensor, SNIOC_HEAT, SHT4X_HEATER_200MW_1);
 
-.. c:macro:: SNIOC_CONFIGURE
+``SNIOC_CONFIGURE``
+-------------------
 
 This command allows the caller to configure the precision of the SHT4X sensor
 used by subsequent measurement commands. By default, the sensor starts at high
@@ -124,4 +97,4 @@ The argument to this command is one of the values in `enum 
sht4x_precision_e`.
 
 .. code-block:: c
 
-  err = ioctl(sensor, SNIOC_CONFIGURE, SHT4X_PREC_LOW);
+  err = orb_ioctl(sensor, SNIOC_CONFIGURE, SHT4X_PREC_LOW);
diff --git a/boards/arm/rp2040/common/src/rp2040_common_bringup.c 
b/boards/arm/rp2040/common/src/rp2040_common_bringup.c
index 3ee76b0bb6..7f43be8655 100644
--- a/boards/arm/rp2040/common/src/rp2040_common_bringup.c
+++ b/boards/arm/rp2040/common/src/rp2040_common_bringup.c
@@ -538,9 +538,9 @@ int rp2040_common_bringup(void)
 
 #ifdef CONFIG_SENSORS_SHT4X
 
-  /* Try to register SHT4X device as /dev/sht4x0 at I2C0. */
+  /* Try to register SHT4X device on I2C0 */
 
-  ret = sht4x_register("/dev/sht4x0", rp2040_i2cbus_initialize(0),
+  ret = sht4x_register(rp2040_i2cbus_initialize(0), 0,
                        CONFIG_SHT4X_I2C_ADDR);
   if (ret < 0)
     {
diff --git a/drivers/sensors/CMakeLists.txt b/drivers/sensors/CMakeLists.txt
index e6bf460ec3..02cfd2579b 100644
--- a/drivers/sensors/CMakeLists.txt
+++ b/drivers/sensors/CMakeLists.txt
@@ -285,7 +285,7 @@ if(CONFIG_SENSORS)
     endif()
 
     if(CONFIG_SENSORS_SHT4X)
-      list(APPEND SRCS sht4x.c)
+      list(APPEND SRCS sht4x_uorb.c)
     endif()
 
     if(CONFIG_SENSORS_SPS30)
diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig
index 14986498af..47960acacc 100644
--- a/drivers/sensors/Kconfig
+++ b/drivers/sensors/Kconfig
@@ -1627,6 +1627,12 @@ config SHT4X_I2C_FREQUENCY
        default 400000
        range 1 400000
 
+config SHT4X_THREAD_STACKSIZE
+    int "SHT4X worker thread stack size"
+       default 1024
+       ---help---
+               The stack size for the worker thread that performs measurements
+
 config SHT4X_I2C_ADDR
        hex "SHT4X I2C address"
        default 0x44
@@ -1634,12 +1640,6 @@ config SHT4X_I2C_ADDR
        ---help---
                Enables debug features for the SHT4X
 
-config SHT4X_FAHRENHEIT
-       bool "SHT4X use Fahrenheit"
-       default n
-       ---help---
-               Configures read outputs of the SHT4X to be in Fahrenheit. 
Default uses Celsius.
-
 config SHT4X_LIMIT_HUMIDITY
        bool "SHT4X limit humidity between 0-100%"
        default y
@@ -1652,11 +1652,12 @@ config SHT4X_CRC_LOOKUP
        ---help---
                Configures the SHT4X to do CRC checks with a lookup table. 
Default uses a bitwise CRC calculation.
 
-config SHT4X_DEBUG
-       bool "SHT4X debug support"
-       default n
+config SENSORS_SHT4X_POLL
+       bool "Use polling"
+       default y
        ---help---
-               Enables debug features for the SHT4X
+        Configures the SHT4X to be polled at an interval instead of allowing 
user code to choose when measurements are
+        taken.
 
 endif # SENSORS_SHT4X
 
diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs
index ac6ec09022..bc382e7e3a 100644
--- a/drivers/sensors/Make.defs
+++ b/drivers/sensors/Make.defs
@@ -289,7 +289,7 @@ ifeq ($(CONFIG_SENSORS_SHT3X),y)
 endif
 
 ifeq ($(CONFIG_SENSORS_SHT4X),y)
-  CSRCS += sht4x.c
+  CSRCS += sht4x_uorb.c
 endif
 
 ifeq ($(CONFIG_SENSORS_SPS30),y)
diff --git a/drivers/sensors/sht4x.c b/drivers/sensors/sht4x_uorb.c
similarity index 59%
rename from drivers/sensors/sht4x.c
rename to drivers/sensors/sht4x_uorb.c
index d8cb2c9863..9303e833ec 100644
--- a/drivers/sensors/sht4x.c
+++ b/drivers/sensors/sht4x_uorb.c
@@ -1,5 +1,5 @@
 /****************************************************************************
- * drivers/sensors/sht4x.c
+ * drivers/sensors/sht4x_uorb.c
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -24,35 +24,29 @@
  * Included Files
  ****************************************************************************/
 
+#include <nuttx/config.h>
+#include <nuttx/nuttx.h>
+
 #include <debug.h>
+#include <stdio.h>
+#include <unistd.h>
+
 #include <nuttx/clock.h>
-#include <nuttx/config.h>
 #include <nuttx/fs/fs.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/kmalloc.h>
+#include <nuttx/kthread.h>
 #include <nuttx/mutex.h>
 #include <nuttx/random.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/sensors/sensor.h>
 #include <nuttx/sensors/sht4x.h>
-
-#include <stdio.h>
-#include <unistd.h>
-
-#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_SHT4X)
+#include <nuttx/signal.h>
 
 /****************************************************************************
  * Pre-processor Definitions
  ****************************************************************************/
 
-#ifdef CONFIG_SHT4X_DEBUG
-#define sht4x_dbg(x, ...) _info(x, ##__VA_ARGS__)
-#endif
-
-#if defined(CONFIG_SHT4X_FAHRENHEIT)
-#define SHT4X_TEMP_UNIT "F"
-#else
-#define SHT4X_TEMP_UNIT "C"
-#endif
-
 #ifndef CONFIG_SHT4X_I2C_FREQUENCY
 #define CONFIG_SHT4X_I2C_FREQUENCY 400000
 #endif
@@ -76,19 +70,34 @@
  * Private
  ****************************************************************************/
 
+/* Sensor information for the lowerhalf sensors.
+ * Since the SHT4X has both a relative humidity and temperature sensor,
+ * two lower halves are needed which will follow this structure.
+ */
+
+struct sht4x_sensor_s
+{
+  FAR struct sensor_lowerhalf_s sensor_lower; /* Lower-half driver */
+  bool enabled;                               /* If this sensor is enabled */
+  FAR struct sht4x_dev_s *dev;                /* Backward reference to
+                                               * device */
+};
+
+/* Represents the main device, with two lower halves for both data types. */
+
 struct sht4x_dev_s
 {
-  FAR struct i2c_master_s *i2c; /* I2C interface. */
-  uint8_t addr;                 /* I2C address. */
-#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
-  bool unlinked;                    /* True, driver has been unlinked. */
-#endif
+  struct sht4x_sensor_s hum;        /* Humidity lower-half */
+  struct sht4x_sensor_s temp;       /* Temperature lower-half */
+  FAR struct i2c_master_s *i2c;     /* I2C interface. */
+  uint8_t addr;                     /* I2C address. */
   struct timespec last_heat;        /* Last time heater was active. */
   enum sht4x_precision_e precision; /* The precision for read operations. */
-#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
-  int16_t crefs; /* Number of open references. */
-#endif
-  mutex_t devlock;
+  sem_t run;                        /* Lock for the polling measurement
+                                     * cycle */
+  mutex_t devlock;                  /* Exclusive device access */
+  uint32_t interval;                /* Measurement interval for polling in
+                                     * us, shared by both halves. */
 };
 
 /* Easy unpacking of serial number from I2C packet. */
@@ -111,9 +120,9 @@ union sht4x_serialno_t
 
 static const uint8_t g_precision_read[] =
 {
-    [SHT4X_PREC_LOW] = SHT4X_READ_LOW_PREC,
-    [SHT4X_PREC_MED] = SHT4X_READ_MED_PREC,
-    [SHT4X_PREC_HIGH] = SHT4X_READ_HIGH_PREC,
+  [SHT4X_PREC_LOW] = SHT4X_READ_LOW_PREC,
+  [SHT4X_PREC_MED] = SHT4X_READ_MED_PREC,
+  [SHT4X_PREC_HIGH] = SHT4X_READ_HIGH_PREC,
 };
 
 #ifdef CONFIG_SHT4X_CRC_LOOKUP
@@ -153,68 +162,67 @@ static const uint8_t g_crc_lookup[] =
 
 static const uint16_t g_measurement_times[] =
 {
-    [SHT4X_PREC_LOW] = 1600,
-    [SHT4X_PREC_MED] = 4500,
-    [SHT4X_PREC_HIGH] = 8300,
+  [SHT4X_PREC_LOW] = 1600,
+  [SHT4X_PREC_MED] = 4500,
+  [SHT4X_PREC_HIGH] = 8300,
 };
 
 /* Commands for the various heating options. */
 
 static const uint8_t g_heat_cmds[] =
 {
-    [SHT4X_HEATER_200MW_1] = SHT4X_HEAT_200_1,
-    [SHT4X_HEATER_200MW_01] = SHT4X_HEAT_200_P1,
-    [SHT4X_HEATER_110MW_1] = SHT4X_HEAT_110_1,
-    [SHT4X_HEATER_110MW_01] = SHT4X_HEAT_110_P1,
-    [SHT4X_HEATER_20MW_1] = SHT4X_HEAT_20_1,
-    [SHT4X_HEATER_20MW_01] = SHT4X_HEAT_20_P1,
+  [SHT4X_HEATER_200MW_1] = SHT4X_HEAT_200_1,
+  [SHT4X_HEATER_200MW_01] = SHT4X_HEAT_200_P1,
+  [SHT4X_HEATER_110MW_1] = SHT4X_HEAT_110_1,
+  [SHT4X_HEATER_110MW_01] = SHT4X_HEAT_110_P1,
+  [SHT4X_HEATER_20MW_1] = SHT4X_HEAT_20_1,
+  [SHT4X_HEATER_20MW_01] = SHT4X_HEAT_20_P1,
 };
 
 /* Timeouts for the various heating options in microseconds. */
 
 static const uint32_t g_heat_times[] =
 {
-    [SHT4X_HEATER_200MW_1] = 1000000, [SHT4X_HEATER_200MW_01] = 100000,
-    [SHT4X_HEATER_110MW_1] = 1000000, [SHT4X_HEATER_110MW_01] = 100000,
-    [SHT4X_HEATER_20MW_1] = 1000000,  [SHT4X_HEATER_20MW_01] = 100000,
+  [SHT4X_HEATER_200MW_1] = 1000000, [SHT4X_HEATER_200MW_01] = 100000,
+  [SHT4X_HEATER_110MW_1] = 1000000, [SHT4X_HEATER_110MW_01] = 100000,
+  [SHT4X_HEATER_20MW_1] = 1000000,  [SHT4X_HEATER_20MW_01] = 100000,
 };
 
 /****************************************************************************
  * Private Function Prototypes
  ****************************************************************************/
 
-static int sht4x_open(FAR struct file *filep);
-static int sht4x_close(FAR struct file *filep);
-static ssize_t sht4x_write(FAR struct file *filep, FAR const char *buffer,
-                           size_t buflen);
-static ssize_t sht4x_read(FAR struct file *filep, FAR char *buffer,
-                          size_t buflen);
-static int sht4x_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
-static int sht4x_unlink(FAR struct inode *inode);
+static int sht4x_set_interval(FAR struct sensor_lowerhalf_s *lower,
+                              FAR struct file *filep,
+                              FAR uint32_t *period_us);
+static int sht4x_activate(FAR struct sensor_lowerhalf_s *lower,
+                          FAR struct file *filep, bool enable);
+static int sht4x_get_info(FAR struct sensor_lowerhalf_s *lower,
+                          FAR struct file *filep,
+                          FAR struct sensor_device_info_s *info);
+static int sht4x_control(FAR struct sensor_lowerhalf_s *lower,
+                         FAR struct file *filep, int cmd, unsigned long arg);
+#ifndef CONFIG_SENSORS_SHT4X_POLL
+static int sht4x_fetch(FAR struct sensor_lowerhalf_s *lower,
+                       FAR struct file *filep, FAR char *buffer,
+                       size_t buflen);
+#endif
 
 /****************************************************************************
  * Private Data
  ****************************************************************************/
 
-static const struct file_operations g_sht4xfops =
+static const struct sensor_ops_s g_sensor_ops =
 {
-#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
-    .open = sht4x_open,
-    .close = sht4x_close,
+    .activate = sht4x_activate,
+#ifdef CONFIG_SENSORS_SHT4X_POLL
+    .fetch = NULL,
 #else
-    .open = NULL,
-    .close = NULL,
-#endif
-    .read = sht4x_read,
-    .write = sht4x_write,
-    .seek = NULL,
-    .ioctl = sht4x_ioctl,
-    .mmap = NULL,
-    .truncate = NULL,
-    .poll = NULL,
-#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
-    .unlink = sht4x_unlink,
+    .fetch = sht4x_fetch,
 #endif
+    .set_interval = sht4x_set_interval,
+    .get_info = sht4x_get_info,
+    .control = sht4x_control,
 };
 
 /****************************************************************************
@@ -411,19 +419,13 @@ static int sht4x_reset(FAR struct sht4x_dev_s *priv)
  * Name: sht4x_calc_temp
  *
  * Description:
- *   Calculate the temperature from the SHT4X raw data.
+ *   Calculate the temperature in degrees Celsius from the SHT4X raw data.
  *
  ****************************************************************************/
 
-static int32_t sht4x_calc_temp(uint16_t temp)
+static float sht4x_calc_temp(uint16_t temp)
 {
-#ifdef CONFIG_SHT4X_FAHRENHEIT
-  /* Millidegrees Fahrenheit */
-
-  return -49000 + 315 * ((temp * 1000) / 65535);
-#else
-  return -45000 + 175 * ((temp * 1000) / 65535); /* Millidegrees Celsius */
-#endif
+  return (float)(-45000 + 175 * ((temp * 1000) / 65535)) / 1000.0f;
 }
 
 /****************************************************************************
@@ -434,7 +436,7 @@ static int32_t sht4x_calc_temp(uint16_t temp)
  *
  ****************************************************************************/
 
-static int16_t sht4x_calc_hum(uint16_t humidity)
+static float sht4x_calc_hum(uint16_t humidity)
 {
   int16_t hum = -600 + 125 * ((humidity * 100) / 65535); /* 0.01 %RH */
 #ifdef CONFIG_SHT4X_LIMIT_HUMIDITY
@@ -451,253 +453,201 @@ static int16_t sht4x_calc_hum(uint16_t humidity)
     }
 
 #endif
-  return hum;
+  return (float)(hum / 100.0f);
 }
 
 /****************************************************************************
- * Name: has_time_passed
+ * Name: sht4x_read
  *
- * Description:
- *   Return true if curr >= start + secs_since_start
+ * Description: Read temperature and humidity into UORB sensor formats.
+ *
+ * Return:
+ *   Negated error code, or 0 on success.
  *
  ****************************************************************************/
 
-static bool has_time_passed(struct timespec curr, struct timespec start,
-                            unsigned int secs_since_start)
+static int sht4x_read(FAR struct sht4x_dev_s *priv,
+                      FAR struct sensor_humi *humi,
+                      FAR struct sensor_temp *temp)
 {
-  if ((long)((start.tv_sec + secs_since_start) - curr.tv_sec) == 0)
+  uint16_t raw_temp;
+  uint16_t raw_hum;
+  int err;
+
+  /* Exclusive access */
+
+  err = nxmutex_lock(&priv->devlock);
+  if (err < 0)
     {
-      return start.tv_nsec <= curr.tv_nsec;
+      return err;
     }
 
-  return (long)((start.tv_sec + secs_since_start) - curr.tv_sec) <= 0;
-}
+  /* Get temp and humidity */
 
-/****************************************************************************
- * Name: sht4x_open
- *
- * Description:
- *   This function is called whenever the SHT4X device is opened.
- *
- ****************************************************************************/
+  err = sht4x_cmd(priv, g_precision_read[priv->precision],
+                  g_measurement_times[priv->precision], &raw_temp, &raw_hum);
+  if (err < 0)
+    {
+      nxmutex_unlock(&priv->devlock);
+      return err;
+    }
 
-#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
-static int sht4x_open(FAR struct file *filep)
-{
-  FAR struct inode *inode = filep->f_inode;
-  FAR struct sht4x_dev_s *priv = inode->i_private;
-  int err;
+  /* Release mutex */
 
-  err = nxmutex_lock(&priv->devlock);
+  err = nxmutex_unlock(&priv->devlock);
   if (err < 0)
     {
       return err;
     }
 
-  /* Increment the count of open references on the driver */
+  /* Store results */
 
-  priv->crefs++;
-  DEBUGASSERT(priv->crefs > 0);
+  humi->timestamp = sensor_get_timestamp();
+  humi->humidity = sht4x_calc_hum(raw_hum);
+  temp->timestamp = humi->timestamp;
+  temp->temperature = sht4x_calc_temp(raw_temp);
 
-  nxmutex_unlock(&priv->devlock);
-  return 0;
+  return err;
 }
-#endif
 
 /****************************************************************************
- * Name: sht4x_close
+ * Name: has_time_passed
  *
  * Description:
- *   This routine is called when the SHT4X device is closed.
+ *   Return true if curr >= start + secs_since_start
  *
  ****************************************************************************/
 
-#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
-static int sht4x_close(FAR struct file *filep)
+static bool has_time_passed(struct timespec curr, struct timespec start,
+                            unsigned int secs_since_start)
 {
-  FAR struct inode *inode = filep->f_inode;
-  FAR struct sht4x_dev_s *priv = inode->i_private;
-  int err;
-
-  err = nxmutex_lock(&priv->devlock);
-  if (err < 0)
+  if ((long)((start.tv_sec + secs_since_start) - curr.tv_sec) == 0)
     {
-      return err;
+      return start.tv_nsec <= curr.tv_nsec;
     }
 
-  /* Decrement the count of open references on the driver */
+  return (long)((start.tv_sec + secs_since_start) - curr.tv_sec) <= 0;
+}
 
-  DEBUGASSERT(priv->crefs > 0);
-  priv->crefs--;
+/****************************************************************************
+ * Name: sht4x_get_info
+ ****************************************************************************/
 
-  /* If the count has decremented to zero and the driver has been unlinked,
-   * then free memory now.
-   */
+static int sht4x_get_info(FAR struct sensor_lowerhalf_s *lower,
+                          FAR struct file *filep,
+                          FAR struct sensor_device_info_s *info)
+{
+  /* Fill out information */
 
-  if (priv->crefs <= 0 && priv->unlinked)
+  info->version = 0;
+  info->power = 0.0004f;  /* 0.4uA */
+  info->min_delay = 1300; /* 1.3ms */
+  info->max_delay = 8300; /* 8.3ms */
+  memcpy(info->name, "SHT4x", sizeof("SHT4x"));
+  memcpy(info->vendor, "Sensirion", sizeof("Sensirion"));
+
+  /* Fill out information specific to a certain lower half */
+
+  if (lower->type == SENSOR_TYPE_RELATIVE_HUMIDITY)
     {
-      nxmutex_destroy(&priv->devlock);
-      kmm_free(priv);
-      return 0;
+      info->max_range = 100.0f;
+      info->resolution = 0.01f;
+    }
+  else if (lower->type == SENSOR_TYPE_AMBIENT_TEMPERATURE)
+    {
+      info->max_range = 125.0f;
+      info->resolution = 0.01f;
     }
 
-  nxmutex_unlock(&priv->devlock);
+  info->fifo_reserved_event_count = 0;
+  info->fifo_max_event_count = 0;
   return 0;
 }
-#endif
 
 /****************************************************************************
- * Name: sht4x_read
+ * Name: sht4x_set_interval
  *
  * Description:
- *     Character driver interface to sensor for debugging.
+ *     Sets the measurement interval for the SHT4X sensor in microseconds.
  *
  ****************************************************************************/
 
-static ssize_t sht4x_read(FAR struct file *filep, FAR char *buffer,
-                          size_t buflen)
+static int sht4x_set_interval(FAR struct sensor_lowerhalf_s *lower,
+                              FAR struct file *filep,
+                              FAR uint32_t *period_us)
 {
-  FAR struct inode *inode = filep->f_inode;
-  FAR struct sht4x_dev_s *priv = inode->i_private;
-  ssize_t length = 0;
-  struct sht4x_raw_data_s raw_data;
-  struct sht4x_conv_data_s data;
-  int err;
-
-  /* If file position is non-zero, then we're at the end of file. */
+  FAR struct sht4x_sensor_s *priv =
+      container_of(lower, FAR struct sht4x_sensor_s, sensor_lower);
+  FAR struct sht4x_dev_s *dev = priv->dev;
+  dev->interval = *period_us;
+  return 0;
+}
 
-  if (filep->f_pos > 0)
-    {
-      return 0;
-    }
+/****************************************************************************
+ * Name: sht4x_activate
+ ****************************************************************************/
 
-  /* Get exclusive access */
+static int sht4x_activate(FAR struct sensor_lowerhalf_s *lower,
+                          FAR struct file *filep, bool enable)
+{
+  bool start_thread = false;
+  FAR struct sht4x_sensor_s *priv =
+      container_of(lower, FAR struct sht4x_sensor_s, sensor_lower);
+  FAR struct sht4x_dev_s *dev = priv->dev;
 
-  err = nxmutex_lock(&priv->devlock);
-  if (err < 0)
+  if (enable)
     {
-      return err;
+      if (!priv->enabled)
+        {
+          start_thread = true;
+        }
     }
 
-#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
-  if (priv->unlinked)
-    {
-      /* Do not allow operations on unlinked sensors. This allows
-       * sensor use on hot swappable I2C bus.
-       */
+  priv->enabled = enable;
 
-      nxmutex_unlock(&priv->devlock);
-      return 0;
-    }
-#endif
-
-  err = sht4x_cmd(priv, g_precision_read[priv->precision],
-                  g_measurement_times[priv->precision], &raw_data.raw_temp,
-                  &raw_data.raw_hum);
-  if (err < 0)
+  if (start_thread)
     {
-#ifdef CONFIG_SHT4X_DEBUG
-      sht4x_dbg("Could not read device: %d\n", err);
-#endif
-      nxmutex_unlock(&priv->devlock);
-      return err;
-    }
-
-  /* Convert to proper units. */
+      /* Wake up the polling thread */
 
-  data.temp = sht4x_calc_temp(raw_data.raw_temp);
-  data.hum = sht4x_calc_hum(raw_data.raw_hum);
-
-  length = snprintf(buffer, buflen, "%ld m" SHT4X_TEMP_UNIT ", %d %%RH\n",
-                    data.temp, data.hum / 100);
-  if (length > buflen)
-    {
-      length = buflen;
+      nxsem_post(&dev->run);
     }
 
-  filep->f_pos += length;
-  nxmutex_unlock(&priv->devlock);
-  return length;
-}
-
-/****************************************************************************
- * Name: sht4x_write
- *
- * Description:
- *     Not implemented.
- ****************************************************************************/
-
-static ssize_t sht4x_write(FAR struct file *filep, FAR const char *buffer,
-                           size_t buflen)
-{
-  return -ENOSYS;
+  return 0;
 }
 
 /****************************************************************************
- * Name: sht4x_ioctl
+ * Name: sht4x_control
  ****************************************************************************/
 
-static int sht4x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
+static int sht4x_control(FAR struct sensor_lowerhalf_s *lower,
+                         FAR struct file *filep, int cmd, unsigned long arg)
 {
-  FAR struct inode *inode = filep->f_inode;
-  FAR struct sht4x_dev_s *priv = inode->i_private;
+  FAR struct sht4x_sensor_s *priv =
+      container_of(lower, FAR struct sht4x_sensor_s, sensor_lower);
+  FAR struct sht4x_dev_s *dev = priv->dev;
   int err;
 
-  err = nxmutex_lock(&priv->devlock);
+  err = nxmutex_lock(&dev->devlock);
   if (err < 0)
     {
       return err;
     }
 
-#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
-  if (priv->unlinked)
-    {
-      /* Do not allow operations on unlinked sensors. This allows
-       * sensor use on hot swappable I2C bus.
-       */
-
-      nxmutex_unlock(&priv->devlock);
-      return -ENODEV;
-    }
-#endif
-
   switch (cmd)
     {
     case SNIOC_RESET:
-      err = sht4x_reset(priv);
+      err = sht4x_reset(dev);
       break;
 
     case SNIOC_WHO_AM_I:
       {
         union sht4x_serialno_t serialno;
-        err = sht4x_cmd(priv, SHT4X_READ_SERIAL, 10, &serialno.halves.msb,
+        err = sht4x_cmd(dev, SHT4X_READ_SERIAL, 10, &serialno.halves.msb,
                         &serialno.halves.lsb);
         *((FAR uint32_t *)(arg)) = serialno.full;
       }
       break;
 
-    case SNIOC_READ_RAW_DATA:
-      err = sht4x_cmd(priv, g_precision_read[priv->precision],
-                      g_measurement_times[priv->precision],
-                      &((FAR struct sht4x_raw_data_s *)(arg))->raw_temp,
-                      &((FAR struct sht4x_raw_data_s *)(arg))->raw_hum);
-      break;
-
-    case SNIOC_MEASURE:
-    case SNIOC_READ_CONVERT_DATA:
-      {
-        uint16_t raw_t;
-        uint16_t raw_h;
-
-        err = sht4x_cmd(priv, g_precision_read[priv->precision],
-                        g_measurement_times[priv->precision],
-                        &raw_t, &raw_h);
-        ((FAR struct sht4x_conv_data_s *)(arg))->temp =
-            sht4x_calc_temp(raw_t);
-        ((FAR struct sht4x_conv_data_s *)(arg))->hum = sht4x_calc_hum(raw_h);
-      }
-      break;
-
     case SNIOC_HEAT:
       {
         struct timespec now;
@@ -705,23 +655,30 @@ static int sht4x_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
 
         /* Check if it has been one second since the last heat command. */
 
-        if (!has_time_passed(now, priv->last_heat, 1))
+        if (!has_time_passed(now, dev->last_heat, 1))
           {
             err = -EAGAIN; /* Signal to try again in some time. */
             break;
           }
 
-        /* Caller must pass heater option in the temperature argument. */
+        /* Check for invalid heater command */
+
+        if (0 < arg || arg >= (sizeof(g_heat_cmds) / sizeof(g_heat_cmds[0])))
+          {
+            return -EINVAL;
+          }
 
-        uint16_t raw_t = ((FAR struct sht4x_conv_data_s *)(arg))->temp;
-        uint16_t raw_h;
+        /* Heat for the desired period */
+
+        uint16_t trash;
+        err = sht4x_cmd(dev, g_heat_cmds[arg], g_heat_times[arg], &trash,
+                        &trash);
+        if (err)
+          {
+            break;
+          }
 
-        err = sht4x_cmd(priv, g_heat_cmds[raw_t], g_heat_times[raw_t],
-                        &raw_t, &raw_h);
-        ((FAR struct sht4x_conv_data_s *)(arg))->temp =
-            sht4x_calc_temp(raw_t);
-        ((FAR struct sht4x_conv_data_s *)(arg))->hum = sht4x_calc_hum(raw_h);
-        clock_systime_timespec(&priv->last_heat); /* Update last heat time. */
+        clock_systime_timespec(&dev->last_heat); /* Update last heat time. */
       }
       break;
 
@@ -729,11 +686,7 @@ static int sht4x_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
 
       /* Caller must pass precision option as argument. */
 
-      priv->precision = arg;
-#ifdef CONFIG_SHT4X_DEBUG
-      sht4x_dbg("Precision set to %d\n", priv->precision);
-#endif
-
+      dev->precision = arg;
       break;
 
     default:
@@ -741,47 +694,105 @@ static int sht4x_ioctl(FAR struct file *filep, int cmd, 
unsigned long arg)
       break;
     }
 
-  nxmutex_unlock(&priv->devlock);
+  nxmutex_unlock(&dev->devlock);
   return err;
 }
 
 /****************************************************************************
- * Name: sht4x_unlink
+ * Name: sht4x_fetch
  ****************************************************************************/
 
-#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
-static int sht4x_unlink(FAR struct inode *inode)
+#ifndef CONFIG_SENSORS_SHT4X_POLL
+static int sht4x_fetch(FAR struct sensor_lowerhalf_s *lower,
+                       FAR struct file *filep, FAR char *buffer,
+                       size_t buflen)
 {
-  FAR struct sht4x_dev_s *priv;
+  FAR struct sht4x_sensor_s *priv =
+      container_of(lower, FAR struct sht4x_sensor_s, sensor_lower);
+  FAR struct sht4x_dev_s *dev = priv->dev;
   int err;
 
-  DEBUGASSERT(inode->i_private != NULL);
-  priv = inode->i_private;
-
-  err = nxmutex_lock(&priv->devlock);
+  err = sht4x_read(dev, &humi_data, &temp_data);
   if (err < 0)
     {
       return err;
     }
 
-  /* Are there open references to the driver data structure? */
+  if (dev->hum.enabled)
+    {
+      dev->hum.sensor_lower.push_event(dev->hum.sensor_lower.priv,
+                                       &humi_data, sizeof(humi_data));
+    }
 
-  if (priv->crefs <= 0)
+  if (dev->temp.enabled)
     {
-      nxmutex_destroy(&priv->devlock);
-      kmm_free(priv);
-      return 0;
+      dev->temp.sensor_lower.push_event(dev->temp.sensor_lower.priv,
+                                        &temp_data, sizeof(temp_data));
     }
 
-  /* No. Just mark the driver as unlinked and free the resources when
-   * the last client closes their reference to the driver.
-   */
+  return err;
+}
+#endif /* CONFIG_SENSORS_SHT4X_POLL */
+
+/****************************************************************************
+ * Name: sht4x_thread
+ *
+ * Description: Thread for performing interval measurement cycle and data
+ *              read.
+ *
+ * Parameter:
+ *   argc - Number of arguments
+ *   argv - Pointer to argument list
+ *
+ ****************************************************************************/
+
+static int sht4x_thread(int argc, char **argv)
+{
+  FAR struct sht4x_dev_s *dev =
+      (FAR struct sht4x_dev_s *)((uintptr_t)strtoul(argv[1], NULL, 16));
+
+  struct sensor_temp temp_data;
+  struct sensor_humi humi_data;
+  int err;
+
+  while (true)
+    {
+      if (!dev->hum.enabled && !dev->temp.enabled)
+        {
+          /* Wait for one of the lower halves to be enabled and wake us up */
+
+          err = nxsem_wait(&dev->run);
+          if (err < 0)
+            {
+              continue;
+            }
+        }
+
+      err = sht4x_read(dev, &humi_data, &temp_data);
+      if (err < 0)
+        {
+          continue;
+        }
+
+      if (dev->hum.enabled)
+        {
+          dev->hum.sensor_lower.push_event(dev->hum.sensor_lower.priv,
+                                           &humi_data, sizeof(humi_data));
+        }
+
+      if (dev->temp.enabled)
+        {
+          dev->temp.sensor_lower.push_event(dev->temp.sensor_lower.priv,
+                                            &temp_data, sizeof(temp_data));
+        }
+
+      /* Sleep before next fetch */
+
+      nxsig_usleep(dev->interval);
+    }
 
-  priv->unlinked = true;
-  nxmutex_unlock(&priv->devlock);
   return OK;
 }
-#endif
 
 /****************************************************************************
  * Public Functions
@@ -805,11 +816,12 @@ static int sht4x_unlink(FAR struct inode *inode)
  *
  ****************************************************************************/
 
-int sht4x_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
-                   uint8_t addr)
+int sht4x_register(FAR struct i2c_master_s *i2c, int devno, uint8_t addr)
 {
   FAR struct sht4x_dev_s *priv;
   int err;
+  FAR char *argv[2];
+  char arg1[32];
 
   DEBUGASSERT(i2c != NULL);
   DEBUGASSERT(addr == 0x44 || addr == 0x45 || addr == 0x46);
@@ -826,6 +838,7 @@ int sht4x_register(FAR const char *devpath, FAR struct 
i2c_master_s *i2c,
   priv->i2c = i2c;
   priv->addr = addr;
   priv->precision = SHT4X_PREC_HIGH;
+  priv->interval = 1000000; /* 1s interval */
   err = clock_systime_timespec(&priv->last_heat);
 
   if (err < 0)
@@ -849,17 +862,74 @@ int sht4x_register(FAR const char *devpath, FAR struct 
i2c_master_s *i2c,
       return err;
     }
 
-  /* Register the character driver */
+  err = nxsem_init(&priv->run, 0, 0);
+  if (err < 0)
+    {
+      snerr("Failed to register SHT4X driver: %d\n", err);
+      nxmutex_destroy(&priv->devlock);
+      kmm_free(priv);
+      return err;
+    }
+
+  /* Register lower half for humidity */
+
+  priv->hum.sensor_lower.ops = &g_sensor_ops;
+  priv->hum.sensor_lower.type = SENSOR_TYPE_RELATIVE_HUMIDITY;
+  priv->hum.sensor_lower.uncalibrated = false;
+  priv->hum.enabled = false;
+  priv->hum.dev = priv;
 
-  err = register_driver(devpath, &g_sht4xfops, 0666, priv);
+  /* Register UORB Sensor */
+
+  err = sensor_register(&priv->hum.sensor_lower, devno);
   if (err < 0)
     {
-      snerr("ERROR: Failed to register SHT4X driver: %d\n", err);
+      snerr("Failed to register SHT4X driver: %d\n", err);
+      nxmutex_destroy(&priv->devlock);
+      nxsem_destroy(&priv->run);
+      kmm_free(priv);
+      return err;
+    }
+
+  /* Register lower half for temperature */
+
+  priv->temp.sensor_lower.ops = &g_sensor_ops;
+  priv->temp.sensor_lower.type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
+  priv->temp.sensor_lower.uncalibrated = false;
+  priv->temp.enabled = false;
+  priv->temp.dev = priv;
+
+  /* Register UORB Sensor */
+
+  err = sensor_register(&priv->temp.sensor_lower, devno);
+  if (err < 0)
+    {
+      snerr("Failed to register SHT4X driver: %d\n", err);
+      sensor_unregister(&priv->hum.sensor_lower, devno);
       nxmutex_destroy(&priv->devlock);
+      nxsem_destroy(&priv->run);
       kmm_free(priv);
+      return err;
     }
 
+  /* Polling thread */
+
+  snprintf(arg1, 16, "%p", priv);
+  argv[0] = arg1;
+  argv[1] = NULL;
+  err = kthread_create("sht4x_thread", SCHED_PRIORITY_DEFAULT,
+                       CONFIG_SHT4X_THREAD_STACKSIZE, sht4x_thread, argv);
+  if (err < 0)
+    {
+      snerr("Failed to create the SHT4X notification kthread.\n");
+      sensor_unregister(&priv->hum.sensor_lower, devno);
+      sensor_unregister(&priv->temp.sensor_lower, devno);
+      nxmutex_destroy(&priv->devlock);
+      nxsem_destroy(&priv->run);
+      kmm_free(priv);
+      return err;
+    }
+
+  sninfo("Registered SHT4X driver.\n");
   return err;
 }
-
-#endif /* CONFIG_I2C && CONFIG_SENSORS_SHT4X */
diff --git a/include/nuttx/sensors/sht4x.h b/include/nuttx/sensors/sht4x.h
index 0c2af21daf..6fe2fd1bd0 100644
--- a/include/nuttx/sensors/sht4x.h
+++ b/include/nuttx/sensors/sht4x.h
@@ -35,18 +35,6 @@
 
 struct i2c_master_s; /* Forward reference */
 
-struct sht4x_conv_data_s
-{
-  int32_t temp; /* Millidegrees Celsius or Fahrenheit (depending on config) */
-  int16_t hum;  /* Percentage relative humidity in units of 0.01 %RH */
-};
-
-struct sht4x_raw_data_s
-{
-  uint16_t raw_temp;
-  uint16_t raw_hum;
-};
-
 /* Precision for reading. */
 
 enum sht4x_precision_e
@@ -79,9 +67,9 @@ enum sht4x_heater_e
  *   Register the SHT4X character device as 'devpath'
  *
  * Input Parameters:
- *   devpath - The full path to the driver to register. E.g., "/dev/temp0"
  *   i2c     - An instance of the I2C interface to use to communicate with
  *             the SHT4X
+ *   devno   - The device number that this device should have.
  *   addr    - The I2C address of the SHT4X. The I2C address is one of 0x44,
  *             0x45 and 0x46.
  *
@@ -90,7 +78,6 @@ enum sht4x_heater_e
  *
  ****************************************************************************/
 
-int sht4x_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
-                   uint8_t addr);
+int sht4x_register(FAR struct i2c_master_s *i2c, int devno, uint8_t addr);
 
 #endif /* __INCLUDE_NUTTX_SENSORS_SHT4X_H */


Reply via email to