You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by pk...@apache.org on 2022/04/11 10:29:40 UTC

[incubator-nuttx] branch master updated (609e949ab0 -> 9cd53d714e)

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

pkarashchenko pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


    from 609e949ab0 sched/note: include-able from C++ files
     new bf332cf888 drivers/sensors: Add new driver for scd41 sensor module
     new 3787a362bf drivers/sensors/scd30: Fix invalid parameter check
     new 9cd53d714e drivers/sensors/sgp30: Fix redundant parameter check

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 drivers/sensors/Kconfig                    |  31 ++
 drivers/sensors/Make.defs                  |   4 +
 drivers/sensors/scd30.c                    |  10 +-
 drivers/sensors/{scd30.c => scd41.c}       | 481 +++++++++++++----------------
 drivers/sensors/sgp30.c                    |   2 +-
 include/nuttx/sensors/{scd30.h => scd41.h} |  27 +-
 6 files changed, 271 insertions(+), 284 deletions(-)
 copy drivers/sensors/{scd30.c => scd41.c} (62%)
 copy include/nuttx/sensors/{scd30.h => scd41.h} (80%)


[incubator-nuttx] 02/03: drivers/sensors/scd30: Fix invalid parameter check

Posted by pk...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 3787a362bff25384216c7920ee2e46973210bd40
Author: SPRESENSE <41...@users.noreply.github.com>
AuthorDate: Mon Apr 11 16:34:56 2022 +0900

    drivers/sensors/scd30: Fix invalid parameter check
    
    Fix invalid parameter check and redundant conditions.
---
 drivers/sensors/scd30.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/sensors/scd30.c b/drivers/sensors/scd30.c
