From 2a178beb0a0e5abed0defdda6b0f9ea552a77d94 Mon Sep 17 00:00:00 2001 From: Wonsang Ryou Date: Mon, 24 Jul 2017 15:14:34 +0900 Subject: [PATCH] drivers/sensors: s5j/ppd42ns: modify ppd42ns dust sensor driver This patch modifies ppd42ns driver according to Tizen RT device driver model. The previous ppd42ns driver has implemented according to common sensor API definition (os/include/tinyara/sensors/sensor.h). The common sensor API will be removed. The details are as follows. 1. remove common sensor API definition : os/include/tinyara/sensors/sensor.h 2. modify ppd42ns driver according to Tizen RT device driver model - implement open, close and read operations - implement board dependent functions as callback - implement the function for registering character driver : os/drivers/sensors/ppd42ns.c os/include/tinyara/sensors/ppd42ns.h 3. add Samsung S5JT200 code for implementing board dependent callback : os/arch/arm/src/s5j/s5j_ppd42ns.c os/arch/arm/src/s5j/s5j_ppd42ns.h 4. add sensor driver registering code on board initialization : os/arch/arm/src/artik053/src/artik053_boot.c, os/arch/arm/src/sidk_s5jt200/src/s5jt200_boot.c 5. modify ppd42ns example application using file operation : apps/examples/sensor_test/ppd42ns_test.c Change-Id: I14ae5e10a3624cf8bb7125137323fcc3bb6c50ca Signed-off-by: Wonsang Ryou --- apps/examples/sensor_test/Kconfig | 33 ++ apps/examples/sensor_test/ppd42ns_test.c | 178 ++++++ os/arch/arm/src/artik053/src/artik053_boot.c | 18 +- os/arch/arm/src/s5j/Kconfig | 4 + os/arch/arm/src/s5j/Make.defs | 4 + os/arch/arm/src/s5j/s5j_ppd42ns.c | 282 ++++++++++ os/arch/arm/src/s5j/s5j_ppd42ns.h | 104 ++++ os/arch/arm/src/sidk_s5jt200/src/s5jt200_boot.c | 16 + os/drivers/sensors/Kconfig | 13 +- os/drivers/sensors/ppd42ns.c | 702 +++++++++--------------- os/include/tinyara/sensors/ppd42ns.h | 52 +- os/include/tinyara/sensors/sensor.h | 431 --------------- 12 files changed, 929 insertions(+), 908 deletions(-) create mode 100644 apps/examples/sensor_test/Kconfig create mode 100644 apps/examples/sensor_test/ppd42ns_test.c create mode 100644 os/arch/arm/src/s5j/s5j_ppd42ns.c create mode 100644 os/arch/arm/src/s5j/s5j_ppd42ns.h delete mode 100644 os/include/tinyara/sensors/sensor.h diff --git a/apps/examples/sensor_test/Kconfig b/apps/examples/sensor_test/Kconfig new file mode 100644 index 0000000..9f4d5b1 --- /dev/null +++ b/apps/examples/sensor_test/Kconfig @@ -0,0 +1,33 @@ +# +# For a description of the syntax of this configuration file, +# see kconfig-language at https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt +# + +config EXAMPLES_SENSOR_TEST + bool "\"Sensor Test\" example" + default n + depends on SENSOR + ---help--- + Enable the \"Sensor Test\" example + + +if EXAMPLES_SENSOR_TEST +config EXAMPLES_SENSOR_TEST_PPD42NS + bool "PPD42NS Dust Sensor Example" + default n + ---help--- + Enable PPD42NS Dust Sensor Example Application + +config EXAMPLES_SENSOR_TEST_PPD42NS_MQTT_TRANSMISSION + bool "Support MQTT transmission for sending sensor data" + default n + depends on EXAMPLES_SENSOR_TEST_PPD42NS + depends on EXAMPLES_MQTT_TEST + ---help--- + Enable to dust send sensor data using MQTT transmission + +endif # EXAMPLES_SENSOR_TEST + +config USER_ENTRYPOINT + string + default "ppd42ns_test_main" if ENTRY_SENSOR_TEST diff --git a/apps/examples/sensor_test/ppd42ns_test.c b/apps/examples/sensor_test/ppd42ns_test.c new file mode 100644 index 0000000..d3065bd --- /dev/null +++ b/apps/examples/sensor_test/ppd42ns_test.c @@ -0,0 +1,178 @@ +/**************************************************************************** + * + * Copyright 2017 Samsung Electronics All Rights Reserved. + * + * Licensed 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. + * + ****************************************************************************/ +/** + * @file ppd42ns_test.c + * @brief the program for testing ppd42ns dust sensor + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include + +#define DUST_SENSOR_DEVNAME "/dev/dust0" + +#if defined(CONFIG_EXAMPLES_SENSOR_TEST_PPD42NS_MQTT_TRANSMISSION) +/************** + * Definitions + **************/ +#define MQTT_BROKER_IP_ADDRESS "192.168.1.14" +#define MQTT_BROKER_PORT "1883" +#define MQTT_TOPIC "/test/sensor" + +/************** + * Structure + **************/ +struct mqtt_pub_input { + int argc; + char **argv; +}; + +/************** + * Private Data + **************/ +char g_argv_buf[30][100]; +char *g_argv_cur[30]; + +/****************** + * function prototype + ******************/ +int mqtt_client_pub_task(void *arg); + +/****************** + * static function + ******************/ +static void create_arg(struct mqtt_pub_input *arg, char **argv_cur, char(*argv)[100], char *cmd) +{ + int i, len, idx1, idx2; + + len = (int)strlen(cmd); + idx1 = idx2 = 0; + for (i = 0; i < len; i++) { + if (cmd[i] == ' ') { + argv[idx1][idx2] = '\0'; + idx1++; + idx2 = 0; + i++; + } + argv[idx1][idx2++] = cmd[i]; + } + argv[idx1][idx2] = '\0'; + + arg->argc = idx1 + 1; + for (i = 0; i < arg->argc; i++) { + argv_cur[i] = argv[i]; + } + arg->argv = argv_cur; +} + +static int send_sensor_data(char *data) +{ + struct mqtt_pub_input arg; + char mqtt_str[128]; + + snprintf(mqtt_str, 128, "mqtt_pub -h %s -t %s -p %s -m %s", MQTT_BROKER_IP_ADDRESS, MQTT_TOPIC, MQTT_BROKER_PORT, data); + + create_arg(&arg, g_argv_cur, g_argv_buf, mqtt_str); + mqtt_client_pub_task(&arg); + + return 0; +} +#endif /* CONFIG_EXAMPLES_SENSOR_TEST_PPD42NS_MQTT_TRANSMISSION */ + +/**************************************************************************** + * main + ****************************************************************************/ + +#ifdef CONFIG_BUILD_KERNEL +int main(int argc, FAR char *argv[]) +#else +int ppd42ns_test_main(int argc, char *argv[]) +#endif +{ + int result = -1; + int fd = -1; + float sensor_data; + char msg[64]; + int sampling_interval_ms; + int test_cnt; + int loop_cnt; + + if (argc != 3) { + printf("USAGE: sensor_ppd42ns [sampling_interval_in_ms] [loop_count] \n"); + goto done; + } + + sampling_interval_ms = atoi(argv[1]); + test_cnt = atoi(argv[2]); + loop_cnt = test_cnt; + + /* open ppd42ns sensor driver */ + fd = open(DUST_SENSOR_DEVNAME, O_RDONLY); + if (fd < 0) { + printf("ERROR: open() failed. devname=%s\n", DUST_SENSOR_DEVNAME); + goto done; + } + + printf(">>> Start ppd42ns dust sensor test\n"); + printf(" - interval: %d ms\n", sampling_interval_ms); + printf(" - loop_count: %d\n", loop_cnt); + printf(" - mqtt transmission: "); +#if defined(CONFIG_EXAMPLES_SENSOR_TEST_PPD42NS_MQTT_TRANSMISSION) + printf("ON\n"); +#else + printf("OFF\n"); +#endif + + while (loop_cnt) { + usleep(sampling_interval_ms * 1000); + if (read(fd, (void *)&sensor_data, sizeof(float)) == sizeof(float)) { + /* make sensor data message with json style */ + snprintf(msg, sizeof(msg), "{\"dust\":%.2f}", sensor_data); + printf("[%d] %s \n", (test_cnt - loop_cnt + 1), msg); + +#if defined(CONFIG_EXAMPLES_SENSOR_TEST_PPD42NS_MQTT_TRANSMISSION) + send_sensor_data(msg); +#endif + } else { + printf("ERROR: read() failed. devname=%s, remaining loop_cnt=%d\n", DUST_SENSOR_DEVNAME, loop_cnt - 1); + } + + loop_cnt--; + } + printf("<<< End ppd42ns dust sensor test\n"); + + /* close ppd42ns sensor driver */ + if (fd != -1) { + close(fd); + fd = -1; + } + + result = 0; + +done: + return result; +} diff --git a/os/arch/arm/src/artik053/src/artik053_boot.c b/os/arch/arm/src/artik053/src/artik053_boot.c index 4f5901d..9ae76b6 100644 --- a/os/arch/arm/src/artik053/src/artik053_boot.c +++ b/os/arch/arm/src/artik053/src/artik053_boot.c @@ -64,6 +64,7 @@ #include #include "up_arch.h" #include "s5j_gpio.h" +#include "s5j_ppd42ns.h" /***************************************************************************** * Private Functions @@ -123,7 +124,7 @@ static void board_gpio_initialize(void) * Name: board_i2c_initialize * * Description: - * Expose board dependent I2Cs + * Expose board dependent I2Cs ****************************************************************************/ static void board_i2c_initialize(void) { @@ -133,6 +134,19 @@ static void board_i2c_initialize(void) #endif } +/**************************************************************************** + * Name: board_sensor_initialize + * + * Description: + * Expose board dependent Sensors + ****************************************************************************/ +static void board_sensor_initialize(void) +{ +#if defined(CONFIG_SENSOR_PPD42NS) && defined(CONFIG_S5J_SENSOR_PPD42NS) + s5j_ppd42ns_initialize(); +#endif +} + /***************************************************************************** * Public Functions ****************************************************************************/ @@ -215,7 +229,6 @@ void board_initialize(void) board_gpio_initialize(); board_i2c_initialize(); - #if defined(CONFIG_AUDIO_ALC5658) s5j_alc5658_initialize(0); #elif defined(CONFIG_AUDIO_ALC5658CHAR) @@ -224,5 +237,6 @@ void board_initialize(void) alc5658_i2c_initialize(); i2schar_devinit(); #endif + board_sensor_initialize(); } #endif /* CONFIG_BOARD_INITIALIZE */ diff --git a/os/arch/arm/src/s5j/Kconfig b/os/arch/arm/src/s5j/Kconfig index 9599aa2..ff1d47d 100644 --- a/os/arch/arm/src/s5j/Kconfig +++ b/os/arch/arm/src/s5j/Kconfig @@ -378,4 +378,8 @@ config S5J_PWR_SLEEP endmenu +config S5J_SENSOR_PPD42NS + bool "PPD42NS Dust Sensor" + default n + endmenu diff --git a/os/arch/arm/src/s5j/Make.defs b/os/arch/arm/src/s5j/Make.defs index 89299a4..541635d 100644 --- a/os/arch/arm/src/s5j/Make.defs +++ b/os/arch/arm/src/s5j/Make.defs @@ -187,3 +187,7 @@ CHIP_CSRCS += sss_driver_io.c # built-in static library EXTRA_LIBS += chip/sss/libispdriver.a endif + +ifeq ($(CONFIG_S5J_SENSOR_PPD42NS),y) +CHIP_CSRCS += s5j_ppd42ns.c +endif diff --git a/os/arch/arm/src/s5j/s5j_ppd42ns.c b/os/arch/arm/src/s5j/s5j_ppd42ns.c new file mode 100644 index 0000000..4944b2a --- /dev/null +++ b/os/arch/arm/src/s5j/s5j_ppd42ns.c @@ -0,0 +1,282 @@ +/**************************************************************************** + * + * Copyright 2017 Samsung Electronics All Rights Reserved. + * + * Licensed 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. + * + ****************************************************************************/ +/**************************************************************************** + * arch/arm/src/s5j/s5j_ppd42ns.c + * + * Copyright (C) 2009-2010, 2014-2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include "s5j_gpio.h" + +#ifdef CONFIG_SENSOR_PPD42NS + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +#define DEVNAME_FORMAT "/dev/dust%d" + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct s5j_gpio_info_s { + uint8_t pinnum; + uint16_t pincfg; +}; + +struct s5j_ppd42ns_priv_s { + uint32_t irqvector; + uint32_t pincfg; + int event_on_rising; + int event_on_falling; +}; + +struct s5j_ppd42ns_dev_s { + /* Configuration structure as seen by the ppd42ns driver */ + struct ppd42ns_config_s config; + + /* Additional private definitions only known to this driver */ + ppd42ns_handler_t handler; + FAR void *arg; +}; + +/**************************************************************************** + * Private Functions Prototype + ****************************************************************************/ +static int s5j_ppd42ns_gpio_read(struct ppd42ns_config_s *config); +static int s5j_ppd42ns_irq_attach(struct ppd42ns_config_s *config, ppd42ns_handler_t handler, FAR char *arg); +static int s5j_ppd42ns_irq_enable(struct ppd42ns_config_s *config, int enable); + +/**************************************************************************** + * Private Data + ****************************************************************************/ +static struct s5j_ppd42ns_dev_s g_s5j_dev = { + .config = { + .gpionum = CONFIG_SENSOR_PPD42NS_GPIO_NUM, + .read_gpio = s5j_ppd42ns_gpio_read, + .attach = s5j_ppd42ns_irq_attach, + .enable = s5j_ppd42ns_irq_enable, + .priv = NULL, + }, + + .handler = NULL +}; + +static struct s5j_gpio_info_s g_gpio_info[] = { + {57, GPIO_INPUT | GPIO_PULLDOWN | GPIO_PORTA0 | GPIO_PIN0}, /* XEINT0 */ + {58, GPIO_INPUT | GPIO_PULLDOWN | GPIO_PORTA0 | GPIO_PIN1}, /* XEINT1 */ + {59, GPIO_INPUT | GPIO_PULLDOWN | GPIO_PORTA0 | GPIO_PIN2}, /* XEINT2 */ +}; + +static struct s5j_ppd42ns_priv_s g_s5j_priv; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ +static int s5j_ppd42ns_gpio_read(struct ppd42ns_config_s *config) +{ + struct s5j_ppd42ns_dev_s *dev = (struct s5j_ppd42ns_dev_s *)config; + struct s5j_ppd42ns_priv_s *priv = dev ? (struct s5j_ppd42ns_priv_s *)dev->config.priv : NULL; + + if (priv == NULL) { + lldbg("ERROR: s5j_ppd42ns_gpio_read() is failed.\n"); + return -1; + } + + return s5j_gpioread(priv->pincfg) ? 1 : 0; +} + +static int s5j_ppd42ns_irq_handler(int irq, FAR void *context, FAR void *arg) +{ + struct s5j_ppd42ns_dev_s *dev = (struct s5j_ppd42ns_dev_s *)arg; + struct s5j_ppd42ns_priv_s *priv = dev ? (struct s5j_ppd42ns_priv_s *)dev->config.priv : NULL; + + if (priv == NULL) { + return -1; + } + + s5j_gpio_clear_pending(priv->pincfg); + + if (dev->handler) { + dev->handler(dev->arg); + } + + return 0; +} + +static int s5j_ppd42ns_irq_attach(struct ppd42ns_config_s *config, ppd42ns_handler_t handler, FAR char *arg) +{ + struct s5j_ppd42ns_dev_s *dev = (struct s5j_ppd42ns_dev_s *)config; + struct s5j_ppd42ns_priv_s *priv = dev ? (struct s5j_ppd42ns_priv_s *)dev->config.priv : NULL; + + if (priv == NULL) { + lldbg("ERROR: s5j_ppd42ns_irq_attach() is failed.\n"); + return -1; + } + + dev->handler = handler; + dev->arg = arg; + + return 0; +} + +static int s5j_ppd42ns_irq_enable(struct ppd42ns_config_s *config, int enable) +{ + int result = -1; + struct s5j_ppd42ns_dev_s *dev = (struct s5j_ppd42ns_dev_s *)config; + struct s5j_ppd42ns_priv_s *priv = dev ? (struct s5j_ppd42ns_priv_s *)dev->config.priv : NULL; + uint32_t pincfg; + irqstate_t flags; + + if (priv == NULL) { + lldbg("ERROR: s5j_ppd42ns_irq_enable() is failed.\n"); + return -1; + } + + /* disable interrupt */ + flags = irqsave(); + + pincfg = priv->pincfg; + pincfg &= ~GPIO_FUNC_MASK; + if (priv->event_on_rising && priv->event_on_falling) { + pincfg |= GPIO_EINT | GPIO_EINT_BOTH_EDGE; + } else if (priv->event_on_rising) { + pincfg |= GPIO_EINT | GPIO_EINT_RISING_EDGE; + } else if (priv->event_on_falling) { + pincfg |= GPIO_EINT | GPIO_EINT_FALLING_EDGE; + } + + if (enable) { + irq_attach(priv->irqvector, s5j_ppd42ns_irq_handler, dev); + up_enable_irq(priv->irqvector); + + } else { + up_disable_irq(priv->irqvector); + irq_detach(priv->irqvector); + } + + if (s5j_configgpio(pincfg) != 0) { + goto done; + } + + result = 0; + +done: + /* enable interrupt */ + irqrestore(flags); + + return result; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: s5j_ppd42ns_initialize + * + * Description: + * Initialize the ppd42ns dust sensor driver. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ +int s5j_ppd42ns_initialize(void) +{ + int result = -1; + int i; + int total_pins = sizeof(g_gpio_info) / sizeof(g_gpio_info[0]); + char devpath[32]; + + for (i = 0; i < total_pins; i++) { + if (g_gpio_info[i].pinnum == CONFIG_SENSOR_PPD42NS_GPIO_NUM) { + g_s5j_priv.pincfg = g_gpio_info[i].pincfg; + g_s5j_priv.irqvector = s5j_gpio_irqvector(g_s5j_priv.pincfg); + break; + } + } + if (i == total_pins) { + result = -EINVAL; + goto done; + } + /* set both edge */ + g_s5j_priv.event_on_rising = true; + g_s5j_priv.event_on_falling = true; + + /* set ppd42ns config */ + g_s5j_dev.config.priv = (void *)&g_s5j_priv; + + /* register ppd42ns driver */ + snprintf(devpath, sizeof(devpath), DEVNAME_FORMAT, 0); + if (ppd42ns_register(devpath, &g_s5j_dev.config) != 0) { + goto done; + } + + /* result is success */ + result = 0; + +done: + return result; +} + +#endif /* CONFIG_SENSOR_PPD42NS */ diff --git a/os/arch/arm/src/s5j/s5j_ppd42ns.h b/os/arch/arm/src/s5j/s5j_ppd42ns.h new file mode 100644 index 0000000..87889b6 --- /dev/null +++ b/os/arch/arm/src/s5j/s5j_ppd42ns.h @@ -0,0 +1,104 @@ +/**************************************************************************** + * + * Copyright 2017 Samsung Electronics All Rights Reserved. + * + * Licensed 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. + * + ****************************************************************************/ +/**************************************************************************** + * arch/arm/src/s5j/s5j_ppd42ns.h + * + * Copyright (C) 2009-2010, 2014-2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_S5J_S5J_PPD42NS_H +#define __ARCH_ARM_SRC_S5J_S5J_PPD42NS_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: s5j_ppd42ns_initialize + * + * Description: + * Initialize the ppd42ns dust sensor driver. + * + * Input Parameters: + * None + * + * Returned Value: + * Zero (OK) on success; a negated errno on failure + * + ****************************************************************************/ +int s5j_ppd42ns_initialize(void); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ARCH_ARM_SRC_S5J_S5J_PPD42NS_H */ diff --git a/os/arch/arm/src/sidk_s5jt200/src/s5jt200_boot.c b/os/arch/arm/src/sidk_s5jt200/src/s5jt200_boot.c index 799b7e4..a322c2d 100644 --- a/os/arch/arm/src/sidk_s5jt200/src/s5jt200_boot.c +++ b/os/arch/arm/src/sidk_s5jt200/src/s5jt200_boot.c @@ -71,6 +71,7 @@ #include "sidk_s5jt200.h" #include "s5j_gpio.h" +#include "s5j_ppd42ns.h" /**************************************************************************** * Pre-processor Definitions @@ -134,6 +135,19 @@ static void board_gpio_initialize(void) } /**************************************************************************** + * Name: board_sensor_initialize + * + * Description: + * initialize board dependent sensor driver code + ****************************************************************************/ +static void board_sensor_initialize(void) +{ +#if defined(CONFIG_SENSOR_PPD42NS) && defined(CONFIG_S5J_SENSOR_PPD42NS) + s5j_ppd42ns_initialize(); +#endif +} + +/**************************************************************************** * Public Functions ****************************************************************************/ @@ -224,5 +238,7 @@ void board_initialize(void) #ifdef CONFIG_SIDK_S5JT200_EEPROM sidk_s5jt200_eeprom_init(); #endif + + board_sensor_initialize(); } #endif /* CONFIG_BOARD_INITIALIZE */ diff --git a/os/drivers/sensors/Kconfig b/os/drivers/sensors/Kconfig index f033b12..b100785 100644 --- a/os/drivers/sensors/Kconfig +++ b/os/drivers/sensors/Kconfig @@ -3,10 +3,6 @@ # see kconfig-language at https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt # -comment "Sensor Drivers" - -if SENSOR - config SENSOR_PPD42NS bool "Shinyei PPD42NS Dust Sensor" default n @@ -21,7 +17,10 @@ config SENSOR_PPD42NS_GPIO_NUM ---help--- the pin number of GPIO that is connected to PPD42NS's Dust Signal Pin -endif # SENSOR_PPD42NS - -endif # SENSOR +config SENSOR_PPD42NS_DEBUG + bool "PPD42NS driver debug message" + default n + ---help--- + enable PPD42ns dust sensor driver's debug message +endif # SENSOR_PPD42NS diff --git a/os/drivers/sensors/ppd42ns.c b/os/drivers/sensors/ppd42ns.c index 52f0e6d..d68f542 100644 --- a/os/drivers/sensors/ppd42ns.c +++ b/os/drivers/sensors/ppd42ns.c @@ -21,567 +21,355 @@ ****************************************************************************/ #include #include -#include -#include -#include #include +#include #include -#include -#include -#include -#include + #include /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +#define PPD42NS_TIME_GET(time) gettimeofday(&time, NULL) +#define PPD42NS_TIME_DIFF_USEC(old_time, cur_time) \ + ((cur_time.tv_sec * 1000000 + cur_time.tv_usec) - (old_time.tv_sec * 1000000 + old_time.tv_usec)) + #define GPIO_SIGNAL_LOW 0 #define GPIO_SIGNAL_HIGH 1 /**************************************************************************** - * Structures + * Private Types ****************************************************************************/ -typedef struct { - int initialized; - int activated; - sem_t exclsem; - int fd; - char devpath[16]; - int old_signal; - int lowpulseoccupancy; - struct timeval start_time; - struct timeval lowpulse_start_time; - int pipe_evt_task[2]; - int evt_task_loop; -} ppd42ns_priv; +struct ppd42ns_dev_s { + FAR struct ppd42ns_config_s *config; /* ppd42ns driver config */ + int crefs; /* reference count on the driver instance */ + sem_t exclsem; /* exclusive access to the device */ + sem_t datasem; /* exclusive access while reading sensor data */ + int old_signal; /* previous gpio signal */ + int lowpulseoccupancy; /* low pulse signal time */ + struct timeval start_time; /* start time of total period */ + struct timeval lowpulse_start_time; /* start time of low pulse signal period */ +}; /**************************************************************************** - * Static Function Prototype + * Private Functions Prototype ****************************************************************************/ -static int ppd42ns_init(sensor_device_t *sensor); -static int ppd42ns_deinit(sensor_device_t *sensor); -static int ppd42ns_activate(sensor_device_t *sensor); -static int ppd42ns_deactivate(sensor_device_t *sensor); -static int ppd42ns_ioctl(sensor_device_t *sensor, int id, sensor_ioctl_value_t *val); -static int ppd42ns_get_data(sensor_device_t *sensor, sensor_data_t *data); +static int ppd42ns_open(FAR struct file *filep); +static int ppd42ns_close(FAR struct file *filep); +static ssize_t ppd42ns_read(FAR struct file *filep, FAR char *buffer, size_t len); /**************************************************************************** - * Variables + * Private Data ****************************************************************************/ -static sensor_operations_t g_ops = { - .init = ppd42ns_init, - .deinit = ppd42ns_deinit, - .activate = ppd42ns_activate, - .deactivate = ppd42ns_deactivate, - .ioctl = ppd42ns_ioctl, - .set_trigger = NULL, - .get_data = ppd42ns_get_data, -}; -static ppd42ns_priv g_priv; +/* ppd42ns driver instance */ +static FAR struct ppd42ns_dev_s g_ppd42ns_priv; + +/* This the vtable that supports the character driver interface */ +static const struct file_operations g_ppd42ns_fops = { + ppd42ns_open, /* open */ + ppd42ns_close, /* close */ + ppd42ns_read, /* read */ + 0, /* write */ + 0, /* seek */ + 0, /* ioctl */ +}; /**************************************************************************** - * Static Function + * Private Function ****************************************************************************/ -static void ppd42ns_event_handler(sensor_device_t *sensor) +/**************************************************************************** + * Name: ppd42ns_takesem + * + * Description: + * Take the lock, waiting as necessary + * + ****************************************************************************/ +static inline int ppd42ns_takesem(FAR sem_t *sem) { - /* this is both edge interrupt handler on ppd42ns's digital signal pin */ - - struct timeval time; - ppd42ns_priv *priv; - - if (sensor && sensor->priv) { - priv = (ppd42ns_priv *) sensor->priv; - } else { - return; + /* Take a count from the semaphore, possibly waiting */ + if (sem_wait(sem) < 0) { + /* EINTR is the only error that we expect */ + int errcode = get_errno(); + DEBUGASSERT(errcode == EINTR); + return errcode; } - if (priv->old_signal == GPIO_SIGNAL_LOW) { - /* signal LOW -> HIGH */ - SENSOR_TIME_GET(time); - priv->lowpulseoccupancy += SENSOR_TIME_DIFF_USEC(priv->lowpulse_start_time, time); - priv->old_signal = GPIO_SIGNAL_HIGH; -#if PPD42NS_DEBUG_ON - SENSOR_DEBUG("LOW -> HIGH : tv_sec=%d, tv_usec=%d, lowpulse_time=%d\n", time.tv_sec, time.tv_usec, SENSOR_TIME_DIFF_USEC(priv->lowpulse_start_time, time)); -#endif - } else { - /* signal HIGH -> LOW */ - SENSOR_TIME_GET(priv->lowpulse_start_time); - priv->old_signal = GPIO_SIGNAL_LOW; -#if PPD42NS_DEBUG_ON - SENSOR_DEBUG("HIGH -> LOW : tv_sec=%d, tv_usec=%d\n", priv->lowpulse_start_time.tv_sec, priv->lowpulse_start_time.tv_usec); -#endif - } + return 0; } -static void ppd42ns_event_task(sensor_device_t *sensor) +/**************************************************************************** + * Name: ppd42ns_givesem + * + * Description: + * release the lock + * + ****************************************************************************/ +static inline void ppd42ns_givesem(sem_t *sem) { - int ret; - ppd42ns_priv *priv; - struct pollfd fds[2]; - int size; - int timeout; - -#if PPD42NS_DEBUG_ON - SENSOR_DEBUG("start event task \n"); -#endif - - if (sensor && sensor->priv) { - priv = (ppd42ns_priv *) sensor->priv; - } else { - SENSOR_DEBUG("ERROR: %s is NULL.\n", sensor == NULL ? "sensor" : "sensor->priv"); - return; - } - - /* initializes pollfd */ - memset(fds, 0, sizeof(fds)); - fds[0].fd = priv->pipe_evt_task[1]; - fds[0].events = POLLIN; - fds[1].fd = priv->fd; - fds[1].events = POLLIN; - - timeout = 1000; - size = sizeof(fds) / sizeof(struct pollfd); - priv->evt_task_loop = 1; - while (priv->evt_task_loop) { - ret = poll(fds, size, timeout); - if (ret < 0) { - SENSOR_DEBUG("ERROR: %s is NULL.\n"); - return; - } else if (ret == 0) { - /* poll timeout */ - continue; - } - - /* stop message via pipe */ - if (fds[0].revents & POLLIN) { -#if PPD42NS_DEBUG_ON - SENSOR_DEBUG("received stop message via pipe.\n"); -#endif - priv->evt_task_loop = 0; - break; - } - - /* gpio interrupt */ - if (fds[1].revents & POLLIN) { -#if PPD42NS_DEBUG_ON - SENSOR_DEBUG("gpio interrupt occurred.\n"); -#endif - ppd42ns_event_handler(sensor); - } - } - -#if PPD42NS_DEBUG_ON - SENSOR_DEBUG("stop event task \n"); -#endif + sem_post(sem); } -static int ppd42ns_event_task_start(sensor_device_t *sensor) +/**************************************************************************** + * Name: ppd42ns_interrupt_handler + * + * Description: + * handle ppd42ns's digital pin interrupt + * + ****************************************************************************/ +static void ppd42ns_interrupt_handler(FAR void *arg) { - int result = -1; - int ret; - pthread_t tid; - ppd42ns_priv *priv; - - if (sensor && sensor->priv) { - priv = (ppd42ns_priv *) sensor->priv; - } else { - SENSOR_DEBUG("ERROR: %s is NULL.\n", sensor == NULL ? "sensor" : "sensor->priv"); - return -1; - } - - /* create pipe which is connected to event task */ - priv->pipe_evt_task[0] = -1; - priv->pipe_evt_task[1] = -1; - ret = pipe(priv->pipe_evt_task); - if (ret == -1) { - SENSOR_DEBUG("ERROR: pipe() failed.\n"); - goto done; - } + /* this is both edge interrupt handler on ppd42ns's digital signal pin */ + FAR struct ppd42ns_dev_s *priv = (FAR struct ppd42ns_dev_s *)arg; + struct timeval time; + irqstate_t flags; - /* create event task */ - ret = pthread_create(&tid, NULL, (pthread_startroutine_t) ppd42ns_event_task, (void *)sensor); - if (ret != 0) { - SENSOR_DEBUG("ERROR: pthread_create() failed. (ret=%d)\n", ret); - goto done; - } - ret = pthread_detach(tid); - if (ret != 0) { - SENSOR_DEBUG("ERROR: pthread_detach() failed. (ret=%d)\n", ret); + if (priv == NULL) { + return; } - /* result is success */ - result = 0; - -done: - if (result != 0) { - if (priv->pipe_evt_task[0] != -1) { - close(priv->pipe_evt_task[0]); - priv->pipe_evt_task[0] = -1; - } - - if (priv->pipe_evt_task[1] != -1) { - close(priv->pipe_evt_task[1]); - priv->pipe_evt_task[1] = -1; - } - - SENSOR_DEBUG("ERROR: fail to start event task\n"); + /* This ISR handles only when gpio signal is changed. */ + if (priv->config->read_gpio(priv->config) == priv->old_signal) { + return; } - return result; - -} + /* disable interrupt */ + flags = irqsave(); -static int ppd42ns_event_task_stop(sensor_device_t *sensor) -{ - ppd42ns_priv *priv; - - if (sensor && sensor->priv) { - priv = (ppd42ns_priv *) sensor->priv; + if (priv->old_signal == GPIO_SIGNAL_LOW) { + /* signal LOW -> HIGH */ + PPD42NS_TIME_GET(time); + priv->lowpulseoccupancy += PPD42NS_TIME_DIFF_USEC(priv->lowpulse_start_time, time); + priv->old_signal = GPIO_SIGNAL_HIGH; } else { - SENSOR_DEBUG("ERROR: %s is NULL.\n", sensor == NULL ? "sensor" : "sensor->priv"); - return -1; - } - - if (priv->evt_task_loop) { - if (write(priv->pipe_evt_task[1], "#", 1) < 0) { - SENSOR_DEBUG("ERROR: pipe write() failed. (errno=%d)\n", errno); - } - - while (priv->evt_task_loop) { - usleep(100 * 1000); - } - } - - if (priv->pipe_evt_task[0] != -1) { - close(priv->pipe_evt_task[0]); - priv->pipe_evt_task[0] = -1; - } - - if (priv->pipe_evt_task[1] != -1) { - close(priv->pipe_evt_task[1]); - priv->pipe_evt_task[1] = -1; - } - - return 0; -} - -static int ppd42ns_init(sensor_device_t *sensor) -{ - int result = -1; - ppd42ns_priv *priv; - - if (sensor == NULL || sensor->priv == NULL) { - SENSOR_DEBUG("ERROR: %s is NULL.\n", sensor == NULL ? "sensor" : "sensor->priv"); - goto done; - } - priv = sensor->priv; - - if (priv->initialized) { - SENSOR_DEBUG("ERROR: ppd42ns driver has already been initialized.\n"); - goto done; - } - - /* set gpio device */ - snprintf(priv->devpath, 16, "/dev/gpio%d", CONFIG_SENSOR_PPD42NS_GPIO_NUM); - - /* init semaphore */ - sem_init(&priv->exclsem, 0, 1); - - /* init private variables */ - priv->activated = 0; - priv->evt_task_loop = 0; - priv->pipe_evt_task[0] = -1; - priv->pipe_evt_task[1] = -1; - - /* initialized flag is set */ - priv->initialized = 1; - - /* result is success */ - result = 0; - -done: - return result; -} - -static int ppd42ns_deinit(sensor_device_t *sensor) -{ - int result = -1; - ppd42ns_priv *priv; - - if (sensor == NULL || sensor->priv == NULL) { - SENSOR_DEBUG("ERROR: %s is NULL.\n", sensor == NULL ? "sensor" : "sensor->priv"); - goto done; - } - priv = sensor->priv; - - /* deactivate if activated currently */ - if (priv->activated) { - ppd42ns_deactivate(sensor); + /* signal HIGH -> LOW */ + PPD42NS_TIME_GET(priv->lowpulse_start_time); + priv->old_signal = GPIO_SIGNAL_LOW; } - /* deinit semaphore */ - sem_destroy(&priv->exclsem); - - /* clear priv data */ - memset(priv, 0, sizeof(*priv)); - - /* result is success */ - result = 0; - -done: - return result; + /* enable interrupt */ + irqrestore(flags); } -static int ppd42ns_activate(sensor_device_t *sensor) +/**************************************************************************** + * Name: ppd42ns_open + * + * Description: + * Standard character driver open method. + * + ****************************************************************************/ +static int ppd42ns_open(FAR struct file *filep) { - int result = -1; int ret; - int signal; - ppd42ns_priv *priv; - struct gpio_pollevents_s pollevents; + FAR struct inode *inode = filep->f_inode; + FAR struct ppd42ns_dev_s *priv = inode->i_private; - if (sensor == NULL || sensor->priv == NULL) { - SENSOR_DEBUG("ERROR: %s is NULL.\n", sensor == NULL ? "sensor" : "sensor->priv"); - goto done_without_sem; - } - - if (sensor == NULL || sensor->priv == NULL) { - SENSOR_DEBUG("ERROR: %s is NULL.\n", sensor == NULL ? "sensor" : "sensor->priv"); - goto done_without_sem; - } - priv = sensor->priv; - - if (priv->activated) { - SENSOR_DEBUG("ERROR: ppd42ns driver has already been activated.\n"); - goto done_without_sem; + ret = ppd42ns_takesem(&priv->exclsem); + if (ret < 0) { + /* + * A signal received while waiting for the last close + * operation. + */ + lldbg("ERROR: ppd42ns_takesem() failed: %d\n", ret); + return ret; } - do { - ret = sem_wait(&priv->exclsem); - } while (ret != 0 && errno == EINTR); - - if (ret != 0) { - SENSOR_DEBUG("ERROR: sem_wait() failed.\n"); - goto done_without_sem; + /* ppd42ns driver allows only 1 instance */ + if (priv->crefs > 0) { + lldbg("ERROR: ppd42ns driver is already opened.\n"); + goto errout_with_sem; } - /* open gpio pin */ - priv->fd = open(priv->devpath, O_RDWR); - if (priv->fd < 0) { - SENSOR_DEBUG("ERROR: open() failed. (dev: %s)\n", priv->devpath); - goto done; - } + /* set reference count */ + priv->crefs = 1; - /* set gpio direction */ - ret = ioctl(priv->fd, GPIOIOC_SET_DIRECTION, GPIO_DIRECTION_IN); + /* enable the gpio pin interrupt */ + ret = priv->config->enable(priv->config, 1); if (ret < 0) { - SENSOR_DEBUG("ERROR: ioctl() failed. (dev: %s, ioctl_id: %d, errno: %d)\n", priv->devpath, GPIOIOC_SET_DIRECTION, errno); - goto done; + lldbg("ERROR: failed to enable the interrupt handler. (ret=%d)\n", ret); + goto errout_with_sem; } /* set start time */ - SENSOR_TIME_GET(priv->start_time); + PPD42NS_TIME_GET(priv->start_time); + priv->lowpulse_start_time = priv->start_time; /* get initial signal */ - ret = read(priv->fd, (void *)&signal, sizeof(int)); - if (ret < 0) { - SENSOR_DEBUG("ERROR: read() failed. (fd: %d, errno: %d)\n", priv->fd, errno); - goto done; - } + priv->old_signal = priv->config->read_gpio(priv->config); - if (signal == GPIO_SIGNAL_LOW) { - SENSOR_TIME_GET(priv->lowpulse_start_time); - } + /* initialize lowpulseoccupancy */ priv->lowpulseoccupancy = 0; - priv->old_signal = signal; - /* set interrupt on both edge and poll event */ - pollevents.gp_rising = true; - pollevents.gp_falling = true; - ret = ioctl(priv->fd, GPIOIOC_POLLEVENTS, (unsigned long)&pollevents); - if (ret < 0) { - SENSOR_DEBUG("ERROR: ioctl() failed. (dev: %s, ioctl_id: %d, errno: %d)\n", priv->devpath, GPIOIOC_POLLEVENTS, errno); - goto done; - } + ret = 0; - if (ppd42ns_event_task_start(sensor) != 0) { - SENSOR_DEBUG("ERROR: ppd42ns_event_task_start() failed. (dev: %s)\n", priv->devpath); - goto done; - } - - /* activated flag is set */ - priv->activated = 1; - - /* result is success */ - result = 0; - -done: - sem_post(&priv->exclsem); - -done_without_sem: - return result; -} - -static int ppd42ns_deactivate(sensor_device_t *sensor) -{ - int result = -1; - int ret; - ppd42ns_priv *priv; - - if (sensor == NULL || sensor->priv == NULL) { - SENSOR_DEBUG("ERROR: %s is NULL.\n", sensor == NULL ? "sensor" : "sensor->priv"); - goto done_without_sem; - } - priv = sensor->priv; - - do { - ret = sem_wait(&priv->exclsem); - } while (ret != 0 && errno == EINTR); - - if (ret != 0) { - SENSOR_DEBUG("ERROR: sem_wait() failed.\n"); - goto done_without_sem; - } - - ppd42ns_event_task_stop(sensor); - - /* close gpio */ - close(priv->fd); - - /* activated flag is unset */ - priv->activated = 0; - - /* result is success */ - result = 0; - - sem_post(&priv->exclsem); - -done_without_sem: - return result; +errout_with_sem: + ppd42ns_givesem(&priv->exclsem); + return ret; } -static int ppd42ns_ioctl(sensor_device_t *sensor, int id, sensor_ioctl_value_t *val) +/**************************************************************************** + * Name: ppd42ns_close + * + * Description: + * Standard character driver close method. + * + ****************************************************************************/ +static int ppd42ns_close(FAR struct file *filep) { - int result = -1; int ret; - ppd42ns_priv *priv; + FAR struct inode *inode = filep->f_inode; + FAR struct ppd42ns_dev_s *priv = inode->i_private; - if (sensor == NULL || sensor->priv == NULL) { - SENSOR_DEBUG("ERROR: %s is NULL.\n", sensor == NULL ? "sensor" : "sensor->priv"); - goto done_without_sem; - } - priv = sensor->priv; - - if (!priv->initialized) { - SENSOR_DEBUG("ERROR: ppd42ns driver is not initialized.\n"); - goto done_without_sem; + /* Get exclusive access to the driver structure */ + ret = ppd42ns_takesem(&priv->exclsem); + if (ret < 0) { + lldbg("ERROR: ppd42ns_takesem() failed: %d\n", ret); + return ret; } - if (val == NULL) { - SENSOR_DEBUG("ERROR: ioctl val is null.\n"); - goto done_without_sem; + if (priv->crefs == 0) { + lldbg("ERROR: ppd42ns driver is already closed.\n"); + goto errout_with_sem; } - do { - ret = sem_wait(&priv->exclsem); - } while (ret != 0 && errno == EINTR); - - if (ret != 0) { - SENSOR_DEBUG("ERROR: sem_wait() failed.\n"); - goto done_without_sem; - } + priv->crefs = 0; - switch (id) { - case PPD42NS_IOCTL_ID_GET_GPIO_DEVPATH: - val->p_str = priv->devpath; - break; - default: - SENSOR_DEBUG("ERROR: unknown ioctl id. (id: %d)\n", id); - goto done; + /* disable the gpio pin interrupt */ + ret = priv->config->enable(priv->config, 0); + if (ret < 0) { + lldbg("ERROR: failed to disable the interrupt handler. (ret=%d)\n", ret); + goto errout_with_sem; } - /* result is success */ - result = 0; - -done: - sem_post(&priv->exclsem); + ret = 0; -done_without_sem: - return result; +errout_with_sem: + ppd42ns_givesem(&priv->exclsem); + return ret; } -static int ppd42ns_get_data(sensor_device_t *sensor, sensor_data_t *data) +/**************************************************************************** + * Name: ppd42ns_read + * + * Description: + * Standard character driver read method. + * + ****************************************************************************/ +static ssize_t ppd42ns_read(FAR struct file *filep, FAR char *buffer, size_t len) { - int result = -1; + int ret; + FAR struct inode *inode = filep->f_inode; + FAR struct ppd42ns_dev_s *priv = inode->i_private; + int signal; float ratio = 0.0; float concentration; struct timeval time; - int ret; - int signal; - ppd42ns_priv *priv; - - if (sensor == NULL || sensor->priv == NULL) { - SENSOR_DEBUG("ERROR: %s is NULL.\n", sensor == NULL ? "sensor" : "sensor->priv"); - goto done_without_sem; - } - priv = sensor->priv; - if (!priv->activated) { - SENSOR_DEBUG("ERROR: ppd42ns driver is not activated.\n"); - goto done_without_sem; + ret = ppd42ns_takesem(&priv->datasem); + if (ret < 0) { + lldbg("ERROR: ppd42ns_takesem() failed: %d\n", ret); + return ret; } - do { - ret = sem_wait(&priv->exclsem); - } while (ret != 0 && errno == EINTR); - - if (ret != 0) { - SENSOR_DEBUG("ERROR: sem_wait() failed.\n"); - goto done_without_sem; - } + /* disable gpio pin interrupt */ + priv->config->enable(priv->config, 0); - lseek(priv->fd, 0, SEEK_SET); - ret = read(priv->fd, (void *)&signal, sizeof(int)); - if (ret < 0) { - SENSOR_DEBUG("ERROR: read() failed. (fd: %d, errno: %d)\n", priv->fd, errno); - goto done; - } + /* get gpio signal */ + signal = priv->config->read_gpio(priv->config); - SENSOR_TIME_GET(time); + PPD42NS_TIME_GET(time); if (signal == GPIO_SIGNAL_LOW) { - priv->lowpulseoccupancy += SENSOR_TIME_DIFF_USEC(priv->lowpulse_start_time, time); + priv->lowpulseoccupancy += PPD42NS_TIME_DIFF_USEC(priv->lowpulse_start_time, time); priv->lowpulse_start_time = time; } if (priv->lowpulseoccupancy != 0) { - ratio = (float)priv->lowpulseoccupancy / (float)SENSOR_TIME_DIFF_USEC(priv->start_time, time) * 100.0; /* Integer percentage 0=>100 */ + ratio = (float)priv->lowpulseoccupancy / (float)PPD42NS_TIME_DIFF_USEC(priv->start_time, time) * 100.0; /* percentage 0~100 */ concentration = 1.1 * pow(ratio, 3) - 3.8 * pow(ratio, 2) + 520 * ratio + 0.62; /* using spec sheet curve */ } else { concentration = 0.0; } - data->fval = concentration; -#if PPD42NS_DEBUG_ON - SENSOR_DEBUG("lowpulse_time=%d, total_time=%d, ratio=%.2f \n", priv->lowpulseoccupancy, SENSOR_TIME_DIFF_USEC(priv->start_time, time), ratio); +#ifdef CONFIG_SENSOR_PPD42NS_DEBUG + lldbg("lowpulse_time=%d, total_time=%d, ratio=%.2f, concentration=%.2f \n", priv->lowpulseoccupancy, PPD42NS_TIME_DIFF_USEC(priv->start_time, time), ratio, concentration); #endif priv->start_time = time; priv->lowpulseoccupancy = 0; priv->old_signal = signal; - /* result is success */ - result = 0; + /* enable gpio pin interrupt */ + priv->config->enable(priv->config, 1); -done: - sem_post(&priv->exclsem); + memcpy(buffer, &concentration, sizeof(float)); -done_without_sem: - return result; + ppd42ns_givesem(&priv->datasem); + + return sizeof(float); } /**************************************************************************** - * Create Sensor Instance + * Public Function + ****************************************************************************/ + +/**************************************************************************** + * Name: ppd42ns_register + * + * Description: + * This function will register ppd42ns dust sensor driver as /dev/dustN where N + * is the minor device number + * + * Input Parameters: + * devname - The full path to the driver to register. E.g., "/dev/dust0" + * config - configuration for the ppd42ns driver. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * ****************************************************************************/ -SENSOR_CREATE_INSTANCE(SENSOR_NAME_PPD42NS, SENSOR_DEVICE_TYPE_DUST, &g_ops, &g_priv); +int ppd42ns_register(FAR const char *devname, FAR struct ppd42ns_config_s *config) +{ + int ret; + struct ppd42ns_dev_s *priv = &g_ppd42ns_priv; + + /* validate ppd42ns config */ + if (config == NULL || config->read_gpio == NULL || config->attach == NULL || config->enable == NULL) { + ret = EINVAL; + lldbg("ERROR: invalid ppd42ns config\n"); + return ret; + } + + /* set ppd42ns config */ + priv->config = config; + + /* reference count is set to 0 */ + priv->crefs = 0; + + /* init semaphore */ + sem_init(&priv->exclsem, 0, 1); + sem_init(&priv->datasem, 0, 1); + + /* attach the interrupt handler */ + ret = priv->config->attach(priv->config, ppd42ns_interrupt_handler, (FAR void *)priv); + if (ret < 0) { + lldbg("ERROR: failed to attach the interrupt handler. (ret=%d)\n", ret); + sem_destroy(&priv->exclsem); + sem_destroy(&priv->datasem); + return ret; + } + + /* register the character device driver */ + ret = register_driver(devname, &g_ppd42ns_fops, 0666, priv); + if (ret < 0) { + lldbg("ERROR: failed to register driver %s. (ret=%d)\n", devname, ret); + sem_destroy(&priv->exclsem); + sem_destroy(&priv->datasem); + return ret; + } + + lldbg("Registered %s\n", devname); + + return 0; +} diff --git a/os/include/tinyara/sensors/ppd42ns.h b/os/include/tinyara/sensors/ppd42ns.h index 1616b13..fc0aa5f 100644 --- a/os/include/tinyara/sensors/ppd42ns.h +++ b/os/include/tinyara/sensors/ppd42ns.h @@ -22,19 +22,49 @@ /**************************************************************************** * Included Files ****************************************************************************/ -#include -#define SENSOR_NAME_PPD42NS ppd42ns -SENSOR_EXTERNAL_FUNCTION_PROTOTYPE(SENSOR_NAME_PPD42NS); +/**************************************************************************** + * Public Types + ****************************************************************************/ +typedef void (*ppd42ns_handler_t)(FAR void *arg); + +struct ppd42ns_config_s { + /* gpio pin number */ + int gpionum; + + /* callback function: read gpio pin signal */ + int (*read_gpio)(struct ppd42ns_config_s *config); -/******************** - definitions - ********************/ -#define PPD42NS_DEBUG_ON 0 + /* callback function: attach the ppd42ns interrupt handler to the GPIO interrupt */ + int (*attach)(struct ppd42ns_config_s *config, ppd42ns_handler_t handler, FAR char *arg); -/******************** - custom ioctl id - ********************/ -#define PPD42NS_IOCTL_ID_GET_GPIO_DEVPATH (SENSOR_IOCTL_ID_CUSTOM + 0) + /* callback function: enable or disable gpio pin interrupt */ + int (*enable)(struct ppd42ns_config_s *config, int enable); + + /* board specific data */ + void *priv; +}; + +/**************************************************************************** + * Public Function + ****************************************************************************/ + +/**************************************************************************** + * Name: ppd42ns_register + * + * Description: + * This function will register ppd42ns dust sensor driver as /dev/dustN where N + * is the minor device number + * + * Input Parameters: + * devname - The full path to the driver to register. E.g., "/dev/dust0" + * config - configuration for the ppd42ns driver. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ +int ppd42ns_register(FAR const char *devname, FAR struct ppd42ns_config_s *config); #endif /* __PPD42NS_H__ */ diff --git a/os/include/tinyara/sensors/sensor.h b/os/include/tinyara/sensors/sensor.h deleted file mode 100644 index d4cc509..0000000 --- a/os/include/tinyara/sensors/sensor.h +++ /dev/null @@ -1,431 +0,0 @@ -/**************************************************************************** - * - * Copyright 2017 Samsung Electronics All Rights Reserved. - * - * Licensed 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. - * - ****************************************************************************/ -/** - * @file sensor.h - * @brief Sensor API definition - * @version 0.3 - */ - -#ifndef __SENSOR_H__ -#define __SENSOR_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -/**************************************************************************** - * Public Types - ****************************************************************************/ -/** - * @brief Enumeration of sensor device type - */ -typedef enum { - SENSOR_DEVICE_TYPE_ACCELEROMETER, - SENSOR_DEVICE_TYPE_GYROSCOPE, - SENSOR_DEVICE_TYPE_MAGNETIC_FIELD, - SENSOR_DEVICE_TYPE_TEMPERATURE, - SENSOR_DEVICE_TYPE_HUMIDITY, - SENSOR_DEVICE_TYPE_PRESSURE, - SENSOR_DEVICE_TYPE_LIGHT, - SENSOR_DEVICE_TYPE_DUST, - SENSOR_DEVICE_TYPE_END -} -sensor_device_type_e; - -/** - * @brief Enumeration of sensor device attribute - */ -typedef enum { - SENSOR_IOCTL_ID_GET_TRIGGER_TYPE, - SENSOR_IOCTL_ID_FREQUENCY, - SENSOR_IOCTL_ID_CUSTOM = 0x8000, -} sensor_ioctl_id_e; - -/** - * @brief Enumeration of sensor trigger type - */ -typedef enum { - SENSOR_TRIGGER_TYPE_DATA_READY, - SENSOR_TRIGGER_TYPE_TIMER, - SENSOR_TRIGGER_TYPE_END -} sensor_trigger_type_e; - -/** - * @brief Structure of sensor value - */ -typedef struct { - union { - int ival; - float fval; - double dval; - char *p_str; - void *p; - }; -} sensor_ioctl_value_t; - -/** - * @brief Structure of sensor data - */ -typedef struct { - union { - float v[3]; - struct { - float x; - float y; - float z; - }; - struct { - float azimuth; - float pitch; - float roll; - }; - int ival; - float fval; - double dval; - }; -} sensor_data_t; - -/** - * @brief Structure of sensor trigger information - */ -typedef struct { - sensor_trigger_type_e type; -} sensor_trigger_info_t; - -/** - * @brief Definition of sensor_device_t type - */ -typedef struct sensor_device_t sensor_device_t; - -/** - * @brief Pointer definition to trigger callback function - */ -typedef int (*sensor_trigger_callback_t)(sensor_device_t *sensor, sensor_data_t *data); - -/** - * @brief Pointer definition to sensor operations - */ -typedef int (*sensor_init_t)(sensor_device_t *sensor); -typedef int (*sensor_deinit_t)(sensor_device_t *sensor); -typedef int (*sensor_activate_t)(sensor_device_t *sensor); -typedef int (*sensor_deactivate_t)(sensor_device_t *sensor); -typedef int (*sensor_ioctl_t)(sensor_device_t *sensor, int id, sensor_ioctl_value_t *val); -typedef int (*sensor_set_trigger_t)(sensor_device_t *sensor, sensor_trigger_info_t info, sensor_trigger_callback_t callback); -typedef int (*sensor_get_data_t)(sensor_device_t *sensor, sensor_data_t *data); - -/** - * @brief Structure of sensor operations - */ -typedef struct { - sensor_init_t init; /* initialize sensor device */ - sensor_deinit_t deinit; /* deinitialize sensor device */ - sensor_activate_t activate; /* activate sensor device */ - sensor_deactivate_t deactivate; /* deactivate sensor device */ - sensor_ioctl_t ioctl; /* ioctl on sensor device */ - sensor_set_trigger_t set_trigger; /* set trigger information and calback function */ - sensor_get_data_t get_data; /* get sensor data from device */ -} sensor_operations_t; - -/** - * @brief Structure of sensor device - */ -struct sensor_device_t { - sensor_device_type_e type; /* sensor device type */ - sensor_operations_t *ops; /* sensor opertaions */ - void *priv; /* private data of a specified device */ -}; - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -#define __NAME_STRING(name) #name -#define __SENSOR_CREATE_INSTANCE(name, _type, _ops, _priv) \ - static sensor_device_t g_sensor_##name = { \ - .type = _type, \ - .ops = _ops, \ - .priv = _priv, \ - }; \ - \ - sensor_device_t * name##_get_handle(void) { \ - return &g_sensor_##name; \ - }; \ - \ - sensor_operations_t * name##_get_ops_handle(void) { \ - return (&g_sensor_##name)->ops ? (&g_sensor_##name)->ops : NULL; \ - } - -#define __SENSOR_EXTERNAL_FUNCTION_PROTOTYPE(name) \ - sensor_device_t * name##_get_handle(void); \ - sensor_operations_t * name##_get_ops_handle(void) - -#define __SENSOR_GET_HANDLE(name) name##_get_handle() -#define __SENSOR_GET_OPS_HANDLE(name) name##_get_ops_handle() -#define __SENSOR_GET_NAME_STRING(name) __NAME_STRING(name) - -/*************************** - For Debug - ***************************/ -#define SENSOR_DEBUG_ON 1 -#if SENSOR_DEBUG_ON -#define SENSOR_DEBUG(format, ...) dbg(format, ##__VA_ARGS__) -#else -#define SENSOR_DEBUG(x...) (void)0 -#endif - -/*************************** - For Sensor Driver Developers - ***************************/ - -/**************************************************************************** - * Name: SENSOR_CREATE_INSTANCE - * - * Description: - * create a sensor device instance as sensor_device_t. - * - * Parameters: - * name - sensor device name. - * generally, SENSOR_NAME_XXXXX will be a name. it is in the specified sensor driver's header file. - * _type - sensor device type as sensor_device_type_e type. - * _ops - sensor operations handle as sensor_operations_t type. - * _priv - sensor device's private data handle as void type. - * - * Returned Value: - * none. - * - ****************************************************************************/ -#define SENSOR_CREATE_INSTANCE(name, _type, _ops, _priv) __SENSOR_CREATE_INSTANCE(name, _type, _ops, _priv) - -/**************************************************************************** - * Name: SENSOR_GET_NAME_STRING - * - * Description: - * declare external function prototype. - * - * Parameters: - * name - sensor device name. - * generally, SENSOR_NAME_XXXXX will be a name. it is in the specified sensor driver's header file. - * - * Returned Value: - * none. - * - ****************************************************************************/ -#define SENSOR_EXTERNAL_FUNCTION_PROTOTYPE(name) __SENSOR_EXTERNAL_FUNCTION_PROTOTYPE(name) - -/*************************** - For Upper Layer Developers - ***************************/ - -/**************************************************************************** - * Name: SENSOR_GET_NAME_STRING - * - * Description: - * get a name as string type. - * - * Parameters: - * name - sensor device name. - * generally, SENSOR_NAME_XXXXX will be a name. it is in the specified sensor driver's header file. - * - * Returned Value: - * a name as string type is returned. - * - ****************************************************************************/ -#define SENSOR_GET_NAME_STRING(name) __SENSOR_GET_NAME_STRING(name) - -/**************************************************************************** - * Name: SENSOR_GET_HANDLE - * - * Description: - * get a sensor device handle. - * - * Parameters: - * name - sensor device name. - * generally, SENSOR_NAME_XXXXX will be a name. it is in the specified sensor driver's header file. - * - * Returned Value: - * on success, 0 is returned. on failure, a negative value is returned. - * - ****************************************************************************/ -#define SENSOR_GET_HANDLE(name) __SENSOR_GET_HANDLE(name) - -/**************************************************************************** - * Name: SENSOR_GET_DEVICE_TYPE - * - * Description: - * get sensor device type as sensor_device_type_e type. - * - * Parameters: - * handle - sensor device handle. - * - * Returned Value: - * on success, 0 is returned. on failure, a negative value is returned. - * - ****************************************************************************/ -#define SENSOR_GET_DEVICE_TYPE(handle) (handle ? handle->type : -1) - -/**************************************************************************** - * Name: SENSOR_INIT - * - * Description: - * initialize the specified sensor device. - * - * Parameters: - * handle - sensor device handle. - * - * Returned Value: - * on success, 0 is returned. on failure, a negative value is returned. - * - ****************************************************************************/ -#define SENSOR_INIT(handle) (handle && handle->ops ? handle->ops->init(handle) : -1) - -/**************************************************************************** - * Name: SENSOR_DEINIT - * - * Description: - * deinitialize the specified sensor device. - * - * Parameters: - * handle - sensor device handle. - * - * Returned Value: - * on success, 0 is returned. on failure, a negative value is returned. - * - ****************************************************************************/ -#define SENSOR_DEINIT(handle) (handle && handle->ops ? handle->ops->deinit(handle) : -1) - -/**************************************************************************** - * Name: SENSOR_ACTIVATE - * - * Description: - * activate the specified sensor device. - * - * Parameters: - * handle - sensor device handle. - * - * Returned Value: - * on success, 0 is returned. on failure, a negative value is returned. - * - ****************************************************************************/ -#define SENSOR_ACTIVATE(handle) (handle && handle->ops ? handle->ops->activate(handle) : -1) - -/**************************************************************************** - * Name: SENSOR_DEACTIVATE - * - * Description: - * deactivate the specified sensor device. - * - * Parameters: - * handle - sensor device handle. - * - * Returned Value: - * on success, 0 is returned. on failure, a negative value is returned. - * - ****************************************************************************/ -#define SENSOR_DEACTIVATE(handle) (handle && handle->ops ? handle->ops->deactivate(handle) : -1) - -/**************************************************************************** - * Name: SENSOR_IOCTL - * - * Description: - * do ioctl on the specified sensor device. - * - * Parameters: - * handle - sensor device handle. - * id - ioctl id as sensor_ioctl_id_e type. - * pval -ioctl value as sensor_ioctl_value_t type. - * - * Returned Value: - * on success, 0 is returned. on failure, a negative value is returned. - * - ****************************************************************************/ -#define SENSOR_IOCTL(handle, id, pval) (handle && handle->ops ? handle->ops->ioctl(handle, id, pval) : -1) - -/**************************************************************************** - * Name: SENSOR_SET_TRIGGER - * - * Description: - * set trigger on the specified sensor device. - * - * Parameters: - * handle - sensor device handle. - * info - trigger information as sensor_trigger_info_t type. - * callback - callback function as sensor_trigger_callback_t type. - * - * Returned Value: - * on success, 0 is returned. on failure, a negative value is returned. - * - ****************************************************************************/ -#define SENSOR_SET_TRIGGER(handle, info, callback) (handle && handle->ops ? handle->ops->set_trigger(handle, info, callback) : -1) - -/**************************************************************************** - * Name: SENSOR_GET_DATA - * - * Description: - * get data from the specified sensor device. - * - * Parameters: - * handle - sensor device handle. - * pdata - data as sensor_data_t type. - * - * Returned Value: - * on success, 0 is returned. on failure, a negative value is returned. - * - ****************************************************************************/ -#define SENSOR_GET_DATA(handle, pdata) (handle && handle->ops ? handle->ops->get_data(handle, pdata) : -1) - -/*************************** - Utilities - ***************************/ - -/**************************************************************************** - * Name: SENSOR_TIME_GET - * - * Description: - * get time information as 'struct timeval' type. - * - * Parameters: - * time - the pointer of 'struct timeval' type variable. - * - * Returned Value: - * on success, 0 is returned. on failure, a negative value is returned. - * - ****************************************************************************/ -#define SENSOR_TIME_GET(time) gettimeofday(&time, NULL) - -/**************************************************************************** - * Name: SENSOR_TIME_GET - * - * Description: - * get time differential in usec beween old time and current time. - * - * Parameters: - * old_time - old time's pointer variable that points 'struct timeval' type. - * cur_time - current time's pointer variable that points 'struct timeval' type. - * - * Returned Value: - * time differentil in usec - * - ****************************************************************************/ -#define SENSOR_TIME_DIFF_USEC(old_time, cur_time) \ - ((cur_time.tv_sec * 1000000 + cur_time.tv_usec) - (old_time.tv_sec * 1000000 + old_time.tv_usec)) - -#ifdef __cplusplus -} -#endif -#endif /* __SENSOR_H__ */ -- 2.7.4