diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig index eb994667611..d3d4dbfb586 100644 --- a/drivers/sensors/Kconfig +++ b/drivers/sensors/Kconfig @@ -184,6 +184,34 @@ config SENSORS_HCSR04 ---help--- Enable driver support for the HC-SR04 Distance Sensor. +config SENSORS_HYT271 + bool "IST HYT271 Humidity and Temperature Sensor support" + default n + ---help--- + Enable driver support for the HYT271/HYT221/HYT939 humidity/temperature sensor family. + +config SENSORS_HYT271_POLL + bool "Enables polling sensor data" + depends on SENSORS_HYT271 + default n + ---help--- + Enables polling of sensor. + +config SENSORS_HYT271_POLL_INTERVAL + int "Polling interval in microseconds, default 1 sec" + depends on SENSORS_HYT271 && SENSORS_HYT271_POLL + default 1000000 + range 0 4294967295 + ---help--- + The interval until a new sensor measurement will be triggered. + +config SENSORS_HYT271_THREAD_STACKSIZE + int "Worker thread stack size" + depends on SENSORS_HYT271 && SENSORS_HYT271_POLL + default 1024 + ---help--- + The stack size for the worker thread. + if SENSORS_HCSR04 config HCSR04_DEBUG diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs index f4e34468fc4..d1fd73da203 100644 --- a/drivers/sensors/Make.defs +++ b/drivers/sensors/Make.defs @@ -68,6 +68,10 @@ ifeq ($(CONFIG_SENSORS_FXOS8700CQ),y) CSRCS += fxos8700cq.c endif +ifeq ($(CONFIG_SENSORS_HYT271),y) + CSRCS += hyt271.c +endif + ifeq ($(CONFIG_SENSORS_KXTJ9),y) CSRCS += kxtj9.c endif diff --git a/drivers/sensors/hyt271.c b/drivers/sensors/hyt271.c new file mode 100644 index 00000000000..91700887ee0 --- /dev/null +++ b/drivers/sensors/hyt271.c @@ -0,0 +1,976 @@ +/**************************************************************************** + * drivers/sensors/hyt271.c + * Character driver for HYT271 Digital Humidity and Temperature Module. + * + * 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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_HYT271) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define HYT271_TEMPDATA_MASK 0x3fff +#define HYT271_HUMIDATA_MASK 0x3fff + +#define HYT271_TEMPDATA_SHIFT(x) ((x) >> 2) +#define HYT271_HUMIDATA_SHIFT(x) ((x) >> 16) + +#define HYT271_TEMPRAWDATA(x) (HYT271_TEMPDATA_SHIFT(x) & HYT271_TEMPDATA_MASK) +#define HYT271_TEMPRAWEQUAL(x, y) \ + (HYT271_TEMPRAWDATA(x) == HYT271_TEMPRAWDATA(y)) + +#define HYT271_HUMIRAWDATA(x) (HYT271_HUMIDATA_SHIFT(x) & HYT271_HUMIDATA_MASK) +#define HYT271_HUMIRAWEQUAL(x, y) \ + (HYT271_HUMIRAWDATA(x) == HYT271_HUMIRAWDATA(y)) + +#define HYT271_TEMPDATA(x) (HYT271_TEMPRAWDATA(x) * 165.0 / 16383.0 - 40.0) +#define HYT271_HUMIDATA(x) (HYT271_HUMIRAWDATA(x) * 100.0 / 16383.0) + +#define HYT271_SENSOR_HUMI 0 +#define HYT271_SENSOR_TEMP 1 +#define HYT271_SENSOR_MAX 2 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct hyt271_sensor_data_s +{ + uint32_t data; + uint64_t timestamp; +}; + +struct hyt271_dev_s; +struct hyt271_sensor_s +{ + struct sensor_lowerhalf_s lower; /* Common lower interface */ + unsigned int buffer_size; /* Data size for reading */ +#ifdef CONFIG_SENSORS_HYT271_POLL + bool enabled; /* Sensor activated */ +#endif + FAR struct hyt271_dev_s *dev; /* Driver instance */ +}; + +struct hyt271_dev_s +{ + struct hyt271_sensor_s sensor[HYT271_SENSOR_MAX]; /* Sensor types */ + FAR struct i2c_master_s *i2c; /* I2C interface */ + FAR struct hyt271_bus_s *bus; /* Bus power interface */ + sem_t lock_measure_cylce; /* Locks measure cycle */ + uint32_t freq; /* I2C Frequency */ +#ifdef CONFIG_SENSORS_HYT271_POLL + unsigned int interval; /* Polling interval */ + sem_t run; /* Locks sensor thread */ + bool initial_read; /* Already read */ +#endif + uint8_t addr; /* I2C address */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Sensor functions */ + +static int hyt271_active(FAR struct sensor_lowerhalf_s *lower, + unsigned char enabled); + +static int hyt271_fetch(FAR struct sensor_lowerhalf_s *lower, + FAR char *buffer, size_t buflen); + +static int hyt271_control(FAR struct sensor_lowerhalf_s *lower, + int cmd, unsigned long arg); + +#ifdef CONFIG_SENSORS_HYT271_POLL +static int hyt271_set_interval(FAR struct sensor_lowerhalf_s *lower, + FAR unsigned int *period_us); +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct sensor_ops_s g_hyt271_ops = +{ +#ifdef CONFIG_SENSORS_HYT271_POLL + .set_interval = hyt271_set_interval, +#endif + .activate = hyt271_active, + .fetch = hyt271_fetch, + .control = hyt271_control +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: hyt271_humi_from_rawdata + * + * Description: Helper for converting raw data to temperature. + * + * Parameter: + * data - Pointer to internal datat structure for measured data + * temp - Pointer to sensor data structure for humidity + ****************************************************************************/ + +static void hyt271_humi_from_rawdata(FAR struct hyt271_sensor_data_s *data, + FAR struct sensor_event_humi *humi) +{ + humi->timestamp = data->timestamp; + humi->humidity = HYT271_HUMIDATA(data->data); +} + +/**************************************************************************** + * Name: hyt271_temp_from_rawdata + * + * Description: Helper for converting raw data to temperature. + * + * Parameter: + * data - Pointer to internal datat structure for measured data + * temp - Pointer to sensor data structure for temperature + ****************************************************************************/ + +static void hyt271_temp_from_rawdata(FAR struct hyt271_sensor_data_s *data, + FAR struct sensor_event_temp *temp) +{ + temp->timestamp = data->timestamp; + temp->temperature = HYT271_TEMPDATA(data->data); +} + +/**************************************************************************** + * Name: hyt271_curtime + * + * Description: Helper to get current timestamp. + * + * Return: + * Timestamp in nsec + ****************************************************************************/ + +static unsigned long hyt271_curtime(void) +{ + struct timespec ts; +#ifdef CONFIG_CLOCK_MONOTONIC + clock_gettime(CLOCK_MONOTONIC, &ts); +#else + clock_gettime(CLOCK_REALTIME, &ts); +#endif + + return 1000000ull * ts.tv_sec + ts.tv_nsec / 1000; +} + +/**************************************************************************** + * Name: hyt271_init_rw_buffer + * + * Description: Helper for buffer initializing. + * + * Parameter: + * buffer - Pointer to the buffers memory region + * cmd - The command to set in the buffer + * size - The buffer size + ****************************************************************************/ + +static void hyt271_init_rw_buffer(FAR uint8_t *buffer, uint8_t cmd, + uint8_t size) +{ + int n; + + buffer[0] = cmd; + + for (n = 1; n < size; n++) + { + buffer[n] = 0x00; + } +} + +/**************************************************************************** + * Name: hyt271_df + * + * Description: Helper for reading data by a data fetch. + * + * Parameter: + * dev - Pointer to private driver instance + * config - I2C configuration + * buffer - Pointer to the buffers memory region + * size - The buffer size + * + * Return: + * OK - on success + ****************************************************************************/ + +static int hyt271_df(FAR struct hyt271_dev_s *dev, + FAR struct i2c_config_s *config, FAR uint8_t *buffer, + uint8_t size) +{ + int ret; + + /* Read data from the device */ + + ret = i2c_read(dev->i2c, config, buffer, size); + if (ret < 0) + { + snerr ("i2c_read failed: %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: hyt271_mr + * + * Description: Helper for sending a measurement cylce request. + * + * Parameter: + * dev - Pointer to private driver instance + * config - I2C configuration + * + * Return: + * OK - on success + ****************************************************************************/ + +static int hyt271_mr(FAR struct hyt271_dev_s *dev, + FAR struct i2c_config_s *config) +{ + uint8_t buffer; + int ret; + + /* We only must send the i2c address with write bit enabled here. This + * isn't provided by the i2c api, so instead sending a null byte seems + * working fine. + */ + + buffer = 0x00; + + /* Send address only with write bit enabled */ + + ret = i2c_write(dev->i2c, config, &buffer, 1); + if (ret < 0) + { + snerr ("i2c_write failed: %d\n", ret); + } + + /* Wait until measure cycle is done. This takes between 60 - 100 ms. */ + + nxsig_usleep(100000); + return ret; +} + +/**************************************************************************** + * Name: hyt271_cmd + * + * Description: Helper for sending a command. + * + * Parameter: + * dev - Pointer to private driver instance + * config - I2C configuration + * buffer - Pointer to the buffers memory region + * size - The buffer size + * + * Return: + * OK - on success + ****************************************************************************/ + +static int hyt271_cmd(FAR struct hyt271_dev_s *dev, + FAR struct i2c_config_s *config, FAR uint8_t *buffer, + uint8_t size) +{ + int ret; + + /* Write command data to the device */ + + ret = i2c_write(dev->i2c, config, buffer, size); + if (ret < 0) + { + snerr ("i2c_write failed: %d\n", ret); + return ret; + } + + return OK; +} + +/**************************************************************************** + * Name: hyt271_cmd_response + * + * Description: Helper for sending a command fetching the response after a + * neccessary timeout. + * Parameter: + * dev - Pointer to private driver instance + * config - I2C configuration + * buffer - Pointer to the buffers memory region + * wsize - Bytes to write from the buffer + * rsize - Bytes to read into the buffer + * usec - Timeout between write and read operation in usec + * + * Return: + * OK - on success + ****************************************************************************/ + +static int hyt271_cmd_response(FAR struct hyt271_dev_s *dev, + FAR struct i2c_config_s *config, + FAR uint8_t *buffer, uint8_t wsize, + uint8_t rsize, unsigned int usec) +{ + int ret; + + /* Send command */ + + ret = hyt271_cmd(dev, config, buffer, wsize); + if (ret < 0) + { + return ret; + } + + /* Sleep for usec µs until response is ready */ + + nxsig_usleep(usec); + + /* Read response and return */ + + hyt271_init_rw_buffer(buffer, 0x00, rsize); + ret = hyt271_df(dev, config, buffer, rsize); + if (ret < 0) + { + return ret; + } + + /* Check if ack response is valid */ + + if (buffer[0] != 0x81) + { + snerr ("wrong ack response: 0x%x\n", buffer[0]); + ret = -EIO; + } + + return ret; +} + +/**************************************************************************** + * Name: hyt271_change_addr + * + * Description: Change I2C address of the chip. + * + * Parameter: + * dev - Pointer to private driver instance + * addr - The new I2C address + * + * Return: + * OK - on success + ****************************************************************************/ + +static int hyt271_change_addr(FAR struct hyt271_dev_s *dev, uint8_t addr) +{ + int ret; + irqstate_t irq_flags; + struct i2c_config_s config; + uint8_t buffer[3]; + + if (dev->bus == NULL) + { + return -ENOSYS; + } + + if (addr & 0x80) + { + return -EINVAL; + } + + /* Reset and subsequently operation must be mutual exclusive + * Prevents from beeing used by another open driver instance during this + * operations. + */ + + ret = nxsem_wait(&dev->lock_measure_cylce); + if (ret < 0) + { + return ret; + } + + /* Set up the I2C configuration */ + + config.frequency = dev->freq; + config.address = dev->addr; + config.addrlen = 7; + + /* Enter in command mode */ + + hyt271_init_rw_buffer(buffer, HYT271_CMD_START_CM, 3); + + /* The following section must be done within a time-constrained window. + * It should be enough to lock this cpu than in the case of SMP all the + * others. + */ + + irq_flags = up_irq_save(); + + /* Power on reset the bus. + * Entering in command mode must be done within the next 10 ms after power + * up. + */ + + ret = dev->bus->pwonreset(dev->bus); + if (ret < 0) + { + ret = -EIO; + goto err_unlock; + } + + ret = hyt271_cmd_response(dev, &config, buffer, 3, 1, 100); + + /* The chip should be in command mode now */ + + up_irq_restore(irq_flags); + + if (ret < 0) + { + goto err_unlock; + } + + /* Fetch current I2C address */ + + hyt271_init_rw_buffer(buffer, HYT271_CMD_EEPROM_READ, 3); + ret = hyt271_cmd_response(dev, &config, buffer, 3, 3, 100); + if (ret < 0) + { + goto err_unlock; + } + + if ((buffer[2] & 0x7f) != dev->addr) + { + snerr("wrong current I2C address responsed: 0x%x\n", buffer[2] & 0x7f); + ret = -EIO; + goto err_unlock; + } + + /* Write new I2C address */ + + hyt271_init_rw_buffer(buffer, HYT271_CMD_EEPROM_WRITE, 3); + buffer[2] = addr; + ret = hyt271_cmd_response(dev, &config, buffer, 3, 3, 12000); + if (ret < 0) + { + goto err_unlock; + } + + /* Fetch new I2C address again for confirmation */ + + hyt271_init_rw_buffer(buffer, HYT271_CMD_EEPROM_READ, 3); + ret = hyt271_cmd_response(dev, &config, buffer, 3, 3, 100); + if (ret < 0) + { + goto err_unlock; + } + + if ((buffer[2] & 0x7f) != addr) + { + snerr("wrong changed I2C address responsed: 0x%x\n", buffer[2] & 0x7f); + ret = -EIO; + goto err_unlock; + } + + /* Finally go back to normal mode */ + + hyt271_init_rw_buffer(buffer, HYT271_CMD_START_NOM, 3); + ret = hyt271_cmd(dev, &config, buffer, 3); + if (ret < 0) + { + goto err_unlock; + } + + /* Set new address */ + + dev->addr = addr; + + nxsem_post(&dev->lock_measure_cylce); + return OK; + +err_unlock: + nxsem_post(&dev->lock_measure_cylce); + return ret; +} + +/**************************************************************************** + * Name: hyt271_measure_read + * + * Description: + * Performs a measuremnt cylce and reads measured data. + * + * Parameter: + * dev - Pointer to private driver instance + * data - Pointer to internal data structure for measured data + + * Return: + * OK - on success + ****************************************************************************/ + +static int hyt271_measure_read(FAR struct hyt271_dev_s *dev, + FAR struct hyt271_sensor_data_s *data) +{ + int ret; + struct i2c_config_s config; + uint8_t buffer[4]; + + /* Measure request and read operation must be mutual exclusive + * Prevents from beeing used by another open driver instance during this + * read operation. + */ + + ret = nxsem_wait(&dev->lock_measure_cylce); + if (ret < 0) + { + return ret; + } + + /* Set up the I2C configuration */ + + config.frequency = dev->freq; + config.address = dev->addr; + config.addrlen = 7; + + /* Start a measurement request */ + + ret = hyt271_mr(dev, &config); + if (ret < 0) + { + snerr("ERROR: Error starting measure cycle\n"); + goto err_unlock; + } + + /* Read humity and temperature from the sensor */ + + ret = hyt271_df(dev, &config, buffer, 4); + if (ret < 0) + { + snerr("ERROR: Error reading sensor data!\n"); + goto err_unlock; + } + + sninfo("value: %02x %02x %02x %02x ret: %d\n", + buffer[0], buffer[1], buffer[2], buffer[3], ret); + + data->data = buffer[0] << 24 | buffer[1] << 16 | \ + buffer[2] << 8 | buffer[3]; + data->timestamp = hyt271_curtime(); + + nxsem_post(&dev->lock_measure_cylce); + + return OK; + +err_unlock: + nxsem_post(&dev->lock_measure_cylce); + return ret; +} + +/**************************************************************************** + * Name: hyt271_fetch + * + * Description: Performs a measuremnt cylce and data read with data + * conversion. + * + * Parameter: + * lower - Pointer to lower half sensor driver instance + * buffer - Pointer to the buffer for reading data + * buflen - Size of the buffer + * + * Return: + * OK - on success + ****************************************************************************/ + +static int hyt271_fetch(FAR struct sensor_lowerhalf_s *lower, + FAR char *buffer, size_t buflen) +{ + int ret; + struct hyt271_sensor_data_s data; + FAR struct hyt271_sensor_s *priv = (FAR struct hyt271_sensor_s *)lower; + + /* Check if the user is reading the right size */ + + if (buflen != priv->buffer_size) + { + snerr("ERROR: You need to read %d bytes from this sensor!\n", + priv->buffer_size); + return -EINVAL; + } + + ret = hyt271_measure_read(priv->dev, &data); + if (ret < 0) + { + return ret; + } + + switch (lower->type) + { + case SENSOR_TYPE_AMBIENT_TEMPERATURE: + { + struct sensor_event_temp temp; + hyt271_temp_from_rawdata(&data, &temp); + memcpy(buffer, &temp, sizeof(temp)); + } + break; + case SENSOR_TYPE_RELATIVE_HUMIDITY: + { + struct sensor_event_humi humi; + hyt271_humi_from_rawdata(&data, &humi); + memcpy(buffer, &humi, sizeof(humi)); + } + break; + default: + return -EINVAL; + } + + return buflen; +} + +/**************************************************************************** + * Name: hyt271_control + * + * Description: Interface function of struct sensor_ops_s. + * + * Return: + * OK - on success + ****************************************************************************/ + +static int hyt271_control(FAR struct sensor_lowerhalf_s *lower, + int cmd, unsigned long arg) +{ + int ret; + struct hyt271_sensor_s *priv = (FAR struct hyt271_sensor_s *)lower; + + switch (cmd) + { + /* Read i2c address */ + + case SNIOC_READADDR: + { + FAR uint8_t *ptr = (FAR uint8_t *)((uintptr_t)arg); + DEBUGASSERT(ptr != NULL); + *ptr = priv->dev->addr; + sninfo("readaddr: %02x\n", *ptr); + ret = OK; + } + break; + + /* Change i2c address */ + + case SNIOC_CHANGEADDR: + { + uint8_t addr = arg; + ret = hyt271_change_addr(priv->dev, addr); + sninfo("changeaddr: %02x\n", addr); + } + break; + + default: + snerr("ERROR: Unrecognized cmd: %d\n", cmd); + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Name: hyt271_active + * + * Description: Interface function of struct sensor_ops_s. + * + * Return: + * OK - on success + ****************************************************************************/ + +static int hyt271_active(FAR struct sensor_lowerhalf_s *lower, + unsigned char enabled) +{ +#ifdef CONFIG_SENSORS_HYT271_POLL + bool start_thread = false; + struct hyt271_sensor_s *priv = (FAR struct hyt271_sensor_s *)lower; + + if (enabled) + { + if (!priv->dev->sensor[HYT271_SENSOR_TEMP].enabled && + !priv->dev->sensor[HYT271_SENSOR_HUMI].enabled) + { + start_thread = true; + } + } + + priv->enabled = enabled; + + if (start_thread == true) + { + /* Wake up the thread */ + + nxsem_post(&priv->dev->run); + } +#endif + + return OK; +} + +/**************************************************************************** + * Name: hyt271_set_interval + * + * Description: Interface function of struct sensor_ops_s. + * + * Return: + * OK - on success + ****************************************************************************/ + +#ifdef CONFIG_SENSORS_HYT271_POLL +static int hyt271_set_interval(FAR struct sensor_lowerhalf_s *lower, + FAR unsigned int *period_us) +{ + FAR struct hyt271_sensor_s *priv = (FAR struct hyt271_sensor_s *)lower; + priv->dev->interval = *period_us; + return OK; +} +#endif + +/**************************************************************************** + * Name: hyt271_thread + * + * Description: Thread for performing interval measurement cycle and data + * read. + * + * Parameter: + * argc - Number opf arguments + * argv - Pointer to argument list + ****************************************************************************/ + +#ifdef CONFIG_SENSORS_HYT271_POLL +static int hyt271_thread(int argc, char** argv) +{ + FAR struct hyt271_dev_s *priv = (FAR struct hyt271_dev_s *) + ((uintptr_t)strtoul(argv[1], NULL, 0)); + + while (true) + { + int ret; + uint32_t orawdata; + struct hyt271_sensor_data_s data; + struct hyt271_sensor_s *hsensor = &priv->sensor[HYT271_SENSOR_HUMI]; + struct hyt271_sensor_s *tsensor = &priv->sensor[HYT271_SENSOR_TEMP]; + + if (!hsensor->enabled && !tsensor->enabled) + { + /* Reset inital read identifier */ + + priv->initial_read = false; + + /* Waiting to be woken up */ + + ret = nxsem_wait(&priv->run); + if (ret < 0) + { + continue; + } + } + + /* Store the last sensor data for later comparison */ + + orawdata = data.data; + + ret = hyt271_measure_read(priv, &data); + + if (!ret) + { + /* Notify upper */ + + if (priv->initial_read == false || (hsensor->enabled == true && + !HYT271_HUMIRAWEQUAL(orawdata, data.data))) + { + struct sensor_event_humi humi; + hyt271_humi_from_rawdata(&data, &humi); + hsensor->lower.push_event(hsensor->lower.priv, &humi, + sizeof(struct sensor_event_humi)); + } + + if (priv->initial_read == false || (tsensor->enabled == true && + !HYT271_TEMPRAWEQUAL(orawdata, data.data))) + { + struct sensor_event_temp temp; + hyt271_temp_from_rawdata(&data, &temp); + tsensor->lower.push_event(tsensor->lower.priv, &temp, + sizeof(struct sensor_event_temp)); + } + + if (priv->initial_read == false) + { + priv->initial_read = true; + } + } + + /* Sleeping thread before fetching the next sensor data */ + + nxsig_usleep(priv->interval); + } + + return OK; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: hyt271_register + * + * Description: + * Register the HYT271 character device. + * + * Input Parameters: + * devno - The user specifies device number, from 0. + * i2c - An instance of the I2C interface to communicate with HYT271 + * sensor. + * + * addr - The I2C address of the HYT271. + * bus - Callback to board specific logic for i2c bus power. + * Will be used for changing i2c address of the sensor and can be + * set to NULL when not supported. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + ****************************************************************************/ + +int hyt271_register(int devno, FAR struct i2c_master_s *i2c, uint8_t addr, + FAR struct hyt271_bus_s *bus) +{ + int ret; + struct hyt271_sensor_s *tmp; +#ifdef CONFIG_SENSORS_HYT271_POLL + FAR char *argv[2]; + char arg1[32]; +#endif + + /* Sanity check */ + + if (!i2c) + { + snerr("Invalid i2c instance\n"); + return -EINVAL; + } + + /* Initialize the HYT271 device structure */ + + FAR struct hyt271_dev_s *priv = (FAR struct hyt271_dev_s *) + kmm_malloc(sizeof(struct hyt271_dev_s)); + + if (priv == NULL) + { + snerr("ERROR: Failed to allocate instance\n"); + return -ENOMEM; + } + + priv->i2c = i2c; + priv->freq = 100000; + priv->addr = addr; + priv->bus = bus; +#ifdef CONFIG_SENSORS_HYT271_POLL + priv->interval = CONFIG_SENSORS_HYT271_POLL_INTERVAL; + priv->initial_read = false; +#endif + + nxsem_init(&priv->lock_measure_cylce, 0, 1); +#ifdef CONFIG_SENSORS_HYT271_POLL + nxsem_init(&priv->run, 0, 0); + nxsem_set_protocol(&priv->run, SEM_PRIO_NONE); +#endif + + /* Humidity register */ + + tmp = &priv->sensor[HYT271_SENSOR_HUMI]; + tmp->dev = priv; +#ifdef CONFIG_SENSORS_HYT271_POLL + tmp->enabled = false; +#endif + tmp->buffer_size = sizeof(struct sensor_event_humi); + tmp->lower.ops = &g_hyt271_ops; + tmp->lower.type = SENSOR_TYPE_RELATIVE_HUMIDITY; + tmp->lower.uncalibrated = false; + tmp->lower.buffer_number = 1; + ret = sensor_register(&tmp->lower, devno); + if (ret < 0) + { + goto humi_err; + } + + /* Temperature register */ + + tmp = &priv->sensor[HYT271_SENSOR_TEMP]; + tmp->dev = priv; +#ifdef CONFIG_SENSORS_HYT271_POLL + tmp->enabled = false; +#endif + tmp->buffer_size = sizeof(struct sensor_event_temp); + tmp->lower.ops = &g_hyt271_ops; + tmp->lower.type = SENSOR_TYPE_AMBIENT_TEMPERATURE; + tmp->lower.uncalibrated = false; + tmp->lower.buffer_number = 1; + ret = sensor_register(&tmp->lower, devno); + if (ret < 0) + { + goto temp_err; + } + +#ifdef CONFIG_SENSORS_HYT271_POLL + /* Create thread for sensor */ + + snprintf(arg1, 16, "0x%" PRIxPTR, (uintptr_t)priv); + argv[0] = arg1; + argv[1] = NULL; + ret = kthread_create("hyt271_thread", SCHED_PRIORITY_DEFAULT, + CONFIG_SENSORS_HYT271_THREAD_STACKSIZE, + hyt271_thread, argv); + if (ret > 0) +#endif + { + return OK; + } + +humi_err: + sensor_unregister(&priv->sensor[HYT271_SENSOR_HUMI].lower, devno); +temp_err: + sensor_unregister(&priv->sensor[HYT271_SENSOR_TEMP].lower, devno); + + nxsem_destroy(&priv->lock_measure_cylce); + kmm_free(priv); + return ret; +} +#endif /* CONFIG_I2C && CONFIG_SENSORS_HYT271 */ diff --git a/include/nuttx/sensors/hyt271.h b/include/nuttx/sensors/hyt271.h new file mode 100644 index 00000000000..5c05e697f0b --- /dev/null +++ b/include/nuttx/sensors/hyt271.h @@ -0,0 +1,110 @@ +/**************************************************************************** + * include/nuttx/sensors/hyt271.h + * Character driver for HYT271 Digital Humidity and Temperature Module. + * + * 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_HYT271_H +#define __INCLUDE_NUTTX_SENSORS_HYT271_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_HYT271) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* HYT271 I2C Commands */ + +#define HYT271_CMD_EEPROM_READ (0x1C) /* EEPROM Read Command */ +#define HYT271_CMD_EEPROM_WRITE (0x5C) /* EEPROM Write Command */ +#define HYT271_CMD_START_CM (0xA0) /* Start command mode */ +#define HYT271_CMD_START_NOM (0x80) /* End command mode */ + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct i2c_master_s; + +struct hyt271_bus_s +{ + /************************************************************************** + * Name: pwonreset + * + * Description: + * Callback to board specific logic for power on reset the I2C bus. + * The callback must ensure that the repowered bus is stable before + * returning. + * + * Parameter: + * bus - Instance to this + * + * Return: + * OK on success + **************************************************************************/ + + int (*pwonreset)(FAR struct hyt271_bus_s *bus); +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: hyt271_register + * + * Description: + * Register the HYT271 character device. + * + * Input Parameters: + * devno - The user specifies device number, from 0. + * i2c - An instance of the I2C interface to communicate with HYT271 + * sensor. + * + * addr - The I2C address of the HYT271. + * bus - Callback to board specific logic for i2c bus power. + * Will be used for changing i2c address of the sensor and can be + * set to NULL when not supported. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + ****************************************************************************/ + +int hyt271_register(int devno, FAR struct i2c_master_s *i2c, uint8_t addr, + FAR struct hyt271_bus_s *bus); +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* CONFIG_I2C && CONFIG_SENSORS_HYT271 */ +#endif /* __INCLUDE_NUTTX_SENSORS_HYT271_H */ diff --git a/include/nuttx/sensors/ioctl.h b/include/nuttx/sensors/ioctl.h index 49fae29806f..c8ad99b7aa1 100644 --- a/include/nuttx/sensors/ioctl.h +++ b/include/nuttx/sensors/ioctl.h @@ -223,6 +223,12 @@ #define SNIOC_SET_RESOLUTION _SNIOC(0x0065) /* Arg: uint8_t value */ #define SNIOC_SET_RANGE _SNIOC(0x0066) /* Arg: uint8_t value */ +/* IOCTL commands unique to the HYS271 */ + +/* SNIOC_CHANGEADDR */ /* Arg: uint8_t value */ + +#define SNIOC_READADDR SNIOC_READID /* Arg: uint8_t* pointer */ + /* Command: SNIOC_ACTIVATE * Description: Enable or disable sensor * Argument: true or false.