index 352c669f6c..6c273a9643 100644
--- a/drivers/sensors/scd30.c
+++ b/drivers/sensors/scd30.c
@@ -835,7 +835,7 @@ static int scd30_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
 
       case SNIOC_SET_INTERVAL:
         {
-          if (arg < 2 && arg > 1800)
+          if (arg < 2 || arg > 1800)
             {
               ret = -EINVAL;
               break;
@@ -851,7 +851,7 @@ static int scd30_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
 
       case SNIOC_SET_TEMP_OFFSET:
         {
-          if (arg < 0 && arg > UINT16_MAX)
+          if (arg > UINT16_MAX)
             {
               ret = -EINVAL;
               break;
@@ -867,7 +867,7 @@ static int scd30_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
 
       case SNIOC_SET_PRESSURE_COMP:
         {
-          if (arg != 0 && arg < 700 && arg > 1200)
+          if (arg != 0 && (arg < 700 || arg > 1200))
             {
               ret = -EINVAL;
               break;
@@ -891,7 +891,7 @@ static int scd30_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
 
       case SNIOC_SET_ALTITUDE_COMP:
         {
-          if (arg < 0 && arg > UINT16_MAX)
+          if (arg > UINT16_MAX)
             {
               ret = -EINVAL;
               break;
@@ -908,7 +908,7 @@ static int scd30_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
 
       case SNIOC_SET_FRC:
         {
-          if (arg < 0 && arg > UINT16_MAX)
+          if (arg > UINT16_MAX)
             {
               ret = -EINVAL;
               break;


[incubator-nuttx] 01/03: drivers/sensors: Add new driver for scd41 sensor module

Posted by pk...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit bf332cf888349b102f85665900afbaa46d5b56bd
Author: SPRESENSE <41...@users.noreply.github.com>
AuthorDate: Mon Apr 11 16:30:13 2022 +0900

    drivers/sensors: Add new driver for scd41 sensor module
    
    Add Sensirion's SCD41 CO2, temperature and humidity sensor driver.
---
 drivers/sensors/Kconfig       |   31 ++
 drivers/sensors/Make.defs     |    4 +
 drivers/sensors/scd41.c       | 1030 +++++++++++++++++++++++++++++++++++++++++
 include/nuttx/sensors/scd41.h |   75 +++
 4 files changed, 1140 insertions(+)

diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig
index 38b77f8183..07ef718430 100644
--- a/drivers/sensors/Kconfig
+++ b/drivers/sensors/Kconfig
@@ -845,6 +845,37 @@ config SCD30_DEBUG
 
 endif # SENSORS_SCD30
 
+config SENSORS_SCD41
+	bool "Sensirion SCD41 CO2, humidity and temperature sensor"
+	default n
+	---help---
+		Enable driver support for the Sensirion SCD41 CO₂, humidity and
+		temperature sensor.
+
+if SENSORS_SCD41
+
+config SCD41_I2C
+	bool "Sensirion SCD41 I2C mode"
+	default y
+	select I2C
+
+config SCD41_I2C_FREQUENCY
+	int "SCD41 I2C frequency"
+	default 100000
+	range 1 100000
+	depends on SCD41_I2C
+	---help---
+		I2C frequency for SCD41. Note, maximum supported frequency for
+		this sensor is 100kHz.
+
+config SCD41_DEBUG
+	bool "Debug support for the SCD41"
+	default n
+	---help---
+		Enables debug features for the SCD41
+
+endif # SENSORS_SCD41
+
 config SENSORS_SGP30
 	bool "Sensirion SGP30 Gas Platform sensor"
 	default n
diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs
index 96e0d59307..54e87e46a5 100644
--- a/drivers/sensors/Make.defs
+++ b/drivers/sensors/Make.defs
@@ -192,6 +192,10 @@ ifeq ($(CONFIG_SENSORS_SCD30),y)
   CSRCS += scd30.c
 endif
 
+ifeq ($(CONFIG_SENSORS_SCD41),y)
+  CSRCS += scd41.c
+endif
+
 ifeq ($(CONFIG_SENSORS_SGP30),y)
   CSRCS += sgp30.c
 endif
diff --git a/drivers/sensors/scd41.c b/drivers/sensors/scd41.c
new file mode 100644
index 0000000000..1009a765a2
--- /dev/null
+++ b/drivers/sensors/scd41.c
@@ -0,0 +1,1030 @@
+/****************************************************************************
+ * drivers/sensors/scd41.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 <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+#include <time.h>
+#include <debug.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/signal.h>
+#include <nuttx/fs/fs.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/sensors/scd41.h>
+#include <nuttx/random.h>
+
+#if defined(CONFIG_SENSORS_SCD41)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_SCD41_DEBUG
+#  define scd41_dbg(x, ...)    _info(x, ##__VA_ARGS__)
+#else
+#  define scd41_dbg(x, ...)    sninfo(x, ##__VA_ARGS__)
+#endif
+
+#ifndef CONFIG_SCD41_I2C_FREQUENCY
+#  define CONFIG_SCD41_I2C_FREQUENCY 100000
+#endif
+
+#define SCD41_I2C_RETRIES 3
+
+/* SCD41 command words */
+
+#define SCD41_CMD_START_MEASUREMENT     0x21b1
+#define SCD41_CMD_STOP_MEASUREMENT      0x3f86
+#define SCD41_CMD_GET_DATA_READY        0xe4b8
+#define SCD41_CMD_READ_MEASUREMENT      0xec05
+#define SCD41_CMD_SET_ASC               0x2416
+#define SCD41_CMD_GET_ASC               0x2313
+#define SCD41_CMD_SET_FRC               0x362f
+#define SCD41_CMD_SET_TEMP_OFFSET       0x241d
+#define SCD41_CMD_GET_TEMP_OFFSET       0x2318
+#define SCD41_CMD_SET_ALT_COMPENSATION  0x2427
+#define SCD41_CMD_GET_ALT_COMPENSATION  0x2322
+#define SCD41_CMD_SET_PRESSURE_COMP     0xe000
+#define SCD41_CMD_SOFT_RESET            0x3646
+#define SCD41_CMD_LOWPOWER_MODE         0x21ac
+#define SCD41_CMD_PERSIST_SETTINGS      0x3615
+#define SCD41_CMD_GET_SERIAL_NUMBER     0x3682
+#define SCD41_CMD_START_SELFTEST        0x3639
+#define SCD41_CMD_FACTORY_RESET         0x3632
+#define SCD41_CMD_ONESHOT_MEASUREMENT   0x219d
+#define SCD41_CMD_ONESHOT_MEASURE_RHT   0x2196
+
+#define SCD41_DEFAULT_MEASUREMENT_INTERVAL  5 /* seconds */
+#define SCD41_DEFAULT_PRESSURE_COMPENSATION 0
+#define SCD41_DEFAULT_ALTITUDE_COMPENSATION 0
+#define SCD41_DEFAULT_TEMPERATURE_OFFSET    0
+
+/****************************************************************************
+ * Private
+ ****************************************************************************/
+
+struct scd41_dev_s
+{
+#ifdef CONFIG_SCD41_I2C
+  FAR struct i2c_master_s *i2c; /* I2C interface */
+  uint8_t addr;                 /* I2C address */
+#endif
+  bool valid;                   /* If cached readings are valid */
+  bool started;                 /* If continuous measurement is enabled */
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+  bool unlinked;                /* True, driver has been unlinked */
+#endif
+  struct timespec last_update;  /* Last time when sensor was read */
+  float co2;                    /* Cached CO₂ (PPM) */
+  float temperature;            /* Cached temperature (°C) */
+  float humidity;               /* Cached humidity (RH%) */
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+  int16_t crefs;                /* Number of open references */
+#endif
+  sem_t devsem;
+  uint16_t pressure_comp;       /* Pressure compensation in mbar (non-zero
+                                 * value overrides altitude compensation). */
+  uint16_t altitude_comp;       /* Altitude compensation in meters */
+  uint16_t interval;            /* Background measurement interval in
+                                 * seconds (2 to 1800). */
+  uint16_t temperature_offset;  /* Temperature offset in 0.01 Kelvin. */
+};
+
+struct scd41_word_s
+{
+  uint8_t data[2];
+  uint8_t crc;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* IO Helpers */
+
+#ifdef CONFIG_SCD41_I2C
+static int scd41_do_transfer(FAR struct i2c_master_s *i2c,
+                             FAR struct i2c_msg_s *msgv,
+                             size_t nmsg);
+#endif
+static int scd41_write_cmd(FAR struct scd41_dev_s *priv, uint16_t cmd,
+                           FAR struct scd41_word_s *params,
+                           unsigned int num_params);
+static int scd41_read_words(FAR struct scd41_dev_s *priv,
+                            FAR struct scd41_word_s *words,
+                            unsigned int num_words);
+
+/* Data conversion */
+
+static uint8_t scd41_crc_word(uint16_t word);
+static void scd41_set_command_param(FAR struct scd41_word_s *param,
+                                    uint16_t value);
+static int scd41_check_data_crc(FAR const struct scd41_word_s *words,
+                                unsigned int num_words);
+static uint16_t scd41_data_word2uint16(FAR const struct scd41_word_s *word);
+
+/* Driver features */
+
+static int scd41_read_values(FAR struct scd41_dev_s *priv, FAR float *temp,
+                             FAR float *rh, FAR float *co2, bool wait);
+static int scd41_configure(FAR struct scd41_dev_s *priv, bool start);
+
+/* Character driver methods */
+
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+static int     scd41_open(FAR struct file *filep);
+static int     scd41_close(FAR struct file *filep);
+#endif
+static ssize_t scd41_read(FAR struct file *filep, FAR char *buffer,
+                          size_t buflen);
+static ssize_t scd41_write(FAR struct file *filep, FAR const char *buffer,
+                           size_t buflen);
+static int     scd41_ioctl(FAR struct file *filep, int cmd,
+                           unsigned long arg);
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+static int     scd41_unlink(FAR struct inode *inode);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations g_scd41fops =
+{
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+  scd41_open,     /* open */
+  scd41_close,    /* close */
+#else
+  NULL,           /* open */
+  NULL,           /* close */
+#endif
+  scd41_read,     /* read */
+  scd41_write,    /* write */
+  NULL,           /* seek */
+  scd41_ioctl,    /* ioctl */
+  NULL            /* poll */
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+  , scd41_unlink /* unlink */
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: scd41_do_transfer
+ ****************************************************************************/
+
+#ifdef CONFIG_SCD41_I2C
+static int scd41_do_transfer(FAR struct i2c_master_s *i2c,
+                             FAR struct i2c_msg_s *msgv,
+                             size_t nmsg)
+{
+  int ret = -EIO;
+  int retries;
+
+  for (retries = 0; retries < SCD41_I2C_RETRIES; retries++)
+    {
+      ret = I2C_TRANSFER(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 == SCD41_I2C_RETRIES - 1)
+            {
+              break;
+            }
+
+          ret = I2C_RESET(i2c);
+          if (ret < 0)
+            {
+              scd41_dbg("I2C_RESET failed: %d\n", ret);
+              return ret;
+            }
+#endif
+        }
+    }
+
+  scd41_dbg("xfer failed: %d\n", ret);
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: scd41_write_cmd
+ ****************************************************************************/
+
+static int scd41_write_cmd(FAR struct scd41_dev_s *priv, uint16_t cmd,
+                           FAR struct scd41_word_s *params,
+                           unsigned int num_params)
+{
+#ifdef CONFIG_SCD41_I2C
+  struct i2c_msg_s msg[2];
+  uint8_t cmd_buf[2];
+  int ret;
+
+  cmd_buf[0] = cmd >> 8;
+  cmd_buf[1] = cmd >> 0;
+
+  msg[0].frequency = CONFIG_SCD41_I2C_FREQUENCY;
+  msg[0].addr = priv->addr;
+  msg[0].flags = 0;
+  msg[0].buffer = cmd_buf;
+  msg[0].length = 2;
+
+  if (num_params)
+    {
+      msg[1].frequency = CONFIG_SCD41_I2C_FREQUENCY;
+      msg[1].addr = priv->addr;
+      msg[1].flags = I2C_M_NOSTART;
+      msg[1].buffer = (FAR uint8_t *)params;
+      msg[1].length = num_params * sizeof(*params);
+    }
+
+  ret = scd41_do_transfer(priv->i2c, msg, (num_params) ? 2 : 1);
+
+  scd41_dbg("cmd: 0x%04X num_params: %d ret: %d\n",
+            cmd, num_params, ret);
+  return (ret >= 0) ? OK : ret;
+#else
+  /* UART mode not implemented yet. */
+
+  return -ENODEV;
+#endif
+}
+
+/****************************************************************************
+ * Name: scd41_read_words
+ ****************************************************************************/
+
+static int scd41_read_words(FAR struct scd41_dev_s *priv,
+                            FAR struct scd41_word_s *words,
+                            unsigned int num_words)
+{
+#ifdef CONFIG_SCD41_I2C
+  struct i2c_msg_s msg[1];
+  int ret;
+
+  msg[0].frequency = CONFIG_SCD41_I2C_FREQUENCY;
+  msg[0].addr = priv->addr;
+  msg[0].flags = I2C_M_READ;
+  msg[0].buffer = (FAR uint8_t *)words;
+  msg[0].length = num_words * sizeof(*words);
+
+  ret = scd41_do_transfer(priv->i2c, msg, 1);
+
+  scd41_dbg("num_words: %d ret: %d\n", num_words, ret);
+  return (ret >= 0) ? OK : ret;
+#else
+  /* UART mode not implemented yet. */
+
+  return -ENODEV;
+#endif
+}
+
+/****************************************************************************
+ * Name: scd41_crc_word
+ ****************************************************************************/
+
+static uint8_t scd41_crc_word(uint16_t word)
+{
+  static const uint8_t crc_table[16] =
+  {
+    0x00, 0x31, 0x62, 0x53, 0xc4, 0xf5, 0xa6, 0x97,
+    0xb9, 0x88, 0xdb, 0xea, 0x7d, 0x4c, 0x1f, 0x2e
+  };
+
+  uint8_t crc = 0xff;
+
+  crc ^= word >> 8;
+  crc = (crc << 4) ^ crc_table[crc >> 4];
+  crc = (crc << 4) ^ crc_table[crc >> 4];
+  crc ^= word >> 0;
+  crc = (crc << 4) ^ crc_table[crc >> 4];
+  crc = (crc << 4) ^ crc_table[crc >> 4];
+
+  return crc;
+}
+
+/****************************************************************************
+ * Name: scd41_set_command_param
+ ****************************************************************************/
+
+static void scd41_set_command_param(FAR struct scd41_word_s *param,
+                                    uint16_t value)
+{
+  param->data[0] = value >> 8;
+  param->data[1] = value >> 0;
+  param->crc = scd41_crc_word(value);
+}
+
+/****************************************************************************
+ * Name: scd41_data_word2uint16
+ ****************************************************************************/
+
+static uint16_t scd41_data_word2uint16(FAR const struct scd41_word_s *word)
+{
+  return (word[0].data[0] << 8) | (word[0].data[1]);
+}
+
+/****************************************************************************
+ * Name: scd41_crc_word
+ ****************************************************************************/
+
+static int scd41_check_data_crc(FAR const struct scd41_word_s *words,
+                                unsigned int num_words)
+{
+  while (num_words)
+    {
+      if (scd41_crc_word(scd41_data_word2uint16(words)) != words->crc)
+        {
+          return -1;
+        }
+
+      num_words--;
+      words++;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: scd41_softreset
+ *
+ * Description:
+ *   Reset the SCD41 sensor. This takes less than 2000 ms.
+ *
+ ****************************************************************************/
+
+static int scd41_softreset(FAR struct scd41_dev_s *priv)
+{
+  int ret;
+
+  ret = scd41_write_cmd(priv, SCD41_CMD_SOFT_RESET, NULL, 0);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: has_time_passed
+ *
+ * Description:
+ *   Return true if curr >= start + secs_since_start
+ *
+ ****************************************************************************/
+
+static bool has_time_passed(struct timespec curr,
+                            struct timespec start,
+                            unsigned int secs_since_start)
+{
+  if ((long)((start.tv_sec + secs_since_start) - curr.tv_sec) == 0)
+    {
+      return start.tv_nsec <= curr.tv_nsec;
+    }
+
+  return (long)((start.tv_sec + secs_since_start) - curr.tv_sec) <= 0;
+}
+
+/****************************************************************************
+ * Name: scd41_read_values
+ ****************************************************************************/
+
+static int scd41_read_values(FAR struct scd41_dev_s *priv, FAR float *temp,
+                             FAR float *rh, FAR float *co2, bool wait)
+{
+  struct scd41_word_s data[3];
+  struct timespec ts;
+  int ret;
+
+  clock_systime_timespec(&ts);
+
+  if (wait || !priv->valid ||
+      has_time_passed(ts, priv->last_update,
+                      SCD41_DEFAULT_MEASUREMENT_INTERVAL))
+    {
+      while (1)
+        {
+          /* Wait data to be ready. */
+
+          ret = scd41_write_cmd(priv, SCD41_CMD_GET_DATA_READY, NULL, 0);
+          if (ret < 0)
+            {
+              scd41_dbg("ERROR: scd41_write_cmd failed: %d\n", ret);
+              return ret;
+            }
+
+          ret = scd41_read_words(priv, data, 1);
+          if (ret < 0)
+            {
+              scd41_dbg("ERROR: scd41_read_words failed: %d\n", ret);
+              return ret;
+            }
+
+          if (scd41_check_data_crc(data, 1) < 0)
+            {
+              scd41_dbg("ERROR: scd41_read_words crc failed\n");
+              ret = -EIO;
+              return ret;
+            }
+
+          if ((scd41_data_word2uint16(data) & 0x07ff) == 0x0000)
+            {
+              if (!wait)
+                {
+                  scd41_dbg("ERROR: data not ready\n");
+                  ret = -EAGAIN;
+                  return ret;
+                }
+
+              ret = nxsig_usleep(500 * 1000);
+              if (ret == -EINTR)
+                {
+                  return ret;
+                }
+            }
+          else
+            {
+              break;
+            }
+        }
+
+      /* Read the raw data */
+
+      ret = scd41_write_cmd(priv, SCD41_CMD_READ_MEASUREMENT, NULL, 0);
+      if (ret < 0)
+        {
+          scd41_dbg("ERROR: scd41_write_cmd failed: %d\n", ret);
+          return ret;
+        }
+
+      ret = scd41_read_words(priv, data, 3);
+      if (ret < 0)
+        {
+          scd41_dbg("ERROR: scd41_read_words failed: %d\n", ret);
+          return ret;
+        }
+
+      if (scd41_check_data_crc(data, 3) < 0)
+        {
+          scd41_dbg("ERROR: scd41_read_words crc failed\n");
+          ret = -EIO;
+          return ret;
+        }
+
+      add_sensor_randomness((data[0].crc << 16) ^ (data[1].crc << 8) ^
+                            data[2].crc);
+
+      priv->co2 = (float)scd41_data_word2uint16(data + 0);
+      uint16_t tval = scd41_data_word2uint16(data + 1);
+      priv->temperature = (float)((tval * 175.0) / 65536.0 - 45.0);
+      uint16_t hval = scd41_data_word2uint16(data + 2);
+      priv->humidity = (float)(hval * 100.0 / 65536.0);
+      priv->last_update = ts;
+      priv->valid = true;
+    }
+
+  *temp = priv->temperature;
+  *rh = priv->humidity;
+  *co2 = priv->co2;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: scd41_configure
+ ****************************************************************************/
+
+static int scd41_configure(FAR struct scd41_dev_s *priv, bool start)
+{
+  struct scd41_word_s param;
+  int ret = OK;
+
+  /* Set altitude compensation. */
+
+  scd41_set_command_param(&param, priv->altitude_comp);
+  scd41_write_cmd(priv, SCD41_CMD_SET_ALT_COMPENSATION, &param, 1);
+
+  /* Set temperature offset. */
+
+  scd41_set_command_param(&param, priv->temperature_offset);
+  scd41_write_cmd(priv, SCD41_CMD_SET_TEMP_OFFSET, &param, 1);
+
+  /* Set pressure compensation. */
+
+  scd41_set_command_param(&param, priv->pressure_comp);
+  scd41_write_cmd(priv, SCD41_CMD_SET_PRESSURE_COMP, &param, 1);
+
+  if (start)
+    {
+      /* Start measurements. */
+
+      ret = scd41_write_cmd(priv, SCD41_CMD_START_MEASUREMENT, NULL, 0);
+      if (ret >= 0)
+        {
+          priv->started = true;
+        }
+    }
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: scd41_open
+ *
+ * Description:
+ *   This function is called whenever the SCD41x device is opened.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+static int scd41_open(FAR struct file *filep)
+{
+  FAR struct inode *inode = filep->f_inode;
+  FAR struct scd41_dev_s *priv = inode->i_private;
+  int ret = OK;
+
+  /* Get exclusive access */
+
+  ret = nxsem_wait_uninterruptible(&priv->devsem);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Increment the count of open references on the driver */
+
+  priv->crefs++;
+  DEBUGASSERT(priv->crefs > 0);
+
+  if (priv->crefs == 1)
+    {
+      ret = scd41_configure(priv, true);
+    }
+
+  if (ret < 0)
+    {
+      priv->crefs--;
+    }
+
+  nxsem_post(&priv->devsem);
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: scd41_close
+ *
+ * Description:
+ *   This routine is called when the SCD41 device is closed.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+static int scd41_close(FAR struct file *filep)
+{
+  FAR struct inode       *inode = filep->f_inode;
+  FAR struct scd41_dev_s *priv  = inode->i_private;
+  int ret;
+
+  /* Get exclusive access */
+
+  ret = nxsem_wait_uninterruptible(&priv->devsem);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Decrement the count of open references on the driver */
+
+  DEBUGASSERT(priv->crefs > 0);
+  priv->crefs--;
+
+  /* If the count has decremented to zero and the driver has been unlinked,
+   * then free memory now.
+   */
+
+  if (priv->crefs <= 0 && priv->unlinked)
+    {
+      nxsem_destroy(&priv->devsem);
+      kmm_free(priv);
+      return OK;
+    }
+
+  nxsem_post(&priv->devsem);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: scd41_read
+ ****************************************************************************/
+
+static ssize_t scd41_read(FAR struct file *filep, FAR char *buffer,
+                          size_t buflen)
+{
+  FAR struct inode *inode = filep->f_inode;
+  FAR struct scd41_dev_s *priv = inode->i_private;
+  ssize_t length = 0;
+  float temp;
+  float rh;
+  float co2;
+  unsigned int temp100;
+  unsigned int rh100;
+  unsigned int co2_100;
+  int ret;
+
+  /* Get exclusive access */
+
+  ret = nxsem_wait_uninterruptible(&priv->devsem);
+  if (ret < 0)
+    {
+      return (ssize_t)ret;
+    }
+
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+  if (priv->unlinked)
+    {
+      /* Do not allow operations on unlinked sensors. This allows
+       * sensor use on hot swappable I2C bus.
+       */
+
+      nxsem_post(&priv->devsem);
+      return -ENODEV;
+    }
+#endif
+
+  if (!priv->started)
+    {
+      return -ENODATA;
+    }
+
+  ret = scd41_read_values(priv, &temp, &rh, &co2,
+                          !(filep->f_oflags & O_NONBLOCK));
+  if (ret < 0)
+    {
+      scd41_dbg("cannot read data: %d\n", ret);
+    }
+  else
+    {
+      /* This interface is mainly intended for easy debugging in nsh. */
+
+      temp100 = abs(temp * 100);
+      rh100 = abs(rh * 100);
+      co2_100 = abs(co2 * 100);
+
+      length = snprintf(buffer, buflen, "%s%u.%02u %s%u.%02u %s%u.%02u\n",
+                        co2 < 0 ? "-" : "", co2_100 / 100, co2_100 % 100,
+                        temp < 0 ? "-" : "", temp100 / 100, temp100 % 100,
+                        rh < 0 ? "-" : "", rh100 / 100, rh100 % 100);
+      if (length > buflen)
+        {
+          length = buflen;
+        }
+    }
+
+  nxsem_post(&priv->devsem);
+  return length;
+}
+
+/****************************************************************************
+ * Name: scd41_write
+ ****************************************************************************/
+
+static ssize_t scd41_write(FAR struct file *filep, FAR const char *buffer,
+                           size_t buflen)
+{
+  return -ENOSYS;
+}
+
+/****************************************************************************
+ * Name: scd41_ioctl
+ ****************************************************************************/
+
+static int scd41_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
+{
+  FAR struct inode *inode = filep->f_inode;
+  FAR struct scd41_dev_s *priv = inode->i_private;
+  struct scd41_word_s param;
+  int ret;
+
+  /* Get exclusive access */
+
+  ret = nxsem_wait_uninterruptible(&priv->devsem);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+  if (priv->unlinked)
+    {
+      /* Do not allow operations on unlinked sensors. This allows
+       * sensor use on hot swappable I2C bus.
+       */
+
+      nxsem_post(&priv->devsem);
+      return -ENODEV;
+    }
+#endif
+
+  switch (cmd)
+    {
+      /* Soft reset the SCD41, Arg: None */
+
+      case SNIOC_RESET:
+        {
+          priv->interval = SCD41_DEFAULT_MEASUREMENT_INTERVAL;
+          priv->pressure_comp = SCD41_DEFAULT_PRESSURE_COMPENSATION;
+          priv->altitude_comp = SCD41_DEFAULT_ALTITUDE_COMPENSATION;
+          priv->temperature_offset = SCD41_DEFAULT_TEMPERATURE_OFFSET;
+
+          ret = scd41_softreset(priv);
+          scd41_dbg("softreset ret: %d\n", ret);
+
+          scd41_configure(priv, priv->started);
+        }
+        break;
+
+      /* Start background measurement, Arg: None */
+
+      case SNIOC_START:
+        {
+          /* Start measurements. */
+
+          ret = scd41_write_cmd(priv, SCD41_CMD_START_MEASUREMENT, NULL, 0);
+          if (ret >= 0)
+            {
+              priv->started = true;
+            }
+        }
+        break;
+
+      /* Stop background measurement, Arg: None */
+
+      case SNIOC_STOP:
+        {
+          /* Stop measurements. */
+
+          ret = scd41_write_cmd(priv, SCD41_CMD_STOP_MEASUREMENT, NULL, 0);
+          if (ret >= 0)
+            {
+              priv->started = false;
+            }
+        }
+        break;
+
+      /* Set temperature offset value, Arg: uint16_t */
+
+      case SNIOC_SET_TEMP_OFFSET:
+        {
+          if (arg > UINT16_MAX)
+            {
+              ret = -EINVAL;
+              break;
+            }
+
+          /* Actual Toffset = temperature_offset * 175.0 / 2^16 */
+
+          priv->temperature_offset = arg;
+          scd41_set_command_param(&param, priv->temperature_offset);
+          ret = scd41_write_cmd(priv, SCD41_CMD_SET_TEMP_OFFSET, &param, 1);
+        }
+        break;
+
+      /* Set pressure compensation value, Arg: uint16_t */
+
+      case SNIOC_SET_PRESSURE_COMP:
+        {
+          if (arg > UINT16_MAX)
+            {
+              ret = -EINVAL;
+              break;
+            }
+
+          priv->pressure_comp = arg;
+          scd41_set_command_param(&param, priv->pressure_comp);
+          ret = scd41_write_cmd(priv, SCD41_CMD_SET_PRESSURE_COMP,
+                                &param, 1);
+        }
+        break;
+
+      /* Set altitude compensation value, Arg: uint16_t */
+
+      case SNIOC_SET_ALTITUDE_COMP:
+        {
+          if (arg > UINT16_MAX)
+            {
+              ret = -EINVAL;
+              break;
+            }
+
+          priv->altitude_comp = arg;
+          scd41_set_command_param(&param, priv->altitude_comp);
+          ret = scd41_write_cmd(priv, SCD41_CMD_SET_ALT_COMPENSATION,
+                                &param, 1);
+        }
+        break;
+
+      /* Set Forced Recalibration value (FRC), Arg: uint16_t */
+
+      case SNIOC_SET_FRC:
+        {
+          if (arg > UINT16_MAX)
+            {
+              ret = -EINVAL;
+              break;
+            }
+
+          scd41_set_command_param(&param, arg);
+          ret = scd41_write_cmd(priv, SCD41_CMD_SET_FRC, &param, 1);
+        }
+        break;
+
+      /* (De-)Activate Automatic Self-Calibration (ASC), Arg: bool */
+
+      case SNIOC_ENABLE_ASC:
+        {
+          if (arg != !!arg) /* 0 or 1 */
+            {
+              ret = -EINVAL;
+              break;
+            }
+
+          scd41_set_command_param(&param, arg);
+          ret = scd41_write_cmd(priv, SCD41_CMD_SET_ASC, &param, 1);
+        }
+        break;
+
+      /* Read sensor data, Arg: struct scd41_conv_data_s *data */
+
+      case SNIOC_READ_CONVERT_DATA:
+        {
+          float temp;
+          float rh;
+          float co2;
+
+          ret = scd41_read_values(priv, &temp, &rh, &co2, false);
+          if (ret < 0)
+            {
+              scd41_dbg("cannot read data: %d\n", ret);
+            }
+          else
+            {
+              FAR struct scd41_conv_data_s *data =
+                (FAR struct scd41_conv_data_s *)arg;
+
+              data->temperature = temp;
+              data->humidity = rh;
+              data->co2 = co2;
+            }
+        }
+        break;
+
+      default:
+        scd41_dbg("Unrecognized cmd: %d\n", cmd);
+        ret = -ENOTTY;
+        break;
+    }
+
+  nxsem_post(&priv->devsem);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: scd41_unlink
+ ****************************************************************************/
+
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+static int scd41_unlink(FAR struct inode *inode)
+{
+  FAR struct scd41_dev_s *priv;
+  int ret;
+
+  DEBUGASSERT(inode != NULL && inode->i_private != NULL);
+  priv = (FAR struct scd41_dev_s *)inode->i_private;
+
+  /* Get exclusive access */
+
+  ret = nxsem_wait_uninterruptible(&priv->devsem);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* Are there open references to the driver data structure? */
+
+  if (priv->crefs <= 0)
+    {
+      nxsem_destroy(&priv->devsem);
+      kmm_free(priv);
+      return OK;
+    }
+
+  /* No... just mark the driver as unlinked and free the resources when
+   * the last client closes their reference to the driver.
+   */
+
+  priv->unlinked = true;
+  nxsem_post(&priv->devsem);
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+#ifdef CONFIG_SCD41_I2C
+/****************************************************************************
+ * Name: scd41_register_i2c
+ *
+ * Description:
+ *   Register the SCD41 character device as 'devpath'
+ *
+ * Input Parameters:
+ *   devpath - The full path to the driver to register. E.g., "/dev/co2_0"
+ *   i2c     - An instance of the I2C interface to use to communicate with
+ *             the SCD41
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int scd41_register_i2c(FAR const char *devpath, FAR struct i2c_master_s *i2c)
+{
+  FAR struct scd41_dev_s *priv;
+  int ret;
+
+  DEBUGASSERT(i2c != NULL);
+  DEBUGASSERT(scd41_crc_word(0xbeef) == 0x92);
+
+  /* Initialize the device structure */
+
+  priv = (FAR struct scd41_dev_s *)kmm_zalloc(sizeof(struct scd41_dev_s));
+  if (priv == NULL)
+    {
+      scd41_dbg("ERROR: Failed to allocate instance\n");
+      return -ENOMEM;
+    }
+
+  priv->i2c  = i2c;
+  priv->addr = CONFIG_SCD41_ADDR;
+  priv->started = false;
+  priv->interval = SCD41_DEFAULT_MEASUREMENT_INTERVAL;
+  priv->pressure_comp = SCD41_DEFAULT_PRESSURE_COMPENSATION;
+  priv->altitude_comp = SCD41_DEFAULT_ALTITUDE_COMPENSATION;
+  priv->temperature_offset = SCD41_DEFAULT_TEMPERATURE_OFFSET;
+
+  nxsem_init(&priv->devsem, 0, 1);
+
+  /* Register the character driver */
+
+  ret = register_driver(devpath, &g_scd41fops, 0666, priv);
+  if (ret < 0)
+    {
+      scd41_dbg("ERROR: Failed to register driver: %d\n", ret);
+      kmm_free(priv);
+    }
+
+  return ret;
+}
+#endif /* CONFIG_SCD41_I2C */
+
+#endif /* CONFIG_SENSORS_SCD41 */
diff --git a/include/nuttx/sensors/scd41.h b/include/nuttx/sensors/scd41.h
new file mode 100644
index 0000000000..f3831363f6
--- /dev/null
+++ b/include/nuttx/sensors/scd41.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+ * include/nuttx/sensors/scd41.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_SENSORS_SCD41_H
+#define __INCLUDE_NUTTX_SENSORS_SCD41_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/sensors/ioctl.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define CONFIG_SCD41_ADDR 0x62
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct i2c_master_s;  /* Forward reference */
+
+struct scd41_conv_data_s
+{
+  float temperature; /* Celsius */
+  float humidity;    /* RH-% */
+  float co2;         /* CO₂ PPM */
+};
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef CONFIG_SCD41_I2C
+/****************************************************************************
+ * Name: scd41_register_i2c
+ *
+ * Description:
+ *   Register the SCD41 character device as 'devpath'
+ *
+ * Input Parameters:
+ *   devpath - The full path to the driver to register. E.g., "/dev/co2_0"
+ *   i2c     - An instance of the I2C interface to use to communicate with
+ *             the SCD41
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int scd41_register_i2c(FAR const char *devpath,
+                       FAR struct i2c_master_s *i2c);
+
+#endif
+
+#endif /* __INCLUDE_NUTTX_SENSORS_SCD41_H */


[incubator-nuttx] 03/03: drivers/sensors/sgp30: Fix redundant parameter check

Posted by pk...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 9cd53d714ec43f51a1158f4b2c124ec6d585ae42
Author: SPRESENSE <41...@users.noreply.github.com>
AuthorDate: Mon Apr 11 16:36:18 2022 +0900

    drivers/sensors/sgp30: Fix redundant parameter check
    
    Fix redundant conditions.
---
 drivers/sensors/sgp30.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/sensors/sgp30.c b/drivers/sensors/sgp30.c
index 1c345a3873..ab6cf1fb82 100644
--- a/drivers/sensors/sgp30.c
+++ b/drivers/sensors/sgp30.c
@@ -897,7 +897,7 @@ static int sgp30_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
         {
           /* Input is absolute humidity in unit "mg/m^3". */
 
-          if (arg < 0 || arg >= 256000)
+          if (arg >= 256000)
             {
               ret = -EINVAL;
               break;