This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 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 1b8db1992e4 !sensors/hts221: Replace the legacy driver with a uORB
driver.
1b8db1992e4 is described below
commit 1b8db1992e406d59e0a171cdbab8c5729dde61ca
Author: raiden00pl <[email protected]>
AuthorDate: Mon May 5 16:25:42 2025 +0200
!sensors/hts221: Replace the legacy driver with a uORB driver.
BREAKING CHANGE: the legacy HTS221 character driver is removed, use
hts221_register_uorb() instead.
Assisted-by: Claude:claude-fable-5-1
Signed-off-by: raiden00pl <[email protected]>
---
Documentation/os/drivers/special/sensors.rst | 1 +
.../os/drivers/special/sensors/hts221.rst | 28 +
.../os/drivers/special/sensors/sensors_legacy.rst | 1 -
.../os/drivers/special/sensors/sensors_uorb.rst | 1 +
boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h | 2 +-
boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c | 2 +-
boards/arm/nrf52/nrf52840-dk/src/nrf52_hts221.c | 38 +-
.../olimex-stm32-p407/configs/mqttc/defconfig | 1 -
drivers/sensors/CMakeLists.txt | 2 +-
drivers/sensors/Kconfig | 13 +-
drivers/sensors/Make.defs | 2 +-
drivers/sensors/hts221.c | 1220 --------------------
drivers/sensors/hts221_uorb.c | 1216 +++++++++++++++++++
include/nuttx/sensors/hts221.h | 124 +-
14 files changed, 1289 insertions(+), 1362 deletions(-)
diff --git a/Documentation/os/drivers/special/sensors.rst
b/Documentation/os/drivers/special/sensors.rst
index a2a695fd0d7..52046f59f8a 100644
--- a/Documentation/os/drivers/special/sensors.rst
+++ b/Documentation/os/drivers/special/sensors.rst
@@ -49,3 +49,4 @@ tool for monitoring sensor activity at runtime.
sensors/gnss_lowerhalf.rst
sensors/bh1745nuc.rst
sensors/lps22hb.rst
+ sensors/hts221.rst
diff --git a/Documentation/os/drivers/special/sensors/hts221.rst
b/Documentation/os/drivers/special/sensors/hts221.rst
new file mode 100644
index 00000000000..288cd35ba12
--- /dev/null
+++ b/Documentation/os/drivers/special/sensors/hts221.rst
@@ -0,0 +1,28 @@
+======
+HTS221
+======
+
+STMicroelectronics HTS221 humidity and temperature sensor on I2C,
+:doc:`uORB </os/drivers/special/sensors/sensors_uorb>` interface.
+
+Configuration
+=============
+
+- ``CONFIG_SENSORS_HTS221``
+- ``CONFIG_HTS221_I2C_FREQUENCY``
+
+Usage
+=====
+
+.. code-block:: c
+
+ #include <nuttx/sensors/hts221.h>
+
+ int hts221_register_uorb(int devno, FAR struct i2c_master_s *i2c,
+ uint8_t addr, FAR hts221_config_t *config);
+
+Registers ``sensor_ambient_temp<devno>`` (°C) and ``sensor_humi<devno>``
+(%rH). ``config`` holds the optional data-ready interrupt and power
+callbacks; with the interrupt the interval selects the 1, 7 or 12.5 Hz
+output data rate, without it the sensor is polled in one-shot mode.
+``SNIOC_OVERSAMPLING`` sets the number of averaged samples per topic.
diff --git a/Documentation/os/drivers/special/sensors/sensors_legacy.rst
b/Documentation/os/drivers/special/sensors/sensors_legacy.rst
index 44a920d889d..91719d3df55 100644
--- a/Documentation/os/drivers/special/sensors/sensors_legacy.rst
+++ b/Documentation/os/drivers/special/sensors/sensors_legacy.rst
@@ -35,7 +35,6 @@ Drivers that are available also with the new sensor framework
are marked with ``
- hall3ph
- hc_sr04
- hdc1008
-- hts221
- ina219
- ina226
- ina3221
diff --git a/Documentation/os/drivers/special/sensors/sensors_uorb.rst
b/Documentation/os/drivers/special/sensors/sensors_uorb.rst
index 446302ff216..2f7630e1492 100644
--- a/Documentation/os/drivers/special/sensors/sensors_uorb.rst
+++ b/Documentation/os/drivers/special/sensors/sensors_uorb.rst
@@ -559,6 +559,7 @@ Implemented Drivers
- gnss
- goldfish_gnss
- goldfish_sensor
+- :doc:`hts221`
- hyt271
- l3gd20
- :doc:`lis2mdl`
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h
b/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h
index bbb3d58430c..35877761b1a 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52840-dk.h
@@ -149,7 +149,7 @@ int nrf52_lsm303agr_initialize(char *devpath);
****************************************************************************/
#ifdef CONFIG_SENSORS_HTS221
-int nrf52_hts221_initialize(char *devpath);
+int nrf52_hts221_initialize(int devno);
#endif
/****************************************************************************
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
b/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
index 0a6ae05d9bc..e43d87ab134 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_bringup.c
@@ -210,7 +210,7 @@ int nrf52_bringup(void)
#endif /* CONFIG_SENSORS_LSM303AGR */
#ifdef CONFIG_SENSORS_HTS221
- ret = nrf52_hts221_initialize("/dev/hts2210");
+ ret = nrf52_hts221_initialize(0);
if (ret < 0)
{
syslog(LOG_ERR,
diff --git a/boards/arm/nrf52/nrf52840-dk/src/nrf52_hts221.c
b/boards/arm/nrf52/nrf52840-dk/src/nrf52_hts221.c
index a621d1cf1e0..ee7c04a18fd 100644
--- a/boards/arm/nrf52/nrf52840-dk/src/nrf52_hts221.c
+++ b/boards/arm/nrf52/nrf52840-dk/src/nrf52_hts221.c
@@ -51,8 +51,6 @@
* Private Function Prototypes
****************************************************************************/
-static int nrf52_hts221_irq_attach(struct hts221_config_s *state,
- xcpt_t isr, void *arg);
static void nrf52_hts221_irq_enable(const struct hts221_config_s *state,
bool enable);
static void nrf52_hts221_irq_clear(const struct hts221_config_s *state);
@@ -65,7 +63,7 @@ static int nrf52_hts221_set_power(const struct
hts221_config_s *state,
static hts221_config_t g_hts221_config =
{
- .irq_attach = nrf52_hts221_irq_attach,
+ .irq_attach = NULL, /* DRDY not wired, the driver polls */
.irq_enable = nrf52_hts221_irq_enable,
.irq_clear = nrf52_hts221_irq_clear,
.set_power = nrf52_hts221_set_power
@@ -75,22 +73,6 @@ static hts221_config_t g_hts221_config =
* Private Functions
****************************************************************************/
-/****************************************************************************
- * Name: nrf52_hts221_irq_attach
- ****************************************************************************/
-
-static int nrf52_hts221_irq_attach(struct hts221_config_s *state,
- xcpt_t isr, void *arg)
-{
- sinfo("Attach HTS221 IRQ\n");
-
- /* TODO: IRQ on rising edge */
-
- /* nrf52_gpiosetevent(GPIO_HTS221_IRQ, true, false, false, isr, arg); */
-
- return OK;
-}
-
/****************************************************************************
* Name: nrf52_hts221_irq_enable
****************************************************************************/
@@ -130,32 +112,30 @@ static int nrf52_hts221_set_power(const struct
hts221_config_s *state,
*
****************************************************************************/
-int nrf52_hts221_initialize(char *devpath)
+int nrf52_hts221_initialize(int devno)
{
struct i2c_master_s *i2c;
- int ret = OK;
+ int ret;
sninfo("Initializing HTS221!\n");
-#ifdef CONFIG_NRF52_I2C0_MASTER
i2c = nrf52_i2cbus_initialize(0);
if (i2c == NULL)
{
return -ENODEV;
}
- sninfo("INFO: Initializing HTS221 hum-temp sensor over I2C%d\n", ret);
+ sninfo("INFO: Initializing HTS221 hum-temp sensor over I2C0\n");
- ret = hts221_register(devpath, i2c, HTS221HUM_ADDR, &g_hts221_config);
+ ret = hts221_register_uorb(devno, i2c, HTS221HUM_ADDR, &g_hts221_config);
if (ret < 0)
{
- snerr("ERROR: Failed to initialize HTS221 hum-temp driver %s\n",
- devpath);
- return -ENODEV;
+ snerr("ERROR: Failed to initialize HTS221 hum-temp driver: %d\n",
+ ret);
+ return ret;
}
sninfo("INFO: HTS221 sensor has been initialized successfully\n");
-#endif
- return ret;
+ return OK;
}
diff --git a/boards/arm/stm32f4/olimex-stm32-p407/configs/mqttc/defconfig
b/boards/arm/stm32f4/olimex-stm32-p407/configs/mqttc/defconfig
index 6dc5ccbb18b..f2acbb04e7a 100644
--- a/boards/arm/stm32f4/olimex-stm32-p407/configs/mqttc/defconfig
+++ b/boards/arm/stm32f4/olimex-stm32-p407/configs/mqttc/defconfig
@@ -26,7 +26,6 @@ CONFIG_FS_FAT=y
CONFIG_FS_PROCFS=y
CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
-CONFIG_HTS221_DEBUG=y
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_INTELHEX_BINARY=y
CONFIG_LIBM=y
diff --git a/drivers/sensors/CMakeLists.txt b/drivers/sensors/CMakeLists.txt
index e062a53e9d7..ac9e8088092 100644
--- a/drivers/sensors/CMakeLists.txt
+++ b/drivers/sensors/CMakeLists.txt
@@ -249,7 +249,7 @@ if(CONFIG_SENSORS)
endif()
if(CONFIG_SENSORS_HTS221)
- list(APPEND SRCS hts221.c)
+ list(APPEND SRCS hts221_uorb.c)
endif()
if(CONFIG_SENSORS_LIS2MDL)
diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig
index 786ea1e0a06..6cfd31c83d3 100644
--- a/drivers/sensors/Kconfig
+++ b/drivers/sensors/Kconfig
@@ -866,6 +866,7 @@ config SENSORS_HTS221
bool "STMicro HTS221 humidity sensor"
default n
select I2C
+ select SCHED_LPWORK
---help---
Enable driver support for the STMicro HTS221 humidity sensor.
@@ -876,18 +877,6 @@ config HTS221_I2C_FREQUENCY
default 400000
range 1 400000
-config HTS221_DEBUG
- bool "Debug support for the HTS221"
- default n
- ---help---
- Enables debug features for the HTS221
-
-config HTS221_NPOLLWAITERS
- int "Number of waiters to poll"
- default 1
- ---help---
- Number of waiters to poll
-
endif # SENSORS_HTS221
config SENSORS_L3GD20
diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs
index e643938382e..fc230481f4b 100644
--- a/drivers/sensors/Make.defs
+++ b/drivers/sensors/Make.defs
@@ -243,7 +243,7 @@ ifeq ($(CONFIG_SENSORS_ISL29023),y)
endif
ifeq ($(CONFIG_SENSORS_HTS221),y)
- CSRCS += hts221.c
+ CSRCS += hts221_uorb.c
endif
ifeq ($(CONFIG_SENSORS_LIS2MDL),y)
diff --git a/drivers/sensors/hts221.c b/drivers/sensors/hts221.c
deleted file mode 100644
index 4da88fa26d2..00000000000
--- a/drivers/sensors/hts221.c
+++ /dev/null
@@ -1,1220 +0,0 @@
-/****************************************************************************
- * drivers/sensors/hts221.c
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- ****************************************************************************/
-
-/* WARNING for developers:
- *
- * This driver uses the legacy style of writing sensor drivers for NuttX. The
- * project has since decided to adopt a new sensor framework in order to
- * have a consistent API and feature-set.
- *
- * Sensors which use the uORB framework are typically suffixed "_uorb". You
- * can also visit the documentation about the new sensor framework to learn
- * more.
- */
-
-#warning "This is a deprecated legacy sensor driver."
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-#include <nuttx/config.h>
-
-#include <sys/types.h>
-#include <assert.h>
-#include <nuttx/debug.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <errno.h>
-
-#include <nuttx/arch.h>
-#include <nuttx/fs/fs.h>
-#include <nuttx/i2c/i2c_master.h>
-#include <nuttx/irq.h>
-#include <nuttx/kmalloc.h>
-#include <nuttx/mutex.h>
-#include <nuttx/poll.h>
-#include <nuttx/signal.h>
-#include <nuttx/random.h>
-
-#include <nuttx/sensors/hts221.h>
-
-/****************************************************************************
- * Pre-Processor Definitions
- ****************************************************************************/
-
-#ifdef CONFIG_HTS221_DEBUG
-# define hts221_dbg(x, ...) _info(x, ##__VA_ARGS__)
-#else
-# define hts221_dbg(x, ...) sninfo(x, ##__VA_ARGS__)
-#endif
-
-#define HTS221_WHO_AM_I 0x0f
-#define HTS221_AV_CONF 0x10
-#define HTS221_CTRL_REG1 0x20
-#define HTS221_CTRL_REG2 0x21
-#define HTS221_CTRL_REG3 0x22
-#define HTS221_STATUS_REG 0x27
-#define HTS221_HUM_OUT_L 0x28
-#define HTS221_HUM_OUT_H 0x29
-#define HTS221_TEMP_OUT_L 0x2a
-#define HTS221_TEMP_OUT_H 0x2b
-
-/* Calibration registers */
-
-#define HTS221_CALIB_H0_RH_X2 0x30
-#define HTS221_CALIB_H1_RH_X2 0x31
-#define HTS221_CALIB_T0_DEGC_X8 0x32
-#define HTS221_CALIB_T1_DEGC_X8 0x33
-#define HTS221_CALIB_T1_T0_MSB 0x35
-#define HTS221_CALIB_H0T0_OUT_L 0x36
-#define HTS221_CALIB_H0T0_OUT_H 0x37
-#define HTS221_CALIB_H1T0_OUT_L 0x3a
-#define HTS221_CALIB_H1T0_OUT_H 0x3b
-#define HTS221_CALIB_T0_OUT_L 0x3c
-#define HTS221_CALIB_T0_OUT_H 0x3d
-#define HTS221_CALIB_T1_OUT_L 0x3e
-#define HTS221_CALIB_T1_OUT_H 0x3f
-
-/* HTS221_CTRL_REG1 */
-
-#define HTS221_CTRL_REG1_PD (1 << 7)
-#define HTS221_CTRL_REG1_BDU (1 << 2)
-
-/* HTS221_CTRL_REG2 */
-
-#define HTS221_CTRL_REG2_BOOT (1 << 7)
-#define HTS221_CTRL_REG2_ONE_SHOT (1 << 0)
-
-/* HTS221_CTRL_REG3 */
-
-#define HTS221_CTRL_REG3_DRDY_L_H (1 << 7)
-#define HTS221_CTRL_REG3_PP_OD (1 << 6)
-#define HTS221_CTRL_REG3_DRDY_EN (1 << 2)
-
-/* HTS221_STATUS_REG */
-
-#define HTS221_STATUS_REG_H_DA (1 << 1)
-#define HTS221_STATUS_REG_T_DA (1 << 0)
-
-#define HTS221_I2C_RETRIES 10
-
-/****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
-
-static int hts221_open(FAR struct file *filep);
-static int hts221_close(FAR struct file *filep);
-static ssize_t hts221_read(FAR struct file *filep, FAR char *buffer,
- size_t buflen);
-static ssize_t hts221_write(FAR struct file *filep, FAR const char *buffer,
- size_t buflen);
-static int hts221_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
-static int hts221_poll(FAR struct file *filep, FAR struct pollfd_s *fds,
- bool setup);
-
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-struct hts221_dev_s
-{
- FAR struct i2c_master_s *i2c;
- uint8_t addr;
- FAR hts221_config_t *config;
- mutex_t devlock;
- volatile bool int_pending;
- FAR struct pollfd_s *fds[CONFIG_HTS221_NPOLLWAITERS];
- struct
- {
- int16_t t0_out;
- int16_t t1_out;
- int16_t h0_t0_out;
- int16_t h1_t0_out;
- unsigned int t0_x8:10;
- unsigned int t1_x8:10;
- uint8_t h0_x2;
- uint8_t h1_x2;
- } calib;
-};
-
-/****************************************************************************
- * Private Data
- ****************************************************************************/
-
-static const struct file_operations g_humidityops =
-{
- hts221_open, /* open */
- hts221_close, /* close */
- hts221_read, /* read */
- hts221_write, /* write */
- NULL, /* seek */
- hts221_ioctl, /* ioctl */
- NULL, /* mmap */
- NULL, /* truncate */
- hts221_poll /* poll */
-};
-
-/****************************************************************************
- * Private Functions
- ****************************************************************************/
-
-static int hts221_do_transfer(FAR struct hts221_dev_s *priv,
- FAR struct i2c_msg_s *msgv,
- size_t nmsg)
-{
- int ret = -EIO;
- int retries;
-
- for (retries = 0; retries < HTS221_I2C_RETRIES; retries++)
- {
- ret = I2C_TRANSFER(priv->i2c, msgv, nmsg);
- if (ret >= 0)
- {
- return 0;
- }
- else
- {
- /* Some error. Try to reset I2C bus and keep trying. */
-
-#ifdef CONFIG_I2C_RESET
- if (retries == HTS221_I2C_RETRIES - 1)
- {
- break;
- }
-
- ret = I2C_RESET(priv->i2c);
- if (ret < 0)
- {
- hts221_dbg("I2C_RESET failed: %d\n", ret);
- return ret;
- }
-#endif
- }
- }
-
- hts221_dbg("xfer failed: %d\n", ret);
- return ret;
-}
-
-static int32_t hts221_write_reg8(FAR struct hts221_dev_s *priv,
- const uint8_t *command)
-{
- struct i2c_msg_s msgv[2] =
- {
- {
- .frequency = CONFIG_HTS221_I2C_FREQUENCY,
- .addr = priv->addr,
- .flags = 0,
- .buffer = (FAR void *)&command[0],
- .length = 1
- },
- {
- .frequency = CONFIG_HTS221_I2C_FREQUENCY,
- .addr = priv->addr,
- .flags = I2C_M_NOSTART,
- .buffer = (FAR void *)&command[1],
- .length = 1
- }
- };
-
- return hts221_do_transfer(priv, msgv, 2);
-}
-
-static int hts221_read_reg(FAR struct hts221_dev_s *priv,
- FAR const uint8_t *command, FAR uint8_t *value)
-{
- struct i2c_msg_s msgv[2] =
- {
- {
- .frequency = CONFIG_HTS221_I2C_FREQUENCY,
- .addr = priv->addr,
- .flags = 0,
- .buffer = (FAR void *)command,
- .length = 1
- },
- {
- .frequency = CONFIG_HTS221_I2C_FREQUENCY,
- .addr = priv->addr,
- .flags = I2C_M_READ,
- .buffer = value,
- .length = 1
- }
- };
-
- return hts221_do_transfer(priv, msgv, 2);
-}
-
-static int hts221_get_id(FAR struct hts221_dev_s *priv, uint8_t *value)
-{
- int ret = OK;
- uint8_t cmd = HTS221_WHO_AM_I;
-
- ret = hts221_read_reg(priv, &cmd, value);
-
- hts221_dbg("Who am I request: 0x%02X\n", *value);
-
- return ret;
-}
-
-static int hts221_cfgr_resolution(FAR struct hts221_dev_s *priv,
- FAR hts221_settings_t *settings)
-{
- int ret;
- uint8_t value;
- const uint8_t addr = HTS221_AV_CONF;
- uint8_t regval = 0;
- uint8_t cmd[2] =
- {
- 0
- };
-
- const uint8_t mask = 0x3f;
-
- ret = hts221_read_reg(priv, &addr, ®val);
- hts221_dbg("Default resolution: 0x%02X\n", regval);
- if (ret < 0)
- {
- return ERROR;
- }
-
- value = (uint8_t)settings->humid_resol |
- ((uint8_t)settings->temp_resol << 3);
- regval &= ~mask;
- cmd[0] = addr;
- cmd[1] = regval | value;
- hts221_dbg("New resolution: 0x%02X\n", cmd[1]);
-
- ret = hts221_write_reg8(priv, cmd);
-
- hts221_dbg("Resolution changed: temp=%d humid=%d ret=%d\n",
- settings->temp_resol, settings->humid_resol, ret);
-
- return ret;
-}
-
-static int hts221_config_ctrl_reg3(FAR struct hts221_dev_s *priv,
- FAR hts221_settings_t *settings)
-{
- int ret = OK;
- uint8_t regval = 0;
- uint8_t addr = HTS221_CTRL_REG3;
- const uint8_t mask = 0xc4;
- uint8_t data_to_write[2] =
- {
- 0
- };
-
- ret = hts221_read_reg(priv, &addr, ®val);
- hts221_dbg("CTRL_REG%d: 0x%02X\n", 3, regval);
- if (ret < 0)
- {
- return ERROR;
- }
-
- regval &= ~mask;
- regval |= (uint8_t)(settings->is_high_edge ?
- 0 : HTS221_CTRL_REG3_DRDY_L_H);
- regval |= (uint8_t)(settings->is_open_drain ? HTS221_CTRL_REG3_PP_OD : 0);
- regval |= (uint8_t)(settings->is_data_rdy ? HTS221_CTRL_REG3_DRDY_EN : 0);
-
- data_to_write[0] = addr;
- data_to_write[1] = regval;
-
- ret = hts221_write_reg8(priv, data_to_write);
- if (ret >= 0)
- {
- ret = hts221_read_reg(priv, &addr, ®val);
- if (ret >= 0)
- {
- hts221_dbg("wrote 0x%02X => CTRL_REG%d: 0x%02X\n",
- data_to_write[1], 3, regval);
- }
- }
-
- return ret;
-}
-
-static int hts221_config_ctrl_reg2(FAR struct hts221_dev_s *priv,
- FAR hts221_settings_t *settings)
-{
- int ret = OK;
- uint8_t regval = 0;
- uint8_t addr = HTS221_CTRL_REG2;
- const uint8_t mask = 0x80;
- uint8_t data_to_write[2] =
- {
- 0
- };
-
- int retries = 5;
-
- if (!settings->is_boot)
- {
- return OK;
- }
-
- ret = hts221_read_reg(priv, &addr, ®val);
- hts221_dbg("CTRL_REG%d: 0x%02X\n", 2, regval);
-
- if (ret < 0)
- {
- return ERROR;
- }
-
- regval &= ~mask;
- regval |= HTS221_CTRL_REG2_BOOT;
-
- data_to_write[0] = addr;
- data_to_write[1] = regval;
-
- ret = hts221_write_reg8(priv, data_to_write);
- if (ret >= 0)
- {
- /* Wait until boot bit is cleared. */
-
- do
- {
- ret = hts221_read_reg(priv, &addr, ®val);
- if (ret >= 0)
- {
- hts221_dbg("wrote 0x%02X => CTRL_REG%d: 0x%02X\n",
- data_to_write[1], 2, regval);
- }
- else
- {
- break;
- }
-
- if ((regval & HTS221_CTRL_REG2_BOOT) == 0)
- {
- /* After boot bit is cleared, wait additional 5 msec as
- * recommended in HTS221 application note.
- */
-
- up_mdelay(5);
- break;
- }
-
- nxsched_usleep(10 * 1000);
- retries--;
- }
- while (retries);
-
- if (ret >= 0 && (regval & HTS221_CTRL_REG2_BOOT) != 0)
- {
- ret = -ETIMEDOUT;
- }
- }
-
- return ret;
-}
-
-static int hts221_config_ctrl_reg1(FAR struct hts221_dev_s *priv,
- FAR hts221_settings_t *settings)
-{
- int ret = OK;
- uint8_t regval = 0;
- uint8_t addr = HTS221_CTRL_REG1;
- const uint8_t mask = 0x87;
- uint8_t data_to_write[2] =
- {
- 0
- };
-
- ret = hts221_read_reg(priv, &addr, ®val);
- hts221_dbg("CTRL_REG%d: 0x%02X\n", 1, regval);
- if (ret < 0)
- {
- return ERROR;
- }
-
- regval &= ~mask;
- regval |= (uint8_t)(settings->odr & 0xff);
- regval |= (uint8_t)(settings->is_bdu ? HTS221_CTRL_REG1_BDU : 0);
-
- data_to_write[0] = addr;
- data_to_write[1] = regval;
-
- ret = hts221_write_reg8(priv, data_to_write);
- if (ret >= 0)
- {
- ret = hts221_read_reg(priv, &addr, ®val);
- if (ret >= 0)
- {
- hts221_dbg("wrote 0x%02X => CTRL_REG%d: 0x%02X\n",
- data_to_write[1], 1, regval);
- }
- }
-
- return ret;
-}
-
-static int hts221_power_on_off(FAR struct hts221_dev_s *priv, bool on)
-{
- int ret = OK;
- uint8_t regval = 0;
- uint8_t addr = HTS221_CTRL_REG1;
- uint8_t data_to_write[2];
-
- ret = hts221_read_reg(priv, &addr, ®val);
- hts221_dbg("CTRL_REG%d: 0x%02X\n", 1, regval);
- if (ret < 0)
- {
- return ret;
- }
-
- if (on)
- {
- regval |= HTS221_CTRL_REG1_PD;
- }
- else
- {
- regval &= ~HTS221_CTRL_REG1_PD;
- }
-
- data_to_write[0] = addr;
- data_to_write[1] = regval;
-
- ret = hts221_write_reg8(priv, data_to_write);
- if (ret >= 0)
- {
- ret = hts221_read_reg(priv, &addr, ®val);
- if (ret >= 0)
- {
- hts221_dbg("wrote 0x%02X => CTRL_REG%d: 0x%02X\n",
- data_to_write[1], 1, regval);
- }
- }
-
- return ret;
-}
-
-static int hts221_config(FAR struct hts221_dev_s *priv,
- FAR hts221_settings_t *cfgr)
-{
- int ret = OK;
-
- ret = hts221_config_ctrl_reg2(priv, cfgr); /* Performs sensor reset. */
- if (ret < 0)
- {
- return ERROR;
- }
-
- ret = hts221_cfgr_resolution(priv, cfgr);
- if (ret < 0)
- {
- return ERROR;
- }
-
- ret = hts221_config_ctrl_reg3(priv, cfgr);
- if (ret < 0)
- {
- return ERROR;
- }
-
- ret = hts221_config_ctrl_reg1(priv, cfgr);
- if (ret < 0)
- {
- return ERROR;
- }
-
- return ret;
-}
-
-static int hts221_start_conversion(FAR struct hts221_dev_s *priv)
-{
- int ret;
- uint8_t addr = HTS221_CTRL_REG2;
- uint8_t data_to_write[2];
-
- ret = hts221_power_on_off(priv, true);
- if (ret < 0)
- {
- return ERROR;
- }
-
- data_to_write[0] = addr;
- data_to_write[1] = (uint8_t) HTS221_CTRL_REG2_ONE_SHOT;
-
- ret = hts221_write_reg8(priv, data_to_write);
- if (ret < 0)
- {
- hts221_dbg("Cannot start conversion\n");
- ret = ERROR;
- }
-
- return ret;
-}
-
-static int hts221_check_status(FAR struct hts221_dev_s *priv,
- FAR hts221_status_t *status)
-{
- int ret = OK;
- uint8_t addr = HTS221_STATUS_REG;
- const uint8_t humid_mask = 0x02;
- const uint8_t temp_mask = 0x01;
- uint8_t regval = 0;
-
- ret = hts221_read_reg(priv, &addr, ®val);
- if (ret < 0)
- {
- return ERROR;
- }
-
- status->is_humid_ready = ((regval & humid_mask) ? true : false);
- status->is_temp_ready = ((regval & temp_mask) ? true : false);
-
- return ret;
-}
-
-static int hts221_read_raw_data(FAR struct hts221_dev_s *priv,
- FAR hts221_raw_data_t *data)
-{
- int ret = OK;
- uint8_t addr_humid_low = HTS221_HUM_OUT_L;
- uint8_t addr_humid_high = HTS221_HUM_OUT_H;
- uint8_t addr_temp_low = HTS221_TEMP_OUT_L;
- uint8_t addr_temp_high = HTS221_TEMP_OUT_H;
- irqstate_t flags;
-
- ret = hts221_read_reg(priv, &addr_humid_low, &data->humid_low_bits);
- if (ret < 0)
- {
- return ERROR;
- }
-
- ret = hts221_read_reg(priv, &addr_humid_high, &data->humid_high_bits);
- if (ret < 0)
- {
- return ERROR;
- }
-
- ret = hts221_read_reg(priv, &addr_temp_low, &data->temp_low_bits);
- if (ret < 0)
- {
- return ERROR;
- }
-
- ret = hts221_read_reg(priv, &addr_temp_high, &data->temp_high_bits);
- if (ret < 0)
- {
- return ERROR;
- }
-
- /* Add low-order bytes to entropy pool. */
-
- add_sensor_randomness(((uint32_t)data->humid_low_bits << 8) |
- data->temp_low_bits);
-
- flags = enter_critical_section();
- priv->int_pending = false;
- leave_critical_section(flags);
-
- hts221_dbg("Humid: 0x%02X, 0x%02X Temper: 0x%02X 0x%02X\n",
- data->humid_high_bits, data->humid_low_bits,
- data->temp_high_bits, data->temp_low_bits);
-
- return ret;
-}
-
-static int hts221_load_calibration_data(FAR struct hts221_dev_s *priv)
-{
- int ret;
- uint8_t addr;
- uint8_t t0_degc_x8 = 0;
- uint8_t t1_degc_x8 = 0;
- uint8_t t1_t0_msb = 0;
- uint8_t t0_out_lsb = 0;
- uint8_t t0_out_msb = 0;
- uint8_t t1_out_lsb = 0;
- uint8_t t1_out_msb = 0;
- uint8_t h0_rh_x2 = 0;
- uint8_t h1_rh_x2 = 0;
- uint8_t h0t0_out_lsb = 0;
- uint8_t h0t0_out_msb = 0;
- uint8_t h1t0_out_lsb = 0;
- uint8_t h1t0_out_msb = 0;
-
- addr = HTS221_CALIB_T0_DEGC_X8;
- ret = hts221_read_reg(priv, &addr, &t0_degc_x8);
- if (ret < 0)
- {
- return ret;
- }
-
- addr = HTS221_CALIB_T1_DEGC_X8;
- ret = hts221_read_reg(priv, &addr, &t1_degc_x8);
- if (ret < 0)
- {
- return ret;
- }
-
- addr = HTS221_CALIB_T1_T0_MSB;
- ret = hts221_read_reg(priv, &addr, &t1_t0_msb);
- if (ret < 0)
- {
- return ret;
- }
-
- addr = HTS221_CALIB_T0_OUT_L;
- ret = hts221_read_reg(priv, &addr, &t0_out_lsb);
- if (ret < 0)
- {
- return ret;
- }
-
- addr = HTS221_CALIB_T0_OUT_H;
- ret = hts221_read_reg(priv, &addr, &t0_out_msb);
- if (ret < 0)
- {
- return ret;
- }
-
- addr = HTS221_CALIB_T1_OUT_L;
- ret = hts221_read_reg(priv, &addr, &t1_out_lsb);
- if (ret < 0)
- {
- return ret;
- }
-
- addr = HTS221_CALIB_T1_OUT_H;
- ret = hts221_read_reg(priv, &addr, &t1_out_msb);
- if (ret < 0)
- {
- return ret;
- }
-
- addr = HTS221_CALIB_H0_RH_X2;
- ret = hts221_read_reg(priv, &addr, &h0_rh_x2);
- if (ret < 0)
- {
- return ret;
- }
-
- addr = HTS221_CALIB_H1_RH_X2;
- ret = hts221_read_reg(priv, &addr, &h1_rh_x2);
- if (ret < 0)
- {
- return ret;
- }
-
- addr = HTS221_CALIB_H0T0_OUT_L;
- ret = hts221_read_reg(priv, &addr, &h0t0_out_lsb);
- if (ret < 0)
- {
- return ret;
- }
-
- addr = HTS221_CALIB_H0T0_OUT_H;
- ret = hts221_read_reg(priv, &addr, &h0t0_out_msb);
- if (ret < 0)
- {
- return ret;
- }
-
- addr = HTS221_CALIB_H1T0_OUT_L;
- ret = hts221_read_reg(priv, &addr, &h1t0_out_lsb);
- if (ret < 0)
- {
- return ret;
- }
-
- addr = HTS221_CALIB_H1T0_OUT_H;
- ret = hts221_read_reg(priv, &addr, &h1t0_out_msb);
- if (ret < 0)
- {
- return ret;
- }
-
- priv->calib.t0_x8 = t0_degc_x8 | ((t1_t0_msb & 0x3) << 8);
- priv->calib.t1_x8 = t1_degc_x8 | ((t1_t0_msb & (0x3 << 2)) << (8 - 2));
- priv->calib.t0_out = (uint16_t) (t0_out_lsb | (t0_out_msb << 8));
- priv->calib.t1_out = (uint16_t) (t1_out_lsb | (t1_out_msb << 8));
- priv->calib.h0_x2 = h0_rh_x2;
- priv->calib.h1_x2 = h1_rh_x2;
- priv->calib.h0_t0_out = (uint16_t) (h0t0_out_lsb | (h0t0_out_msb << 8));
- priv->calib.h1_t0_out = (uint16_t) (h1t0_out_lsb | (h1t0_out_msb << 8));
-
- hts221_dbg("calib.t0_x8: %d\n", priv->calib.t0_x8);
- hts221_dbg("calib.t1_x8: %d\n", priv->calib.t1_x8);
- hts221_dbg("calib.t0_out: %d\n", priv->calib.t0_out);
- hts221_dbg("calib.t1_out: %d\n", priv->calib.t1_out);
- hts221_dbg("calib.h0_x2: %d\n", priv->calib.h0_x2);
- hts221_dbg("calib.h1_x2: %d\n", priv->calib.h1_x2);
- hts221_dbg("calib.h0_t0_out: %d\n", priv->calib.h0_t0_out);
- hts221_dbg("calib.h1_t0_out: %d\n", priv->calib.h1_t0_out);
-
- /* As calibration coefficients are unique to each sensor device,
- * they are a good candidate to be added to entropy pool.
- */
-
- up_rngaddentropy(RND_SRC_HW, (FAR uint32_t *)&priv->calib,
- sizeof(priv->calib) / sizeof(uint32_t));
-
- return OK;
-}
-
-static int hts221_calculate_temperature(FAR struct hts221_dev_s *priv,
- FAR int *temperature,
- FAR hts221_raw_data_t *raw_data)
-{
- int16_t t_out = (raw_data->temp_high_bits << 8) | raw_data->temp_low_bits;
- int x0 = priv->calib.t0_out;
- int x1 = priv->calib.t1_out;
- int y0 = priv->calib.t0_x8;
- int y1 = priv->calib.t1_x8;
- int x = t_out;
- int64_t y;
- int x1_x0_diff;
-
- x1_x0_diff = x1 - x0;
-
- y = (y0 * x1_x0_diff + (y1 - y0) * (x - x0));
- y *= HTS221_TEMPERATURE_PRECISION;
- y /= x1_x0_diff * 8;
-
- *temperature = (int)y;
-
- hts221_dbg("Interpolation data temper: %d\n", *temperature);
-
- return OK;
-}
-
-static int hts221_calculate_humidity(FAR struct hts221_dev_s *priv,
- FAR unsigned int *humidity,
- FAR hts221_raw_data_t *raw_data)
-{
- int16_t h_out;
- int x0 = priv->calib.h0_t0_out;
- int x1 = priv->calib.h1_t0_out;
- int y0 = priv->calib.h0_x2;
- int y1 = priv->calib.h1_x2;
- int x;
- int64_t y;
- int x1_x0_diff;
-
- h_out = (raw_data->humid_high_bits << 8) | raw_data->humid_low_bits;
- x = h_out;
- x1_x0_diff = x1 - x0;
-
- y = (y0 * x1_x0_diff + (y1 - y0) * (x - x0));
- y *= HTS221_HUMIDITY_PRECISION;
- y /= x1_x0_diff * 2;
-
- *humidity = (int)y;
-
- hts221_dbg("Interpolation data humidity: %d\n", *humidity);
-
- return OK;
-}
-
-static int hts221_read_convert_data(FAR struct hts221_dev_s *priv,
- FAR hts221_conv_data_t *data)
-{
- int ret = OK;
- hts221_raw_data_t raw_data;
-
- ret = hts221_read_raw_data(priv, &raw_data);
- if (ret < 0)
- {
- return ERROR;
- }
-
- ret = hts221_calculate_temperature(priv, &data->temperature, &raw_data);
- if (ret < 0)
- {
- return ERROR;
- }
-
- hts221_dbg("Temperature calculated\n");
-
- ret = hts221_calculate_humidity(priv, &data->humidity, &raw_data);
- if (ret < 0)
- {
- return ERROR;
- }
-
- hts221_dbg("Humidity calculated\n");
- return ret;
-}
-
-#ifdef CONFIG_HTS221_DEBUG
-static int hts221_dump_registers(FAR struct hts221_dev_s *priv)
-{
- int ret = OK;
- uint8_t av_addr = HTS221_AV_CONF;
- uint8_t ctrl_reg1_addr = HTS221_CTRL_REG1;
- uint8_t ctrl_reg2_addr = HTS221_CTRL_REG2;
- uint8_t ctrl_reg3_addr = HTS221_CTRL_REG3;
- uint8_t regval = 0;
-
- ret = hts221_read_reg(priv, &av_addr, ®val);
- if (ret < 0)
- {
- return ERROR;
- }
-
- hts221_dbg("AV_CONF_REG: 0x%02X\n", regval);
-
- ret = hts221_read_reg(priv, &ctrl_reg1_addr, ®val);
- if (ret < 0)
- {
- return ERROR;
- }
-
- hts221_dbg("CTRL_REG_1: 0x%02X\n", regval);
-
- ret = hts221_read_reg(priv, &ctrl_reg2_addr, ®val);
- if (ret < 0)
- {
- return ERROR;
- }
-
- hts221_dbg("CTRL_REG_2: 0x%02X\n", regval);
-
- ret = hts221_read_reg(priv, &ctrl_reg3_addr, ®val);
- if (ret < 0)
- {
- return ERROR;
- }
-
- hts221_dbg("CTRL_REG_3: 0x%02X\n", regval);
- return ret;
-}
-#endif
-
-static int hts221_open(FAR struct file *filep)
-{
- FAR struct inode *inode = filep->f_inode;
- FAR struct hts221_dev_s *priv = inode->i_private;
- int ret;
-
- /* Get exclusive access */
-
- ret = nxmutex_lock(&priv->devlock);
- if (ret < 0)
- {
- return ret;
- }
-
- priv->config->set_power(priv->config, true);
- priv->config->irq_enable(priv->config, true);
-
- nxmutex_unlock(&priv->devlock);
- hts221_dbg("Sensor is powered on\n");
- return OK;
-}
-
-static int hts221_close(FAR struct file *filep)
-{
- FAR struct inode *inode = filep->f_inode;
- FAR struct hts221_dev_s *priv = inode->i_private;
- int ret;
-
- /* Get exclusive access */
-
- ret = nxmutex_lock(&priv->devlock);
- if (ret < 0)
- {
- return ret;
- }
-
- priv->config->irq_enable(priv->config, false);
- ret = hts221_power_on_off(priv, false);
- priv->config->set_power(priv->config, false);
-
- nxmutex_unlock(&priv->devlock);
- hts221_dbg("CLOSED\n");
- return ret;
-}
-
-static ssize_t hts221_read(FAR struct file *filep, FAR char *buffer,
- size_t buflen)
-{
- FAR struct inode *inode = filep->f_inode;
- FAR struct hts221_dev_s *priv = inode->i_private;
- hts221_conv_data_t data;
- ssize_t length = 0;
- int ret;
-
- /* Get exclusive access */
-
- ret = nxmutex_lock(&priv->devlock);
- if (ret < 0)
- {
- return (ssize_t)ret;
- }
-
- ret = hts221_read_convert_data(priv, &data);
- if (ret < 0)
- {
- hts221_dbg("cannot read data: %d\n", ret);
- }
- else
- {
- /* This interface is mainly intended for easy debugging in nsh. */
-
- length = snprintf(buffer, buflen, "%d %u\n",
- data.temperature, data.humidity);
- if (length > buflen)
- {
- length = buflen;
- }
- }
-
- nxmutex_unlock(&priv->devlock);
- return length;
-}
-
-static ssize_t hts221_write(FAR struct file *filep, FAR const char *buffer,
- size_t buflen)
-{
- ssize_t length = 0;
-
- return length;
-}
-
-static int hts221_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
-{
- FAR struct inode *inode = filep->f_inode;
- FAR struct hts221_dev_s *priv = inode->i_private;
- int ret;
-
- /* Get exclusive access */
-
- ret = nxmutex_lock(&priv->devlock);
- if (ret < 0)
- {
- return ret;
- }
-
- switch (cmd)
- {
- case SNIOC_GET_DEV_ID:
- ret = hts221_get_id(priv, (FAR uint8_t *) arg);
- break;
-
- case SNIOC_CFGR:
- ret = hts221_config(priv, (FAR hts221_settings_t *) arg);
- break;
-
- case SNIOC_START_CONVERSION:
- ret = hts221_start_conversion(priv);
- break;
-
- case SNIOC_CHECK_STATUS_REG:
- ret = hts221_check_status(priv, (FAR hts221_status_t *) arg);
- break;
-
- case SNIOC_READ_RAW_DATA:
- ret = hts221_read_raw_data(priv, (FAR hts221_raw_data_t *) arg);
- break;
-
-#ifdef CONFIG_HTS221_DEBUG
- case SNIOC_DUMP_REGS:
- ret = hts221_dump_registers(priv);
- break;
-#endif
-
- case SNIOC_READ_CONVERT_DATA:
- ret = hts221_read_convert_data(priv, (FAR hts221_conv_data_t *) arg);
- break;
-
- default:
- ret = -ENOTTY;
- break;
- }
-
- nxmutex_unlock(&priv->devlock);
- return ret;
-}
-
-static bool hts221_sample(FAR struct hts221_dev_s *priv)
-{
- int ret;
- hts221_status_t status =
- {
- .is_humid_ready = false,
- .is_temp_ready = false
- };
-
- ret = hts221_check_status(priv, &status);
- if (ret < 0)
- {
- return false;
- }
-
- return status.is_humid_ready || status.is_temp_ready;
-}
-
-static int hts221_poll(FAR struct file *filep, FAR struct pollfd_s *fds,
- bool setup)
-{
- FAR struct inode *inode;
- FAR struct hts221_dev_s *priv;
- irqstate_t flags;
- int ret = OK;
- int i;
-
- DEBUGASSERT(fds);
- inode = filep->f_inode;
-
- DEBUGASSERT(inode->i_private);
- priv = inode->i_private;
-
- /* Get exclusive access */
-
- ret = nxmutex_lock(&priv->devlock);
- if (ret < 0)
- {
- return ret;
- }
-
- if (setup)
- {
- /* Ignore waits that do not include POLLIN */
-
- if ((fds->events & POLLIN) == 0)
- {
- ret = -EDEADLK;
- goto out;
- }
-
- /* This is a request to set up the poll. Find an available slot for
- * the poll structure reference.
- */
-
- for (i = 0; i < CONFIG_HTS221_NPOLLWAITERS; i++)
- {
- /* Find an available slot */
-
- if (!priv->fds[i])
- {
- /* Bind the poll structure and this slot */
-
- priv->fds[i] = fds;
- fds->priv = &priv->fds[i];
- break;
- }
- }
-
- if (i >= CONFIG_HTS221_NPOLLWAITERS)
- {
- fds->priv = NULL;
- ret = -EBUSY;
- goto out;
- }
-
- flags = enter_critical_section();
- if (priv->int_pending || hts221_sample(priv))
- {
- poll_notify(&fds, 1, POLLIN);
- }
-
- leave_critical_section(flags);
- }
- else if (fds->priv)
- {
- /* This is a request to tear down the poll. */
-
- FAR struct pollfd_s **slot = (FAR struct pollfd_s **)fds->priv;
-
- DEBUGASSERT(slot != NULL);
-
- /* Remove all memory of the poll setup */
-
- *slot = NULL;
- fds->priv = NULL;
- }
-
-out:
- nxmutex_unlock(&priv->devlock);
- return ret;
-}
-
-static int hts221_int_handler(int irq, FAR void *context, FAR void *arg)
-{
- FAR struct hts221_dev_s *priv = (FAR struct hts221_dev_s *)arg;
-
- DEBUGASSERT(priv != NULL);
-
- priv->int_pending = true;
- hts221_dbg("Hts221 interrupt\n");
- poll_notify(priv->fds, CONFIG_HTS221_NPOLLWAITERS, POLLIN);
-
- return OK;
-}
-
-int hts221_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
- uint8_t addr, FAR hts221_config_t *config)
-{
- int ret = 0;
- FAR struct hts221_dev_s *priv;
-
- priv = kmm_zalloc(sizeof(struct hts221_dev_s));
-
- if (!priv)
- {
- hts221_dbg("Memory cannot be allocated for hts221 sensor");
- return -ENOMEM;
- }
-
- priv->addr = addr;
- priv->i2c = i2c;
- priv->config = config;
- nxmutex_init(&priv->devlock);
-
- priv->config->set_power(priv->config, true);
-
- ret = hts221_load_calibration_data(priv);
- if (ret < 0)
- {
- nxmutex_destroy(&priv->devlock);
- kmm_free(priv);
- hts221_dbg("Cannot calibrate hts221 sensor\n");
- return ret;
- }
-
- ret = register_driver(devpath, &g_humidityops, 0600, priv);
-
- hts221_dbg("Registered with %d\n", ret);
-
- if (ret < 0)
- {
- nxmutex_destroy(&priv->devlock);
- kmm_free(priv);
- hts221_dbg("Error occurred during the driver registering\n");
- return ret;
- }
-
- if (priv->config->irq_clear)
- {
- priv->config->irq_clear(priv->config);
- }
-
- priv->config->irq_attach(priv->config, hts221_int_handler, priv);
- priv->config->irq_enable(priv->config, false);
- priv->config->set_power(priv->config, false);
- return OK;
-}
diff --git a/drivers/sensors/hts221_uorb.c b/drivers/sensors/hts221_uorb.c
new file mode 100644
index 00000000000..8ea5dfd7adf
--- /dev/null
+++ b/drivers/sensors/hts221_uorb.c
@@ -0,0 +1,1216 @@
+/****************************************************************************
+ * drivers/sensors/hts221_uorb.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <debug.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <nuttx/nuttx.h>
+#include <nuttx/arch.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/mutex.h>
+#include <nuttx/random.h>
+#include <nuttx/signal.h>
+#include <nuttx/wqueue.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/sensors/sensor.h>
+#include <nuttx/sensors/hts221.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register map */
+
+#define HTS221_WHO_AM_I 0x0f
+#define HTS221_AV_CONF 0x10
+#define HTS221_CTRL_REG1 0x20
+#define HTS221_CTRL_REG2 0x21
+#define HTS221_CTRL_REG3 0x22
+#define HTS221_STATUS_REG 0x27
+#define HTS221_HUM_OUT_L 0x28
+#define HTS221_HUM_OUT_H 0x29
+#define HTS221_TEMP_OUT_L 0x2a
+#define HTS221_TEMP_OUT_H 0x2b
+
+/* Calibration registers */
+
+#define HTS221_CALIB_H0_RH_X2 0x30
+#define HTS221_CALIB_H1_RH_X2 0x31
+#define HTS221_CALIB_T0_DEGC_X8 0x32
+#define HTS221_CALIB_T1_DEGC_X8 0x33
+#define HTS221_CALIB_T1_T0_MSB 0x35
+#define HTS221_CALIB_H0T0_OUT_L 0x36
+#define HTS221_CALIB_H0T0_OUT_H 0x37
+#define HTS221_CALIB_H1T0_OUT_L 0x3a
+#define HTS221_CALIB_H1T0_OUT_H 0x3b
+#define HTS221_CALIB_T0_OUT_L 0x3c
+#define HTS221_CALIB_T0_OUT_H 0x3d
+#define HTS221_CALIB_T1_OUT_L 0x3e
+#define HTS221_CALIB_T1_OUT_H 0x3f
+
+/* HTS221_AV_CONF: AVGH in bits 0-2, AVGT in bits 3-5 */
+
+#define HTS221_AV_CONF_AVGH_SHIFT 0
+#define HTS221_AV_CONF_AVGT_SHIFT 3
+#define HTS221_AV_CONF_MASK 0x3f
+#define HTS221_AVGT_DEFAULT 3 /* 16 samples */
+#define HTS221_AVGH_DEFAULT 3 /* 32 samples */
+#define HTS221_AVG_CODES 8
+
+/* HTS221_CTRL_REG1 */
+
+#define HTS221_CTRL_REG1_PD (1 << 7)
+#define HTS221_CTRL_REG1_BDU (1 << 2)
+#define HTS221_CTRL_REG1_ODR_MASK 0x03
+#define HTS221_ODR_ONESHOT 0
+#define HTS221_ODR_1HZ 1
+#define HTS221_ODR_7HZ 2
+#define HTS221_ODR_12_5HZ 3
+
+/* HTS221_CTRL_REG2 */
+
+#define HTS221_CTRL_REG2_BOOT (1 << 7)
+#define HTS221_CTRL_REG2_ONE_SHOT (1 << 0)
+
+/* HTS221_CTRL_REG3 */
+
+#define HTS221_CTRL_REG3_DRDY_L_H (1 << 7)
+#define HTS221_CTRL_REG3_PP_OD (1 << 6)
+#define HTS221_CTRL_REG3_DRDY_EN (1 << 2)
+
+/* HTS221_STATUS_REG */
+
+#define HTS221_STATUS_REG_H_DA (1 << 1)
+#define HTS221_STATUS_REG_T_DA (1 << 0)
+#define HTS221_STATUS_REG_DA (HTS221_STATUS_REG_H_DA | \
+ HTS221_STATUS_REG_T_DA)
+
+#define HTS221_DEVID 0xbc
+
+#define HTS221_BOOT_RETRIES 5
+#define HTS221_ONE_SHOT_RETRIES 10
+
+/* Output data rate periods in us */
+
+#define HTS221_PERIOD_12_5HZ 80000
+#define HTS221_PERIOD_7HZ 142857
+#define HTS221_PERIOD_1HZ 1000000
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Each measurement channel needs its own lower-half. */
+
+struct hts221_sensor_s
+{
+ FAR struct sensor_lowerhalf_s lower; /* Lower-half driver */
+ FAR struct hts221_dev_s *dev; /* Parent device */
+ bool enabled; /* Channel activated */
+};
+
+struct hts221_dev_s
+{
+ struct hts221_sensor_s temp; /* Temperature lower-half */
+ struct hts221_sensor_s hum; /* Humidity lower-half */
+ FAR struct i2c_master_s *i2c; /* I2C interface */
+ FAR hts221_config_t *config; /* Board callbacks, may be NULL */
+ uint8_t addr; /* I2C address */
+ uint8_t avgt; /* Temperature averaging code */
+ uint8_t avgh; /* Humidity averaging code */
+ uint8_t odr; /* Output data rate code */
+ uint32_t interval; /* Requested interval in us */
+ struct work_s work; /* Measurement work */
+ mutex_t lock; /* Serialize device access */
+ bool running; /* Sampling in progress */
+ struct
+ {
+ int16_t t0_out;
+ int16_t t1_out;
+ int16_t h0_t0_out;
+ int16_t h1_t0_out;
+ unsigned int t0_x8:10;
+ unsigned int t1_x8:10;
+ uint8_t h0_x2;
+ uint8_t h1_x2;
+ } calib;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int hts221_read_reg(FAR struct hts221_dev_s *priv, uint8_t regaddr,
+ FAR uint8_t *regval);
+static int hts221_write_reg(FAR struct hts221_dev_s *priv, uint8_t regaddr,
+ uint8_t regval);
+static int hts221_modify_reg(FAR struct hts221_dev_s *priv,
+ uint8_t regaddr, uint8_t mask, uint8_t value);
+static int hts221_load_calibration(FAR struct hts221_dev_s *priv);
+static int hts221_boot(FAR struct hts221_dev_s *priv);
+static bool hts221_use_irq(FAR struct hts221_dev_s *priv);
+static int hts221_apply_settings(FAR struct hts221_dev_s *priv);
+static int hts221_board_power(FAR struct hts221_dev_s *priv, bool on);
+static int hts221_power(FAR struct hts221_dev_s *priv, bool on);
+static int hts221_wait_data(FAR struct hts221_dev_s *priv, int retries);
+static int hts221_read_raw(FAR struct hts221_dev_s *priv,
+ FAR int16_t *t_out, FAR int16_t *h_out);
+static sensor_data_t hts221_interpolate(int y0, int y1, int x0, int x1,
+ int x, int div);
+static void hts221_push(FAR struct hts221_dev_s *priv, int16_t t_out,
+ int16_t h_out, bool temp_en, bool hum_en);
+static void hts221_worker(FAR void *arg);
+static int hts221_int_handler(int irq, FAR void *context, FAR void *arg);
+static int hts221_start(FAR struct hts221_dev_s *priv);
+static void hts221_stop(FAR struct hts221_dev_s *priv);
+static int hts221_set_oversampling(FAR struct hts221_sensor_s *sensor,
+ unsigned long samples);
+
+/* Sensor lower-half operations */
+
+static int hts221_activate(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep, bool enable);
+static int hts221_set_interval(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep,
+ FAR uint32_t *period_us);
+static int hts221_selftest(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep, unsigned long arg);
+static int hts221_get_info(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep,
+ FAR struct sensor_device_info_s *info);
+static int hts221_control(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep, int cmd,
+ unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct sensor_ops_s g_hts221_ops =
+{
+ .activate = hts221_activate,
+ .set_interval = hts221_set_interval,
+ .selftest = hts221_selftest,
+ .get_info = hts221_get_info,
+ .control = hts221_control,
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: hts221_read_reg
+ ****************************************************************************/
+
+static int hts221_read_reg(FAR struct hts221_dev_s *priv, uint8_t regaddr,
+ FAR uint8_t *regval)
+{
+ struct i2c_config_s config;
+
+ config.frequency = CONFIG_HTS221_I2C_FREQUENCY;
+ config.address = priv->addr;
+ config.addrlen = 7;
+
+ return i2c_writeread(priv->i2c, &config, ®addr, 1, regval, 1);
+}
+
+/****************************************************************************
+ * Name: hts221_write_reg
+ ****************************************************************************/
+
+static int hts221_write_reg(FAR struct hts221_dev_s *priv, uint8_t regaddr,
+ uint8_t regval)
+{
+ struct i2c_config_s config;
+ uint8_t buf[2];
+
+ config.frequency = CONFIG_HTS221_I2C_FREQUENCY;
+ config.address = priv->addr;
+ config.addrlen = 7;
+
+ buf[0] = regaddr;
+ buf[1] = regval;
+
+ return i2c_write(priv->i2c, &config, buf, 2);
+}
+
+/****************************************************************************
+ * Name: hts221_modify_reg
+ ****************************************************************************/
+
+static int hts221_modify_reg(FAR struct hts221_dev_s *priv,
+ uint8_t regaddr, uint8_t mask, uint8_t value)
+{
+ uint8_t regval;
+ int ret;
+
+ ret = hts221_read_reg(priv, regaddr, ®val);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ regval &= ~mask;
+ regval |= value & mask;
+
+ return hts221_write_reg(priv, regaddr, regval);
+}
+
+/****************************************************************************
+ * Name: hts221_load_calibration
+ *
+ * Description:
+ * Read the factory calibration coefficients used to convert raw readings
+ * into physical units.
+ *
+ ****************************************************************************/
+
+static int hts221_load_calibration(FAR struct hts221_dev_s *priv)
+{
+ uint8_t t0_degc_x8 = 0;
+ uint8_t t1_degc_x8 = 0;
+ uint8_t t1_t0_msb = 0;
+ uint8_t t0_out_lsb = 0;
+ uint8_t t0_out_msb = 0;
+ uint8_t t1_out_lsb = 0;
+ uint8_t t1_out_msb = 0;
+ uint8_t h0_rh_x2 = 0;
+ uint8_t h1_rh_x2 = 0;
+ uint8_t h0t0_out_lsb = 0;
+ uint8_t h0t0_out_msb = 0;
+ uint8_t h1t0_out_lsb = 0;
+ uint8_t h1t0_out_msb = 0;
+ int ret;
+
+ ret = hts221_read_reg(priv, HTS221_CALIB_T0_DEGC_X8, &t0_degc_x8);
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_CALIB_T1_DEGC_X8, &t1_degc_x8);
+ }
+
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_CALIB_T1_T0_MSB, &t1_t0_msb);
+ }
+
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_CALIB_T0_OUT_L, &t0_out_lsb);
+ }
+
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_CALIB_T0_OUT_H, &t0_out_msb);
+ }
+
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_CALIB_T1_OUT_L, &t1_out_lsb);
+ }
+
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_CALIB_T1_OUT_H, &t1_out_msb);
+ }
+
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_CALIB_H0_RH_X2, &h0_rh_x2);
+ }
+
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_CALIB_H1_RH_X2, &h1_rh_x2);
+ }
+
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_CALIB_H0T0_OUT_L, &h0t0_out_lsb);
+ }
+
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_CALIB_H0T0_OUT_H, &h0t0_out_msb);
+ }
+
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_CALIB_H1T0_OUT_L, &h1t0_out_lsb);
+ }
+
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_CALIB_H1T0_OUT_H, &h1t0_out_msb);
+ }
+
+ if (ret < 0)
+ {
+ snerr("ERROR: Failed to read HTS221 calibration data: %d\n", ret);
+ return ret;
+ }
+
+ priv->calib.t0_x8 = t0_degc_x8 | ((t1_t0_msb & 0x3) << 8);
+ priv->calib.t1_x8 = t1_degc_x8 | ((t1_t0_msb & (0x3 << 2)) << (8 - 2));
+ priv->calib.t0_out = t0_out_lsb | (t0_out_msb << 8);
+ priv->calib.t1_out = t1_out_lsb | (t1_out_msb << 8);
+ priv->calib.h0_x2 = h0_rh_x2;
+ priv->calib.h1_x2 = h1_rh_x2;
+ priv->calib.h0_t0_out = h0t0_out_lsb | (h0t0_out_msb << 8);
+ priv->calib.h1_t0_out = h1t0_out_lsb | (h1t0_out_msb << 8);
+
+ /* As calibration coefficients are unique to each sensor device,
+ * they are a good candidate to be added to the entropy pool.
+ */
+
+ up_rngaddentropy(RND_SRC_HW, (FAR uint32_t *)&priv->calib,
+ sizeof(priv->calib) / sizeof(uint32_t));
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: hts221_boot
+ *
+ * Description:
+ * Reboot the sensor to reload the trimming parameters. Resets the
+ * control registers, so it is done before they are programmed.
+ *
+ ****************************************************************************/
+
+static int hts221_boot(FAR struct hts221_dev_s *priv)
+{
+ uint8_t regval;
+ int retries = HTS221_BOOT_RETRIES;
+ int ret;
+
+ ret = hts221_write_reg(priv, HTS221_CTRL_REG2, HTS221_CTRL_REG2_BOOT);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ do
+ {
+ nxsig_usleep(10000);
+ ret = hts221_read_reg(priv, HTS221_CTRL_REG2, ®val);
+ if (ret < 0)
+ {
+ return ret;
+ }
+ }
+ while ((regval & HTS221_CTRL_REG2_BOOT) && --retries);
+
+ if (regval & HTS221_CTRL_REG2_BOOT)
+ {
+ return -ETIMEDOUT;
+ }
+
+ /* After boot bit is cleared, wait additional 5 msec as recommended in
+ * HTS221 application note.
+ */
+
+ up_mdelay(5);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: hts221_use_irq
+ *
+ * Description:
+ * True when the data-ready interrupt drives the sampling: the board
+ * provides the interrupt and the requested rate maps to a continuous
+ * output data rate.
+ *
+ ****************************************************************************/
+
+static bool hts221_use_irq(FAR struct hts221_dev_s *priv)
+{
+ return priv->config != NULL && priv->config->irq_attach != NULL &&
+ priv->odr != HTS221_ODR_ONESHOT;
+}
+
+/****************************************************************************
+ * Name: hts221_apply_settings
+ *
+ * Description:
+ * Program averaging, data-ready pin and output data rate. The PD bit is
+ * left untouched.
+ *
+ ****************************************************************************/
+
+static int hts221_apply_settings(FAR struct hts221_dev_s *priv)
+{
+ uint8_t regval;
+ int ret;
+
+ regval = (priv->avgh << HTS221_AV_CONF_AVGH_SHIFT) |
+ (priv->avgt << HTS221_AV_CONF_AVGT_SHIFT);
+ ret = hts221_modify_reg(priv, HTS221_AV_CONF, HTS221_AV_CONF_MASK,
+ regval);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ regval = 0;
+ if (hts221_use_irq(priv))
+ {
+ regval |= HTS221_CTRL_REG3_DRDY_EN;
+ regval |= priv->config->drdy_active_low ?
+ HTS221_CTRL_REG3_DRDY_L_H : 0;
+ regval |= priv->config->drdy_open_drain ?
+ HTS221_CTRL_REG3_PP_OD : 0;
+ }
+
+ ret = hts221_write_reg(priv, HTS221_CTRL_REG3, regval);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ return hts221_modify_reg(priv, HTS221_CTRL_REG1,
+ HTS221_CTRL_REG1_ODR_MASK | HTS221_CTRL_REG1_BDU,
+ priv->odr | HTS221_CTRL_REG1_BDU);
+}
+
+/****************************************************************************
+ * Name: hts221_board_power
+ *
+ * Description:
+ * Switch the sensor supply through the board callback, if any.
+ *
+ ****************************************************************************/
+
+static int hts221_board_power(FAR struct hts221_dev_s *priv, bool on)
+{
+ if (priv->config != NULL && priv->config->set_power != NULL)
+ {
+ return priv->config->set_power(priv->config, on);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: hts221_power
+ *
+ * Description:
+ * Set or clear the PD bit.
+ *
+ ****************************************************************************/
+
+static int hts221_power(FAR struct hts221_dev_s *priv, bool on)
+{
+ return hts221_modify_reg(priv, HTS221_CTRL_REG1, HTS221_CTRL_REG1_PD,
+ on ? HTS221_CTRL_REG1_PD : 0);
+}
+
+/****************************************************************************
+ * Name: hts221_wait_data
+ *
+ * Description:
+ * Wait until both temperature and humidity samples are available.
+ *
+ ****************************************************************************/
+
+static int hts221_wait_data(FAR struct hts221_dev_s *priv, int retries)
+{
+ uint8_t regval;
+ int ret;
+
+ for (; ; )
+ {
+ ret = hts221_read_reg(priv, HTS221_STATUS_REG, ®val);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ if ((regval & HTS221_STATUS_REG_DA) == HTS221_STATUS_REG_DA)
+ {
+ return OK;
+ }
+
+ if (--retries <= 0)
+ {
+ return -EAGAIN;
+ }
+
+ nxsig_usleep(5000);
+ }
+}
+
+/****************************************************************************
+ * Name: hts221_read_raw
+ *
+ * Description:
+ * Read the raw temperature and humidity output registers.
+ *
+ ****************************************************************************/
+
+static int hts221_read_raw(FAR struct hts221_dev_s *priv,
+ FAR int16_t *t_out, FAR int16_t *h_out)
+{
+ uint8_t h_l;
+ uint8_t h_h;
+ uint8_t t_l;
+ uint8_t t_h;
+ int ret;
+
+ ret = hts221_read_reg(priv, HTS221_HUM_OUT_L, &h_l);
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_HUM_OUT_H, &h_h);
+ }
+
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_TEMP_OUT_L, &t_l);
+ }
+
+ if (ret >= 0)
+ {
+ ret = hts221_read_reg(priv, HTS221_TEMP_OUT_H, &t_h);
+ }
+
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ *t_out = t_h << 8 | t_l;
+ *h_out = h_h << 8 | h_l;
+
+ add_sensor_randomness(*h_out ^ *t_out);
+ return OK;
+}
+
+/****************************************************************************
+ * Name: hts221_interpolate
+ *
+ * Description:
+ * Linear interpolation between the two factory calibration points
+ * (x0, y0) and (x1, y1) at x, with the result divided by div.
+ *
+ ****************************************************************************/
+
+static sensor_data_t hts221_interpolate(int y0, int y1, int x0, int x1,
+ int x, int div)
+{
+ sensor_data_t slope;
+ int span = x1 - x0;
+ int delta = x - x0;
+ int rise = y1 - y0;
+
+ /* Keep the operands within the b16 range */
+
+ while (span > 16383 || span < -16383)
+ {
+ span /= 2;
+ delta /= 2;
+ }
+
+ slope = sensor_data_div(sensor_data_itof(rise), sensor_data_itof(span));
+
+ return sensor_data_divi(sensor_data_add(sensor_data_itof(y0),
+ sensor_data_muli(slope, delta)),
+ div);
+}
+
+/****************************************************************************
+ * Name: hts221_push
+ *
+ * Description:
+ * Convert a raw sample with the factory calibration and push it to the
+ * enabled topics. Called without the lock held, since the upper half
+ * takes its own lock in push_event.
+ *
+ ****************************************************************************/
+
+static void hts221_push(FAR struct hts221_dev_s *priv, int16_t t_out,
+ int16_t h_out, bool temp_en, bool hum_en)
+{
+ struct sensor_temp temp;
+ struct sensor_humi humi;
+
+ temp.timestamp = sensor_get_timestamp();
+ temp.temperature = hts221_interpolate(priv->calib.t0_x8,
+ priv->calib.t1_x8,
+ priv->calib.t0_out,
+ priv->calib.t1_out, t_out, 8);
+ humi.timestamp = temp.timestamp;
+ humi.humidity = hts221_interpolate(priv->calib.h0_x2,
+ priv->calib.h1_x2,
+ priv->calib.h0_t0_out,
+ priv->calib.h1_t0_out, h_out, 2);
+
+ if (temp_en)
+ {
+ priv->temp.lower.push_event(priv->temp.lower.priv, &temp,
+ sizeof(temp));
+ }
+
+ if (hum_en)
+ {
+ priv->hum.lower.push_event(priv->hum.lower.priv, &humi,
+ sizeof(humi));
+ }
+}
+
+/****************************************************************************
+ * Name: hts221_worker
+ *
+ * Description:
+ * In one-shot mode trigger a conversion, wait for it and re-queue every
+ * interval. With the data-ready interrupt the handler queues the worker
+ * and the sample is ready.
+ *
+ ****************************************************************************/
+
+static void hts221_worker(FAR void *arg)
+{
+ FAR struct hts221_dev_s *priv = (FAR struct hts221_dev_s *)arg;
+ bool temp_en;
+ bool hum_en;
+ int16_t t_out = 0;
+ int16_t h_out = 0;
+ int ret;
+
+ nxmutex_lock(&priv->lock);
+
+ if (!priv->running)
+ {
+ nxmutex_unlock(&priv->lock);
+ return;
+ }
+
+ if (!hts221_use_irq(priv))
+ {
+ /* Reading the output registers clears stale data-ready flags left by
+ * a boot or a previous run, so that the wait below sees only the
+ * conversion triggered here.
+ */
+
+ ret = hts221_read_raw(priv, &t_out, &h_out);
+ if (ret >= 0)
+ {
+ ret = hts221_write_reg(priv, HTS221_CTRL_REG2,
+ HTS221_CTRL_REG2_ONE_SHOT);
+ }
+
+ if (ret >= 0)
+ {
+ ret = hts221_wait_data(priv, HTS221_ONE_SHOT_RETRIES);
+ }
+
+ work_queue(LPWORK, &priv->work, hts221_worker, priv,
+ USEC2TICK(priv->interval));
+ }
+ else
+ {
+ ret = hts221_wait_data(priv, 1);
+ }
+
+ if (ret == OK)
+ {
+ ret = hts221_read_raw(priv, &t_out, &h_out);
+ }
+
+ temp_en = priv->temp.enabled;
+ hum_en = priv->hum.enabled;
+
+ nxmutex_unlock(&priv->lock);
+
+ if (ret == OK)
+ {
+ hts221_push(priv, t_out, h_out, temp_en, hum_en);
+ }
+ else if (ret != -EAGAIN)
+ {
+ snerr("ERROR: HTS221 measurement failed: %d\n", ret);
+ }
+}
+
+/****************************************************************************
+ * Name: hts221_int_handler
+ ****************************************************************************/
+
+static int hts221_int_handler(int irq, FAR void *context, FAR void *arg)
+{
+ FAR struct hts221_dev_s *priv = (FAR struct hts221_dev_s *)arg;
+
+ DEBUGASSERT(priv != NULL);
+
+ if (priv->config->irq_clear != NULL)
+ {
+ priv->config->irq_clear(priv->config);
+ }
+
+ return work_queue(LPWORK, &priv->work, hts221_worker, priv, 0);
+}
+
+/****************************************************************************
+ * Name: hts221_start
+ *
+ * Description:
+ * Power on, program the settings and start sampling. Called with the
+ * lock held.
+ *
+ ****************************************************************************/
+
+static int hts221_start(FAR struct hts221_dev_s *priv)
+{
+ int ret;
+
+ ret = hts221_board_power(priv, true);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ ret = hts221_apply_settings(priv);
+ if (ret >= 0)
+ {
+ ret = hts221_power(priv, true);
+ }
+
+ if (ret < 0)
+ {
+ hts221_board_power(priv, false);
+ return ret;
+ }
+
+ priv->running = true;
+
+ if (hts221_use_irq(priv))
+ {
+ if (priv->config->irq_clear != NULL)
+ {
+ priv->config->irq_clear(priv->config);
+ }
+
+ if (priv->config->irq_enable != NULL)
+ {
+ priv->config->irq_enable(priv->config, true);
+ }
+ }
+
+ /* Take the first sample now; it also drains a sample that may already
+ * be waiting so that the DRDY line goes low.
+ */
+
+ return work_queue(LPWORK, &priv->work, hts221_worker, priv, 0);
+}
+
+/****************************************************************************
+ * Name: hts221_stop
+ *
+ * Description:
+ * Stop sampling and power off. Called with the lock held.
+ *
+ ****************************************************************************/
+
+static void hts221_stop(FAR struct hts221_dev_s *priv)
+{
+ priv->running = false;
+ work_cancel(LPWORK, &priv->work);
+
+ if (priv->config != NULL && priv->config->irq_enable != NULL)
+ {
+ priv->config->irq_enable(priv->config, false);
+ }
+
+ hts221_write_reg(priv, HTS221_CTRL_REG2, 0);
+ hts221_power(priv, false);
+ hts221_board_power(priv, false);
+}
+
+/****************************************************************************
+ * Name: hts221_set_oversampling
+ *
+ * Description:
+ * Set the number of internal samples averaged for one output: 2 to 256
+ * for temperature, 4 to 512 for humidity, powers of two. Called with
+ * the lock held.
+ *
+ ****************************************************************************/
+
+static int hts221_set_oversampling(FAR struct hts221_sensor_s *sensor,
+ unsigned long samples)
+{
+ FAR struct hts221_dev_s *priv = sensor->dev;
+ unsigned long base;
+ uint8_t code;
+
+ base = sensor->lower.type == SENSOR_TYPE_AMBIENT_TEMPERATURE ? 2 : 4;
+
+ for (code = 0; code < HTS221_AVG_CODES; code++)
+ {
+ if (samples == (base << code))
+ {
+ break;
+ }
+ }
+
+ if (code == HTS221_AVG_CODES)
+ {
+ return -EINVAL;
+ }
+
+ if (sensor->lower.type == SENSOR_TYPE_AMBIENT_TEMPERATURE)
+ {
+ priv->avgt = code;
+ }
+ else
+ {
+ priv->avgh = code;
+ }
+
+ return hts221_modify_reg(priv, HTS221_AV_CONF, HTS221_AV_CONF_MASK,
+ (priv->avgh << HTS221_AV_CONF_AVGH_SHIFT) |
+ (priv->avgt << HTS221_AV_CONF_AVGT_SHIFT));
+}
+
+/****************************************************************************
+ * Name: hts221_activate
+ ****************************************************************************/
+
+static int hts221_activate(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep, bool enable)
+{
+ FAR struct hts221_sensor_s *sensor =
+ container_of(lower, FAR struct hts221_sensor_s, lower);
+ FAR struct hts221_dev_s *priv = sensor->dev;
+ int ret = OK;
+
+ nxmutex_lock(&priv->lock);
+
+ sensor->enabled = enable;
+
+ if (enable && !priv->running)
+ {
+ ret = hts221_start(priv);
+ }
+ else if (!enable && priv->running &&
+ !priv->temp.enabled && !priv->hum.enabled)
+ {
+ hts221_stop(priv);
+ }
+
+ nxmutex_unlock(&priv->lock);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: hts221_set_interval
+ *
+ * Description:
+ * Without the data-ready interrupt the part is polled in one-shot mode
+ * every interval. With it the interval selects the continuous output
+ * data rate: 12.5 Hz, 7 Hz or 1 Hz.
+ *
+ ****************************************************************************/
+
+static int hts221_set_interval(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep,
+ FAR uint32_t *period_us)
+{
+ FAR struct hts221_sensor_s *sensor =
+ container_of(lower, FAR struct hts221_sensor_s, lower);
+ FAR struct hts221_dev_s *priv = sensor->dev;
+ uint8_t odr = HTS221_ODR_ONESHOT;
+ int ret = OK;
+
+ if (priv->config != NULL && priv->config->irq_attach != NULL)
+ {
+ if (*period_us <= HTS221_PERIOD_12_5HZ)
+ {
+ odr = HTS221_ODR_12_5HZ;
+ *period_us = HTS221_PERIOD_12_5HZ;
+ }
+ else if (*period_us <= HTS221_PERIOD_7HZ)
+ {
+ odr = HTS221_ODR_7HZ;
+ *period_us = HTS221_PERIOD_7HZ;
+ }
+ else
+ {
+ odr = HTS221_ODR_1HZ;
+ }
+ }
+
+ nxmutex_lock(&priv->lock);
+
+ priv->interval = *period_us;
+
+ if (odr != priv->odr)
+ {
+ priv->odr = odr;
+ if (priv->running)
+ {
+ hts221_stop(priv);
+ ret = hts221_start(priv);
+ }
+ }
+
+ nxmutex_unlock(&priv->lock);
+ return ret;
+}
+
+/****************************************************************************
+ * Name: hts221_selftest
+ *
+ * Description:
+ * Check that the part answers with its device ID.
+ *
+ ****************************************************************************/
+
+static int hts221_selftest(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep, unsigned long arg)
+{
+ FAR struct hts221_sensor_s *sensor =
+ container_of(lower, FAR struct hts221_sensor_s, lower);
+ FAR struct hts221_dev_s *priv = sensor->dev;
+ uint8_t id = 0;
+ int ret;
+
+ nxmutex_lock(&priv->lock);
+ ret = hts221_read_reg(priv, HTS221_WHO_AM_I, &id);
+ nxmutex_unlock(&priv->lock);
+
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ return id == HTS221_DEVID ? OK : -ENODEV;
+}
+
+/****************************************************************************
+ * Name: hts221_get_info
+ ****************************************************************************/
+
+static int hts221_get_info(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep,
+ FAR struct sensor_device_info_s *info)
+{
+ memset(info, 0, sizeof(*info));
+
+ info->version = 0;
+ info->power = sensor_data_ftof(0.002f); /* 2 uA at 1 Hz */
+ info->min_delay = HTS221_PERIOD_12_5HZ;
+ info->max_delay = HTS221_PERIOD_1HZ;
+ strlcpy(info->name, "HTS221", sizeof(info->name));
+ strlcpy(info->vendor, "STMicroelectronics", sizeof(info->vendor));
+
+ if (lower->type == SENSOR_TYPE_AMBIENT_TEMPERATURE)
+ {
+ info->max_range = sensor_data_itof(120);
+ info->resolution = sensor_data_ftof(0.016f); /* 64 LSB / degC */
+ }
+ else
+ {
+ info->max_range = sensor_data_itof(100);
+ info->resolution = sensor_data_ftof(0.004f); /* 256 LSB / %rH */
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: hts221_control
+ *
+ * Description:
+ * SNIOC_OVERSAMPLING - number of averaged samples for this topic
+ *
+ ****************************************************************************/
+
+static int hts221_control(FAR struct sensor_lowerhalf_s *lower,
+ FAR struct file *filep, int cmd,
+ unsigned long arg)
+{
+ FAR struct hts221_sensor_s *sensor =
+ container_of(lower, FAR struct hts221_sensor_s, lower);
+ FAR struct hts221_dev_s *priv = sensor->dev;
+ int ret;
+
+ nxmutex_lock(&priv->lock);
+
+ switch (cmd)
+ {
+ case SNIOC_OVERSAMPLING:
+ ret = hts221_set_oversampling(sensor, arg);
+ break;
+
+ default:
+ ret = -ENOTTY;
+ break;
+ }
+
+ nxmutex_unlock(&priv->lock);
+ return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: hts221_register_uorb
+ *
+ * Description:
+ * Register the HTS221 humidity and temperature sensor as UORB devices.
+ *
+ * Input Parameters:
+ * devno - The device number, used to build the device path.
+ * i2c - The I2C bus driver instance.
+ * addr - The I2C address of the HTS221.
+ * config - Board callbacks for the data-ready interrupt and power, or
+ * NULL.
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int hts221_register_uorb(int devno, FAR struct i2c_master_s *i2c,
+ uint8_t addr, FAR hts221_config_t *config)
+{
+ FAR struct hts221_dev_s *priv;
+ uint8_t id;
+ int ret;
+
+ DEBUGASSERT(i2c != NULL);
+
+ priv = kmm_zalloc(sizeof(struct hts221_dev_s));
+ if (priv == NULL)
+ {
+ snerr("ERROR: Failed to allocate HTS221 instance\n");
+ return -ENOMEM;
+ }
+
+ priv->i2c = i2c;
+ priv->addr = addr;
+ priv->config = config;
+ priv->avgt = HTS221_AVGT_DEFAULT;
+ priv->avgh = HTS221_AVGH_DEFAULT;
+ priv->odr = HTS221_ODR_ONESHOT;
+ priv->interval = HTS221_PERIOD_1HZ;
+ nxmutex_init(&priv->lock);
+
+ ret = hts221_board_power(priv, true);
+ if (ret < 0)
+ {
+ snerr("ERROR: Failed to power on HTS221: %d\n", ret);
+ goto errout;
+ }
+
+ ret = hts221_read_reg(priv, HTS221_WHO_AM_I, &id);
+ if (ret < 0 || id != HTS221_DEVID)
+ {
+ snerr("ERROR: HTS221 not found: ret=%d id=0x%02x\n", ret, id);
+ ret = ret < 0 ? ret : -ENODEV;
+ goto errout_power;
+ }
+
+ ret = hts221_boot(priv);
+ if (ret < 0)
+ {
+ snerr("ERROR: Failed to boot HTS221: %d\n", ret);
+ goto errout_power;
+ }
+
+ ret = hts221_load_calibration(priv);
+ if (ret < 0)
+ {
+ snerr("ERROR: Failed to calibrate HTS221: %d\n", ret);
+ goto errout_power;
+ }
+
+ hts221_board_power(priv, false);
+
+ if (config != NULL && config->irq_attach != NULL)
+ {
+ if (config->irq_clear != NULL)
+ {
+ config->irq_clear(config);
+ }
+
+ ret = config->irq_attach(config, hts221_int_handler, priv);
+ if (ret < 0)
+ {
+ snerr("ERROR: Failed to attach HTS221 interrupt: %d\n", ret);
+ goto errout;
+ }
+
+ if (config->irq_enable != NULL)
+ {
+ config->irq_enable(config, false);
+ }
+ }
+
+ /* Register the temperature lower-half */
+
+ priv->temp.dev = priv;
+ priv->temp.lower.ops = &g_hts221_ops;
+ priv->temp.lower.type = SENSOR_TYPE_AMBIENT_TEMPERATURE;
+ priv->temp.lower.nbuffer = 1;
+
+ ret = sensor_register(&priv->temp.lower, devno);
+ if (ret < 0)
+ {
+ snerr("ERROR: Failed to register HTS221 temperature: %d\n", ret);
+ goto errout;
+ }
+
+ /* Register the humidity lower-half */
+
+ priv->hum.dev = priv;
+ priv->hum.lower.ops = &g_hts221_ops;
+ priv->hum.lower.type = SENSOR_TYPE_RELATIVE_HUMIDITY;
+ priv->hum.lower.nbuffer = 1;
+
+ ret = sensor_register(&priv->hum.lower, devno);
+ if (ret < 0)
+ {
+ snerr("ERROR: Failed to register HTS221 humidity: %d\n", ret);
+ sensor_unregister(&priv->temp.lower, devno);
+ goto errout;
+ }
+
+ sninfo("HTS221 registered\n");
+ return OK;
+
+errout_power:
+ hts221_board_power(priv, false);
+errout:
+ nxmutex_destroy(&priv->lock);
+ kmm_free(priv);
+ return ret;
+}
diff --git a/include/nuttx/sensors/hts221.h b/include/nuttx/sensors/hts221.h
index f06dfa668a4..5dbef91e6b6 100644
--- a/include/nuttx/sensors/hts221.h
+++ b/include/nuttx/sensors/hts221.h
@@ -27,14 +27,10 @@
* Included Files
****************************************************************************/
-#include <nuttx/sensors/ioctl.h>
+#include <stdbool.h>
+#include <stdint.h>
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-#define HTS221_TEMPERATURE_PRECISION 100
-#define HTS221_HUMIDITY_PRECISION 10
+#include <nuttx/irq.h>
/****************************************************************************
* Public Types
@@ -42,108 +38,46 @@
struct i2c_master_s; /* Forward reference */
-/* Number of temperature samples */
-
-typedef enum hts221_avrg_temp_e
-{
- HTS221_AVGT2 = 0,
- HTS221_AVGT4,
- HTS221_AVGT8,
- HTS221_AVGT16, /* Default value */
- HTS221_AVGT32,
- HTS221_AVGT64,
- HTS221_AVGT128,
- HTS221_AVGT256
-} hts221_avrg_temp_t;
-
-/* Number of humidity samples */
-
-typedef enum hts221_avrg_humid_e
-{
- HTS221_AVGH4 = 0,
- HTS221_AVGH8,
- HTS221_AVGH16,
- HTS221_AVGH32, /* Default value */
- HTS221_AVGH64,
- HTS221_AVGH128,
- HTS221_AVGH256,
- HTS221_AVGH512
-}hts221_avrg_humid_t;
-
-/* Output data rate configuration */
-
-typedef enum hts221_odr_e
-{
- HTS221_ODR_ONESHOT = 0,
- HTS221_ODR_1HZ,
- HTS221_ODR_7HZ,
- HTS221_ODR_12_5HZ
-} hts221_odr_t;
-
-/* Configuration structure */
-
-typedef struct hts221_settings_s
-{
- hts221_avrg_temp_t temp_resol; /* Temperature resolution. The more
- * samples sensor takes, the more power
- * it uses */
- hts221_avrg_humid_t humid_resol; /* Humidity resolution. The more
- * samples sensor takes, the more power
- * it uses */
- hts221_odr_t odr; /* Output data rate */
- bool is_bdu; /* If read operation is not faster than
output
- * operation, then this variable must be
set to true */
- bool is_data_rdy; /* Must be set to true, if interrupt
needed.
- * Default is 0, disabled */
- bool is_high_edge; /* High or low interrupt signal from
device.
- * Default is high, 0 */
- bool is_open_drain; /* Open drain or push-pull on data-ready
pin.
- * Default is push-pull, 0 */
- bool is_boot; /* Refresh the content of the internal
registers */
-} hts221_settings_t;
-
-/* Interrupt configuration data structure */
+/* Board interface: data-ready interrupt and power control. All callbacks
+ * are optional. Without irq_attach the driver polls the sensor.
+ */
typedef struct hts221_config_s
{
int irq;
- CODE int (*irq_attach)(FAR struct hts221_config_s * state, xcpt_t isr,
+ CODE int (*irq_attach)(FAR struct hts221_config_s *state, xcpt_t isr,
FAR void *arg);
CODE void (*irq_enable)(FAR const struct hts221_config_s *state,
bool enable);
CODE void (*irq_clear)(FAR const struct hts221_config_s *state);
CODE int (*set_power)(FAR const struct hts221_config_s *state, bool on);
+ bool drdy_active_low; /* Data-ready pin polarity */
+ bool drdy_open_drain; /* Data-ready pin open drain, else push-pull */
} hts221_config_t;
-/* Raw data structure */
-
-typedef struct hts221_raw_data_s
-{
- uint8_t humid_low_bits;
- uint8_t humid_high_bits;
- uint8_t temp_low_bits;
- uint8_t temp_high_bits;
-} hts221_raw_data_t;
-
-typedef struct hts221_conv_data_s
-{
- int temperature;
- unsigned int humidity;
-} hts221_conv_data_t;
-
-/* Status register data */
-
-typedef struct hts221_status_s
-{
- bool is_humid_ready;
- bool is_temp_ready;
-} hts221_status_t;
-
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
-int hts221_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
- uint8_t addr, hts221_config_t * config);
+/****************************************************************************
+ * Name: hts221_register_uorb
+ *
+ * Description:
+ * Register the HTS221 as UORB devices: sensor_ambient_temp<devno> and
+ * sensor_humi<devno>.
+ *
+ * Input Parameters:
+ * devno - The device number, used to build the device path.
+ * i2c - The I2C bus driver instance.
+ * addr - The I2C address of the HTS221.
+ * config - Board interface, or NULL.
+ *
+ * Returned Value:
+ * Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int hts221_register_uorb(int devno, FAR struct i2c_master_s *i2c,
+ uint8_t addr, FAR hts221_config_t *config);
#endif /* __INCLUDE_NUTTX_SENSORS_HTS221_H */