Repository: incubator-mynewt-core Updated Branches: refs/heads/develop 605317587 -> 2d4f8a760
MYNEWT-665 SensorAPI: Add TCS34725 Driver and color sensor support Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/2d4f8a76 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/2d4f8a76 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/2d4f8a76 Branch: refs/heads/develop Commit: 2d4f8a76055e50d42983da0eef2158e99be721d1 Parents: 6053175 Author: Vipul Rahane <[email protected]> Authored: Thu Mar 9 15:07:58 2017 -0800 Committer: Vipul Rahane <[email protected]> Committed: Thu Mar 9 15:16:46 2017 -0800 ---------------------------------------------------------------------- apps/sensors_test/pkg.yml | 1 + apps/sensors_test/src/main.c | 32 +- apps/sensors_test/syscfg.yml | 7 +- hw/bsp/nrf52dk/src/hal_bsp.c | 68 ++ .../tcs34725/include/tcs34725/tcs34725.h | 84 ++ hw/drivers/sensors/tcs34725/pkg.yml | 32 + hw/drivers/sensors/tcs34725/src/tcs34725.c | 920 +++++++++++++++++++ hw/drivers/sensors/tcs34725/src/tcs34725_priv.h | 278 ++++++ .../sensors/tcs34725/src/tcs34725_shell.c | 471 ++++++++++ hw/drivers/sensors/tcs34725/syscfg.yml | 35 + hw/sensor/include/sensor/color.h | 51 + hw/sensor/include/sensor/sensor.h | 8 +- hw/sensor/src/sensor_shell.c | 25 + 13 files changed, 2004 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2d4f8a76/apps/sensors_test/pkg.yml ---------------------------------------------------------------------- diff --git a/apps/sensors_test/pkg.yml b/apps/sensors_test/pkg.yml index 406ad30..41db418 100644 --- a/apps/sensors_test/pkg.yml +++ b/apps/sensors_test/pkg.yml @@ -35,6 +35,7 @@ pkg.deps: - hw/drivers/sensors/lsm303dlhc - hw/drivers/sensors/tsl2561 - hw/drivers/sensors/bno055 + - hw/drivers/sensors/tcs34725 - boot/bootutil - sys/shell - sys/config http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2d4f8a76/apps/sensors_test/src/main.c ---------------------------------------------------------------------- diff --git a/apps/sensors_test/src/main.c b/apps/sensors_test/src/main.c index b79b2b5..45d25a2 100755 --- a/apps/sensors_test/src/main.c +++ b/apps/sensors_test/src/main.c @@ -32,6 +32,7 @@ #include <sensor/sensor.h> #include <lsm303dlhc/lsm303dlhc.h> #include <tsl2561/tsl2561.h> +#include <tcs34725/tcs34725.h> #include <bno055/bno055.h> #include "flash_map/flash_map.h" #include <hal/hal_system.h> @@ -244,6 +245,29 @@ config_sensor(void) struct os_dev *dev; int rc; +#if MYNEWT_VAL(TCS34725_PRESENT) + struct tcs34725_cfg tcscfg; + + dev = (struct os_dev *) os_dev_open("color0", OS_TIMEOUT_NEVER, NULL); + assert(dev != NULL); + rc = tcs34725_init(dev, NULL); + if (rc) { + os_dev_close(dev); + goto err; + } + + /* Gain set to 16X and Inetgration time set to 24ms */ + tcscfg.gain = TCS34725_GAIN_16X;; + tcscfg.integration_time = TCS34725_INTEGRATIONTIME_24MS; + + rc = tcs34725_config((struct tcs34725 *)dev, &tcscfg); + if (rc) { + os_dev_close(dev); + goto err; + } + os_dev_close(dev); +#endif + #if MYNEWT_VAL(TSL2561_PRESENT) struct tsl2561_cfg tslcfg; @@ -309,9 +333,9 @@ config_sensor(void) BNO055_DO_FORMAT_ANDROID; bcfg.bc_opr_mode = BNO055_OPR_MODE_ACCONLY; - bcfg.bc_pwr_mode = BNO055_PWR_MODE_NORMAL; - + bcfg.bc_acc_bw = BNO055_ACC_CFG_BW_125HZ; + bcfg.bc_acc_range = BNO055_ACC_CFG_RNG_16G; bcfg.bc_use_ext_xtal = 1; rc = bno055_config((struct bno055 *) dev, &bcfg); @@ -418,6 +442,10 @@ main(int argc, char **argv) } #endif +#if MYNEWT_VAL(TCS34725_CLI) + tcs34725_shell_init(); +#endif + #if MYNEWT_VAL(TSL2561_CLI) tsl2561_shell_init(); #endif http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2d4f8a76/apps/sensors_test/syscfg.yml ---------------------------------------------------------------------- diff --git a/apps/sensors_test/syscfg.yml b/apps/sensors_test/syscfg.yml index 5507f28..bdbe400 100644 --- a/apps/sensors_test/syscfg.yml +++ b/apps/sensors_test/syscfg.yml @@ -47,11 +47,14 @@ syscfg.vals: syscfg.defs: TSL2561_PRESENT: description: 'TSL2561 is present' - value : 1 + value : 0 LSM303DLHC_PRESENT: description: 'LSM303 is present' value : 1 BNO055_PRESENT: description: 'BNO055 is present' - value : 1 + value : 0 + TCS34725_PRESENT: + description: 'BNO055 is present' + value : 0 http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2d4f8a76/hw/bsp/nrf52dk/src/hal_bsp.c ---------------------------------------------------------------------- diff --git a/hw/bsp/nrf52dk/src/hal_bsp.c b/hw/bsp/nrf52dk/src/hal_bsp.c index 1ab37e1..3b7b375 100644 --- a/hw/bsp/nrf52dk/src/hal_bsp.c +++ b/hw/bsp/nrf52dk/src/hal_bsp.c @@ -42,6 +42,26 @@ #endif #include "os/os_dev.h" #include "bsp.h" +#include <lsm303dlhc/lsm303dlhc.h> +#include <tsl2561/tsl2561.h> +#include <tcs34725/tcs34725.h> +#include <bno055/bno055.h> + +#if MYNEWT_VAL(LSM303DLHC_PRESENT) +static struct lsm303dlhc lsm303dlhc; +#endif + +#if MYNEWT_VAL(BNO055_PRESENT) +static struct bno055 bno055; +#endif + +#if MYNEWT_VAL(TSL2561_PRESENT) +static struct tsl2561 tsl2561; +#endif + +#if MYNEWT_VAL(TCS34725_PRESENT) +static struct tcs34725 tcs34725; +#endif #if MYNEWT_VAL(UART_0) static struct uart_dev os_bsp_uart0; @@ -151,6 +171,30 @@ hal_bsp_get_nvic_priority(int irq_num, uint32_t pri) return cfg_pri; } +#if MYNEWT_VAL(LSM303DLHC_PRESENT) || MYNEWT_VAL(BNO055_PRESENT) +static int +slinky_accel_init(struct os_dev *dev, void *arg) +{ + return (0); +} +#endif + +#if MYNEWT_VAL(TSL2561_PRESENT) +static int +slinky_light_init(struct os_dev *dev, void *arg) +{ + return (0); +} +#endif + +#if MYNEWT_VAL(TCS34725_PRESENT) +static int +slinky_color_init(struct os_dev *dev, void *arg) +{ + return (0); +} +#endif + void hal_bsp_init(void) { @@ -202,6 +246,30 @@ hal_bsp_init(void) assert(rc == 0); #endif +#if MYNEWT_VAL(LSM303DLHC_PRESENT) + rc = os_dev_create((struct os_dev *) &lsm303dlhc, "accel0", + OS_DEV_INIT_PRIMARY, 0, slinky_accel_init, NULL); + assert(rc == 0); +#endif + +#if MYNEWT_VAL(BNO055_PRESENT) + rc = os_dev_create((struct os_dev *) &bno055, "accel1", + OS_DEV_INIT_PRIMARY, 0, slinky_accel_init, NULL); + assert(rc == 0); +#endif + +#if MYNEWT_VAL(TSL2561_PRESENT) + rc = os_dev_create((struct os_dev *) &tsl2561, "light0", + OS_DEV_INIT_PRIMARY, 0, slinky_light_init, NULL); + assert(rc == 0); +#endif + +#if MYNEWT_VAL(TCS34725_PRESENT) + rc = os_dev_create((struct os_dev *) &tcs34725, "color0", + OS_DEV_INIT_PRIMARY, 0, slinky_color_init, NULL); + assert(rc == 0); +#endif + #if MYNEWT_VAL(UART_0) rc = os_dev_create((struct os_dev *) &os_bsp_uart0, "uart0", OS_DEV_INIT_PRIMARY, 0, uart_hal_init, (void *)&os_bsp_uart0_cfg); http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2d4f8a76/hw/drivers/sensors/tcs34725/include/tcs34725/tcs34725.h ---------------------------------------------------------------------- diff --git a/hw/drivers/sensors/tcs34725/include/tcs34725/tcs34725.h b/hw/drivers/sensors/tcs34725/include/tcs34725/tcs34725.h new file mode 100644 index 0000000..59e4385 --- /dev/null +++ b/hw/drivers/sensors/tcs34725/include/tcs34725/tcs34725.h @@ -0,0 +1,84 @@ +/* + * 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 + * resarding 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 __TCS34725_H__ +#define __TCS34725_H__ + +#define TCS34725_INTEGRATIONTIME_2_4MS 0xFF /* 2.4ms - 1 cycle - Max Count: 1024 */ +#define TCS34725_INTEGRATIONTIME_24MS 0xF6 /* 24ms - 10 cycles - Max Count: 10240 */ +#define TCS34725_INTEGRATIONTIME_50MS 0xEB /* 50ms - 20 cycles - Max Count: 20480 */ +#define TCS34725_INTEGRATIONTIME_101MS 0xD5 /* 101ms - 42 cycles - Max Count: 43008 */ +#define TCS34725_INTEGRATIONTIME_154MS 0xC0 /* 154ms - 64 cycles - Max Count: 65535 */ +#define TCS34725_INTEGRATIONTIME_700MS 0x00 /* 700ms - 256 cycles - Max Count: 65535 */ + +#define TCS34725_GAIN_1X 0x00 /* No gain */ +#define TCS34725_GAIN_4X 0x01 /* 4x gain */ +#define TCS34725_GAIN_16X 0x02 /* 16x gain */ +#define TCS34725_GAIN_60X 0x03 /* 60x gain */ + +#include <os/os.h> +#include "os/os_dev.h" +#include "sensor/sensor.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct tcs34725_cfg { + uint8_t gain; + uint8_t integration_time; +}; + +struct tcs34725 { + struct os_dev dev; + struct sensor sensor; + struct tcs34725_cfg cfg; + os_time_t last_read_time; +}; + +/** + * Expects to be called back through os_dev_create(). + * + * @param The device object associated with this accellerometer + * @param Argument passed to OS device init, unused + * + * @return 0 on success, non-zero error on failure. + */ +int +tcs34725_init(struct os_dev *dev, void *arg); + +/** + * Configure the sensor + * + * @param ptr to the sensor + * @param ptr to sensor config + * @return 0 on success, non-zero on failure + */ +int +tcs34725_config(struct tcs34725 *tcs34725, struct tcs34725_cfg *cfg); + +#if MYNEWT_VAL(TCS34725_CLI) +int tcs34725_shell_init(void); +#endif + +#ifdef __cplusplus +} +#endif + +#endif http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2d4f8a76/hw/drivers/sensors/tcs34725/pkg.yml ---------------------------------------------------------------------- diff --git a/hw/drivers/sensors/tcs34725/pkg.yml b/hw/drivers/sensors/tcs34725/pkg.yml new file mode 100644 index 0000000..18c65c4 --- /dev/null +++ b/hw/drivers/sensors/tcs34725/pkg.yml @@ -0,0 +1,32 @@ +# +# 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. +# + +pkg.name: hw/drivers/sensors/tcs34725 +pkg.description: Driver for the TCS34725 light to digital sensor +pkg.author: "Adafruit <[email protected]>" +pkg.homepage: "http://www.adafruit.com/" +pkg.keywords: + - adafruit + - tcs34725 + - i2c + - sensor + +pkg.deps: + - "@apache-mynewt-core/kernel/os" + - "@apache-mynewt-core/hw/hal" http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2d4f8a76/hw/drivers/sensors/tcs34725/src/tcs34725.c ---------------------------------------------------------------------- diff --git a/hw/drivers/sensors/tcs34725/src/tcs34725.c b/hw/drivers/sensors/tcs34725/src/tcs34725.c new file mode 100644 index 0000000..cd0f2c2 --- /dev/null +++ b/hw/drivers/sensors/tcs34725/src/tcs34725.c @@ -0,0 +1,920 @@ +/* + * 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 + * resarding 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. + */ + +#include <string.h> +#include <errno.h> +#include <assert.h> + +#include "defs/error.h" +#include "os/os.h" +#include "sysinit/sysinit.h" +#include "hal/hal_i2c.h" +#include "sensor/sensor.h" +#include "tcs34725/tcs34725.h" +#include "tcs34725_priv.h" +#include "sensor/color.h" + +#if MYNEWT_VAL(TCS34725_LOG) +#include "log/log.h" +#endif + +#if MYNEWT_VAL(TCS34725_STATS) +#include "stats/stats.h" +#endif + +#if MYNEWT_VAL(TCS34725_STATS) +/* Define the stats section and records */ +STATS_SECT_START(tcs34725_stat_section) + STATS_SECT_ENTRY(samples_2_4ms) + STATS_SECT_ENTRY(samples_24ms) + STATS_SECT_ENTRY(samples_50ms) + STATS_SECT_ENTRY(samples_101ms) + STATS_SECT_ENTRY(samples_154ms) + STATS_SECT_ENTRY(samples_700ms) + STATS_SECT_ENTRY(samples_userdef) + STATS_SECT_ENTRY(errors) +STATS_SECT_END + +/* Define stat names for querying */ +STATS_NAME_START(tcs34725_stat_section) + STATS_NAME(tcs34725_stat_section, samples_2_4ms) + STATS_NAME(tcs34725_stat_section, samples_24ms) + STATS_NAME(tcs34725_stat_section, samples_50ms) + STATS_NAME(tcs34725_stat_section, samples_101ms) + STATS_NAME(tcs34725_stat_section, samples_154ms) + STATS_NAME(tcs34725_stat_section, samples_700ms) + STATS_NAME(tcs34725_stat_section, samples_userdef) + STATS_NAME(tcs34725_stat_section, errors) +STATS_NAME_END(tcs34725_stat_section) + +/* Global variable used to hold stats data */ +STATS_SECT_DECL(tcs34725_stat_section) g_tcs34725stats; +#endif + +#if MYNEWT_VAL(TCS34725_LOG) +#define LOG_MODULE_TCS34725 (307) +#define TCS34725_INFO(...) LOG_INFO(&_log, LOG_MODULE_TCS34725, __VA_ARGS__) +#define TCS34725_ERR(...) LOG_ERROR(&_log, LOG_MODULE_TCS34725, __VA_ARGS__) +static struct log _log; +#else +#define TCS34725_INFO(...) +#define TCS34725_ERR(...) +#endif + +/* Exports for the sensor interface. + */ +static void *tcs34725_sensor_get_interface(struct sensor *, sensor_type_t); +static int tcs34725_sensor_read(struct sensor *, sensor_type_t, + sensor_data_func_t, void *, uint32_t); +static int tcs34725_sensor_get_config(struct sensor *, sensor_type_t, + struct sensor_cfg *); + +static const struct sensor_driver g_tcs34725_sensor_driver = { + tcs34725_sensor_get_interface, + tcs34725_sensor_read, + tcs34725_sensor_get_config +}; + +uint8_t g_tcs34725_gain; +uint8_t g_tcs34725_integration_time; +uint8_t g_tcs34725_enabled; + +/** + * Writes a single byte to the specified register + * + * @param The register address to write to + * @param The value to write + * + * @return 0 on success, non-zero error on failure. + */ +int +tcs34725_write8(uint8_t reg, uint32_t value) +{ + int rc; + uint8_t payload[2] = { reg | TCS34725_COMMAND_BIT, value & 0xFF }; + + struct hal_i2c_master_data data_struct = { + .address = MYNEWT_VAL(TCS34725_I2CADDR), + .len = 2, + .buffer = payload + }; + + rc = hal_i2c_master_write(MYNEWT_VAL(TCS34725_I2CBUS), &data_struct, + OS_TICKS_PER_SEC / 10, 1); + if (rc) { + TCS34725_ERR("Failed to write to 0x%02X:0x%02X with value 0x%02X\n", + addr, reg, value); +#if MYNEWT_VAL(TCS34725_STATS) + STATS_INC(g_tcs34725stats, errors); +#endif + } + + return rc; +} + +/** + * Reads a single byte from the specified register + * + * @param The register address to read from + * @param Pointer to where the register value should be written + * + * @return 0 on success, non-zero error on failure. + */ +int +tcs34725_read8(uint8_t reg, uint8_t *value) +{ + int rc; + uint8_t payload; + + struct hal_i2c_master_data data_struct = { + .address = MYNEWT_VAL(TCS34725_I2CADDR), + .len = 1, + .buffer = &payload + }; + + /* Register write */ + payload = reg | TCS34725_COMMAND_BIT; + rc = hal_i2c_master_write(MYNEWT_VAL(TCS34725_I2CBUS), &data_struct, + OS_TICKS_PER_SEC / 10, 1); + if (rc) { + TCS34725_ERR("I2C access failed at address 0x%02X\n", addr); +#if MYNEWT_VAL(TCS34725_STATS) + STATS_INC(g_tcs34725stats, errors); +#endif + goto error; + } + + /* Read one byte back */ + payload = 0; + rc = hal_i2c_master_read(MYNEWT_VAL(TCS34725_I2CBUS), &data_struct, + OS_TICKS_PER_SEC / 10, 1); + *value = payload; + if (rc) { + TCS34725_ERR("Failed to read from 0x%02X:0x%02X\n", addr, reg); +#if MYNEWT_VAL(TCS34725_STATS) + STATS_INC(g_tcs34725stats, errors); +#endif + } + +error: + return rc; +} + +/** + * Read data from the sensor of variable length (MAX: 8 bytes) + * + * @param Register to read from + * @param Bufer to read into + * @param Length of the buffer + * + * @return 0 on success and non-zero on failure + */ +int +tcs34725_readlen(uint8_t reg, uint8_t *buffer, uint8_t len) +{ + int rc; + uint8_t payload[9] = { reg | TCS34725_COMMAND_BIT, 0, 0, 0, 0, 0, 0, 0, 0}; + + struct hal_i2c_master_data data_struct = { + .address = MYNEWT_VAL(TCS34725_I2CADDR), + .len = 1, + .buffer = payload + }; + + /* Clear the supplied buffer */ + memset(buffer, 0, len); + + /* Register write */ + rc = hal_i2c_master_write(MYNEWT_VAL(TCS34725_I2CBUS), &data_struct, + OS_TICKS_PER_SEC / 10, 1); + if (rc) { + TCS34725_ERR("I2C access failed at address 0x%02X\n", addr); +#if MYNEWT_VAL(TCS34725_STATS) + STATS_INC(g_tcs34725stats, errors); +#endif + goto err; + } + + /* Read len bytes back */ + memset(payload, 0, sizeof(payload)); + data_struct.len = len; + rc = hal_i2c_master_read(MYNEWT_VAL(TCS34725_I2CBUS), &data_struct, + OS_TICKS_PER_SEC / 10, 1); + + if (rc) { + TCS34725_ERR("Failed to read from 0x%02X:0x%02X\n", addr, reg); +#if MYNEWT_VAL(TCS34725_STATS) + STATS_INC(g_tcs34725stats, errors); +#endif + goto err; + } + + /* Copy the I2C results into the supplied buffer */ + memcpy(buffer, payload, len); + + return 0; +err: + return rc; +} + +/** + * Writes a multiple bytes to the specified register + * + * @param The register address to write to + * @param The data buffer to write from + * + * @return 0 on success, non-zero error on failure. + */ +int +tcs34725_writelen(uint8_t reg, uint8_t *buffer, uint8_t len) +{ + int rc; + uint8_t payload[9] = { reg, 0, 0, 0, 0, 0, 0, 0, 0}; + + struct hal_i2c_master_data data_struct = { + .address = MYNEWT_VAL(TCS34725_I2CADDR), + .len = 1, + .buffer = payload + }; + + memcpy(&payload[1], buffer, len); + + /* Register write */ + rc = hal_i2c_master_write(MYNEWT_VAL(TCS34725_I2CBUS), &data_struct, + OS_TICKS_PER_SEC / 10, 1); + if (rc) { + TCS34725_ERR("I2C access failed at address 0x%02X\n", addr); +#if MYNEWT_VAL(TCS34725_STATS) + STATS_INC(g_tcs34725stats, errors); +#endif + goto err; + } + + memset(payload, 0, sizeof(payload)); + data_struct.len = len; + rc = hal_i2c_master_write(MYNEWT_VAL(TCS34725_I2CBUS), &data_struct, + OS_TICKS_PER_SEC / 10, len); + + if (rc) { + TCS34725_ERR("Failed to read from 0x%02X:0x%02X\n", addr, reg); +#if MYNEWT_VAL(TCS34725_STATS) + STATS_INC(g_tcs34725stats, errors); +#endif + goto err; + } + + return 0; +err: + return rc; +} + + +#if MYNEWT_VAL(USE_MATH) +/** + * Float power function + * + * @param float base + * @param float exponent + */ +static float +powf(float base, float exp) +{ + return (float)(pow((double)base, (double)exp)); +} + +#endif + +/** + * + * Enables the device + * + * @param enable/disable + * @return 0 on success, non-zero on error + */ +int +tcs34725_enable(uint8_t enable) +{ + int rc; + uint8_t reg; + + rc = tcs34725_read8(TCS34725_REG_ENABLE, ®); + if (rc) { + goto err; + } + + os_time_delay((3 * OS_TICKS_PER_SEC)/1000 + 1); + + if (enable) { + rc = tcs34725_write8(TCS34725_REG_ENABLE, reg | TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN); + if (rc) { + goto err; + } + } else { + rc = tcs34725_write8(TCS34725_REG_ENABLE, reg & ~(TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN)); + if (rc) { + goto err; + } + } + + g_tcs34725_enabled = enable; + + return 0; +err: + return rc; +} + +/** + * Expects to be called back through os_dev_create(). + * + * @param The device object associated with this accellerometer + * @param Argument passed to OS device init, unused + * + * @return 0 on success, non-zero error on failure. + */ +int +tcs34725_init(struct os_dev *dev, void *arg) +{ + struct tcs34725 *tcs34725; + struct sensor *sensor; + int rc; + + tcs34725 = (struct tcs34725 *) dev; + +#if MYNEWT_VAL(TCS34725_LOG) + log_register("tcs34725", &_log, &log_console_handler, NULL, LOG_SYSLEVEL); +#endif + + sensor = &tcs34725->sensor; + +#if MYNEWT_VAL(TCS34725_STATS) + /* Initialise the stats entry */ + rc = stats_init( + STATS_HDR(g_tcs34725stats), + STATS_SIZE_INIT_PARMS(g_tcs34725stats, STATS_SIZE_32), + STATS_NAME_INIT_PARMS(tcs34725_stat_section)); + SYSINIT_PANIC_ASSERT(rc == 0); + /* Register the entry with the stats registry */ + rc = stats_register("tcs34725", STATS_HDR(g_tcs34725stats)); + SYSINIT_PANIC_ASSERT(rc == 0); +#endif + + rc = sensor_init(sensor, dev); + if (rc != 0) { + goto err; + } + + /* Add the color sensor driver */ + rc = sensor_set_driver(sensor, SENSOR_TYPE_COLOR, + (struct sensor_driver *) &g_tcs34725_sensor_driver); + if (rc != 0) { + goto err; + } + + rc = sensor_mgr_register(sensor); + if (rc != 0) { + goto err; + } + + return (0); +err: + return (rc); +} + +/** + * Indicates whether the sensor is enabled or not + * + * @return 1 if enabled, 0 if disabled + */ +uint8_t +tcs34725_get_enable (void) +{ + return g_tcs34725_enabled; +} + +/** + * Sets integration time + * + * @param integration time to be set + * @return 0 on success, non-zero on failure + */ +int +tcs34725_set_integration_time(uint8_t int_time) +{ + int rc; + + rc = tcs34725_write8(TCS34725_REG_ATIME, + int_time | g_tcs34725_gain); + if (rc) { + goto err; + } + + g_tcs34725_integration_time = int_time; + +err: + return rc; +} + +/** + * Gets integration time set earlier + * + * @return integration time + */ +uint8_t +tcs34725_get_integration_time(void) +{ + return g_tcs34725_integration_time; +} + +/** + * Set gain of the sensor + * + * @param gain + * @return 0 on success, non-zero on failure + */ +int +tcs34725_set_gain(uint8_t gain) +{ + int rc; + + if (gain > TCS34725_GAIN_60X) { + TCS34725_ERR("Invalid gain value\n"); + rc = SYS_EINVAL; + goto err; + } + + rc = tcs34725_write8(TCS34725_REG_CONTROL, + g_tcs34725_integration_time | gain); + if (rc) { + goto err; + } + + g_tcs34725_gain = gain; + +err: + return rc; +} + +/** + * Get gain of the sensor + * + * @return gain + */ +uint8_t +tcs34725_get_gain(void) +{ + return g_tcs34725_gain; +} + +/** + * Get chip ID from the sensor + * + * @param Pointer to the variable to fill up chip ID in + * @return 0 on success, non-zero on failure + */ +int +tcs34725_get_chip_id(uint8_t *id) +{ + int rc; + uint8_t idtmp; + + /* Check if we can read the chip address */ + rc = tcs34725_read8(TCS34725_REG_ID, &idtmp); + if (rc) { + goto err; + } + + *id = idtmp; + + return 0; +err: + return rc; +} + +/** + * Configure the sensor + * + * @param ptr to the sensor + * @param ptr to sensor config + * @return 0 on success, non-zero on failure + */ +int +tcs34725_config(struct tcs34725 *tcs34725, struct tcs34725_cfg *cfg) +{ + int rc; + uint8_t id; + + rc = tcs34725_get_chip_id(&id); + if (id != TCS34725_ID || rc != 0) { + rc = SYS_EINVAL; + goto err; + } + + rc |= tcs34725_enable(1); + + rc |= tcs34725_set_integration_time(cfg->integration_time); + + rc |= tcs34725_set_gain(cfg->gain); + if (rc) { + goto err; + } + + /* Overwrite the configuration data. */ + memcpy(&tcs34725->cfg, cfg, sizeof(*cfg)); + +err: + return (rc); +} + +/** + * Reads the raw red, green, blue and clear channel values + * + * + * @param red value to return + * @param green value to return + * @param blue value to return + * @param clear channel value + * @param driver sturcture containing config + */ +int +tcs34725_get_rawdata(uint16_t *r, uint16_t *g, uint16_t *b, uint16_t *c, + struct tcs34725 *tcs34725) +{ + uint8_t payload[8] = {0}; + int rc; + int delay_ticks; + + /* Set a delay for the integration time */ + switch (tcs34725->cfg.integration_time) + { + case TCS34725_INTEGRATIONTIME_2_4MS: + delay_ticks = (3 * OS_TICKS_PER_SEC)/1000 + 1; + break; + case TCS34725_INTEGRATIONTIME_24MS: + delay_ticks = (24 * OS_TICKS_PER_SEC)/1000 + 1; + break; + case TCS34725_INTEGRATIONTIME_50MS: + delay_ticks = (50 * OS_TICKS_PER_SEC)/1000 + 1; + break; + case TCS34725_INTEGRATIONTIME_101MS: + delay_ticks = (101 * OS_TICKS_PER_SEC)/1000 + 1; + break; + case TCS34725_INTEGRATIONTIME_154MS: + delay_ticks = (154 * OS_TICKS_PER_SEC)/1000 + 1; + break; + case TCS34725_INTEGRATIONTIME_700MS: + delay_ticks = (700 * OS_TICKS_PER_SEC)/1000 + 1; + break; + default: + /* + * If the integration time specified is not from the config, + * it will get considered as valid inetgration time in ms + */ + delay_ticks = (tcs34725->cfg.integration_time * OS_TICKS_PER_SEC)/ + 1000 + 1; + break; + } + + os_time_delay(delay_ticks); + + *c = *r = *g = *b = 0; + + rc = tcs34725_readlen(TCS34725_REG_CDATAL, payload, 8); + if (rc) { + goto err; + } + + *c = payload[1] << 8 | payload[0]; + *r = payload[3] << 8 | payload[2]; + *g = payload[5] << 8 | payload[4]; + *b = payload[7] << 8 | payload[6]; + +#if MYNEWT_VAL(TCS34725_STATS) + switch (tcs34725->cfg.integration_time) { + case TCS34725_INTEGRATIONTIME_2_4MS: + STATS_INC(g_tcs34725stats, samples_2_4ms); + break; + case TCS34725_INTEGRATIONTIME_24MS: + STATS_INC(g_tcs34725stats, samples_24ms); + break; + case TCS34725_INTEGRATIONTIME_50MS: + STATS_INC(g_tcs34725stats, samples_50ms); + break; + case TCS34725_INTEGRATIONTIME_101MS: + STATS_INC(g_tcs34725stats, samples_101ms); + break; + case TCS34725_INTEGRATIONTIME_154MS: + STATS_INC(g_tcs34725stats, samples_154ms); + break; + case TCS34725_INTEGRATIONTIME_700MS: + STATS_INC(g_tcs34725stats, samples_700ms); + default: + STATS_INC(g_tcs34725stats, samples_userdef); + break; + } + +#endif + + return 0; +err: + return rc; + +} + +/** + * + * Converts raw RGB values to color temp in deg K + * + * @param red value + * @param green value + * @param blue value + * @return final CCT value using McCamy's formula + */ +static uint16_t +tcs34725_calculate_color_temp(uint16_t r, uint16_t g, uint16_t b) +{ + float n; + float cct; + + /** + * From the designer's notebook by TAOS: + * Mapping sensor response RGB values to CIE tristimulus values(XYZ) + * based on broad enough transformation, the light sources chosen were a + * high color temperature fluorescent (6500K), a low color temperature + * fluorescent (3000K), and an incandescent (60W) + * Note: y = Illuminance or lux + * + * For applications requiring more precision, + * narrower range of light sources should be used and a new correlation + * matrix could be formulated and CIE tristimulus values should be + * calculated. Please refer the manual for calculating tristumulus values. + * + * x = (-0.14282F * r) + (1.54924F * g) + (-0.95641F * b); + * y = (-0.32466F * r) + (1.57837F * g) + (-0.73191F * b); + * z = (-0.68202F * r) + (0.77073F * g) + ( 0.56332F * b); + * + * + * Calculating chromaticity co-ordinates, the light can be plotted on a two + * dimensional chromaticity diagram + * + * xc = x / (x + y + z); + * yc = y / (x + y + z); + * + * Use McCamy's formula to determine the CCT + * n = (xc - 0.3320F) / (0.1858F - yc); + */ + + /* + * n can be calculated directly using the following formula for + * above considerations + */ + n = ((0.23881)*r + (0.25499)*g + (-0.58291)*b) / ((0.11109)*r + (-0.85406)*g + + (0.52289)*b); + + /* + * Calculate the final CCT + * CCT is only meant to characterize near white lights. + */ + +#if MYNEWT_VAL(USE_MATH) + cct = (449.0F * powf(n, 3)) + (3525.0F * powf(n, 2)) + (6823.3F * n) + 5520.33F; +#else + cct = (449.0F * n * n * n) + (3525.0F * n * n) + (6823.3F * n) + 5520.33F; +#endif + + /* Return the results in degrees Kelvin */ + return (uint16_t)cct; +} + +/** + * + * Converts the raw RGB values to lux + * + * @param red value + * @param green value + * @param blue value + * @return lux value + */ +static uint16_t +tcs34725_calculate_lux(uint16_t r, uint16_t g, uint16_t b) +{ + float lux; + + lux = (-0.32466F * r) + (1.57837F * g) + (-0.73191F * b); + + return (uint16_t)lux; +} + + + +static int +tcs34725_sensor_read(struct sensor *sensor, sensor_type_t type, + sensor_data_func_t data_func, void *data_arg, uint32_t timeout) +{ + struct tcs34725 *tcs34725; + struct sensor_color_data scd; + uint16_t r; + uint16_t g; + uint16_t b; + uint16_t c; + int rc; + + /* If the read isn't looking for accel or mag data, don't do anything. */ + if (!(type & SENSOR_TYPE_COLOR)) { + rc = SYS_EINVAL; + goto err; + } + + tcs34725 = (struct tcs34725 *) SENSOR_GET_DEVICE(sensor); + + /* Get a new accelerometer sample */ + if (type & SENSOR_TYPE_COLOR) { + r = g = b = c = 0; + + rc = tcs34725_get_rawdata(&r, &g, &b, &c, tcs34725); + if (rc) { + goto err; + } + + scd.scd_r = r; + scd.scd_g = g; + scd.scd_b = b; + scd.scd_c = c; + scd.scd_lux = tcs34725_calculate_lux(r, g, b); + scd.scd_colortemp = tcs34725_calculate_color_temp(r, g, b); + + /* Call data function */ + rc = data_func(sensor, data_arg, &scd); + if (rc != 0) { + goto err; + } + } + + return 0; +err: + return rc; +} + +/** + * enables/disables interrupts + * + * @param enable/disable + * @return 0 on success, non-zero on failure + */ +int +tcs34725_enable_interrupt(uint8_t enable) +{ + uint8_t reg; + int rc; + + rc = tcs34725_read8(TCS34725_REG_ENABLE, ®); + if (rc) { + goto err; + } + + if (enable) { + reg |= TCS34725_ENABLE_AIEN; + } else { + reg &= ~TCS34725_ENABLE_AIEN; + } + + rc = tcs34725_write8(TCS34725_REG_ENABLE, reg); + if (rc) { + goto err; + } + + return 0; +err: + return rc; +} + +/** + * Clears the interrupt by writing to the command register + * as a special function + * ______________________________________________________ + * | CMD | TYPE | ADDR/SF | + * | 7 | 6:5 | 4:0 | + * | 1 | 11 | 00110 | + * |_______|_____________|______________________________| + * + * @return 0 on success, non-zero on failure + */ +int +tcs34725_clear_interrupt(void) +{ + int rc; + uint8_t payload = TCS34725_COMMAND_BIT | TCS34725_CMD_TYPE | TCS34725_CMD_ADDR; + + struct hal_i2c_master_data data_struct = { + .address = MYNEWT_VAL(TCS34725_I2CADDR), + .len = 0, + .buffer = &payload + }; + + rc = hal_i2c_master_write(MYNEWT_VAL(TCS34725_I2CBUS), &data_struct, + OS_TICKS_PER_SEC / 10, 1); + if (rc) { + goto err; + } + + return 0; +err: + return rc; +} + +/** + * Sets threshold limits for interrupts, if the low threshold is set above + * the high threshold, the high threshold is ignored and only the low + * threshold is evaluated + * + * @param lower threshold + * @param higher threshold + * + * @return 0 on success, non-zero on failure + */ +int +tcs34725_set_int_limits(uint16_t low, uint16_t high) +{ + uint8_t payload[4]; + int rc; + + payload[0] = low & 0xFF; + payload[1] = low >> 8; + payload[2] = high & 0xFF; + payload[3] = high >> 8; + + rc = tcs34725_writelen(TCS34725_REG_AILTL, payload, sizeof(payload)); + if (rc) { + return rc; + } + return 0; +} + +static void * +tcs34725_sensor_get_interface(struct sensor *sensor, sensor_type_t type) +{ + return (NULL); +} + +/** + * + * Gets threshold limits for interrupts, if the low threshold is set above + * the high threshold, the high threshold is ignored and only the low + * threshold is evaluated + * + * @param ptr to lower threshold + * @param ptr to higher threshold + * + * @return 0 on success, non-zero on failure + */ +int +tcs34725_get_int_limits(uint16_t *low, uint16_t *high) +{ + uint8_t payload[4]; + int rc; + + rc = tcs34725_readlen(TCS34725_REG_AILTL, payload, sizeof(payload)); + if (rc) { + return rc; + } + + *low = payload[0]; + *low |= payload[1] << 8; + *high = payload[2]; + *high |= payload[3] << 8; + + return 0; +} + +static int +tcs34725_sensor_get_config(struct sensor *sensor, sensor_type_t type, + struct sensor_cfg *cfg) +{ + int rc; + + if ((type != SENSOR_TYPE_COLOR)) { + rc = SYS_EINVAL; + goto err; + } + + cfg->sc_valtype = SENSOR_VALUE_TYPE_INT32; + + return (0); +err: + return (rc); +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2d4f8a76/hw/drivers/sensors/tcs34725/src/tcs34725_priv.h ---------------------------------------------------------------------- diff --git a/hw/drivers/sensors/tcs34725/src/tcs34725_priv.h b/hw/drivers/sensors/tcs34725/src/tcs34725_priv.h new file mode 100644 index 0000000..4c47929 --- /dev/null +++ b/hw/drivers/sensors/tcs34725/src/tcs34725_priv.h @@ -0,0 +1,278 @@ +/* + * 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 + * resarding 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 __TCS34725_PRIV_H__ +#define __TCS34725_PRIV_H__ + +#define TCS34725_ID 0x44 + +/* COMMAND Register - Specific register address */ +#define TCS34725_COMMAND_BIT (1 << 7) +#define TCS34725_CMD_TYPE (3 << 5) +#define TCS34725_CMD_ADDR (6 << 1) + +/* Enable register */ +#define TCS34725_REG_ENABLE 0x00 +#define TCS34725_ENABLE_AIEN 0x10 /* enable/disable RGBC interrupt */ +#define TCS34725_ENABLE_WEN 0x08 /* enable/disable wait timer */ +#define TCS34725_ENABLE_AEN 0x02 /* enable/disable ADC */ +#define TCS34725_ENABLE_PON 0x01 /* enable/disable int oscillator */ + +/* Integration time */ +#define TCS34725_REG_ATIME 0x01 + +/* Wait time register (if TCS34725_ENABLE_WEN is asserted) */ +#define TCS34725_REG_WTIME 0x03 +#define TCS34725_WTIME_2_4MS 0xFF /* WLONG0 = 2.4ms WLONG1 = 0.029s */ +#define TCS34725_WTIME_204MS 0xAB /* WLONG0 = 204ms WLONG1 = 2.45s */ +#define TCS34725_WTIME_614MS 0x00 /* WLONG0 = 614ms WLONG1 = 7.4s */ + +/* Clear channel lower interrupt threshold register */ +#define TCS34725_REG_AILTL 0x04 +#define TCS34725_REG_AILTH 0x05 + +/* Clear channel upper interrupt threshold register */ +#define TCS34725_REG_AIHTL 0x06 +#define TCS34725_REG_AIHTH 0x07 + +/* Persistence register */ +#define TCS34725_REG_PERS 0x0C +#define TCS34725_PERS_NONE 0x00 /* interrupt for each RGBC cycle */ +#define TCS34725_PERS_1_CYCLE 0x01 /* interrupt for 1 RGBC cycle */ +#define TCS34725_PERS_2_CYCLE 0x02 /* interrupt for 2 RGBC cycle */ +#define TCS34725_PERS_3_CYCLE 0x03 /* interrupt for 3 RGBC cycle */ +#define TCS34725_PERS_5_CYCLE 0x04 /* interrupt for 5 RGBC cycle */ +#define TCS34725_PERS_10_CYCLE 0x05 /* interrupt for 10 RGBC cycle */ +#define TCS34725_PERS_15_CYCLE 0x06 /* interrupt for 15 RGBC cycle */ +#define TCS34725_PERS_20_CYCLE 0x07 /* interrupt for 20 RGBC cycle */ +#define TCS34725_PERS_25_CYCLE 0x08 /* interrupt for 25 RGBC cycle */ +#define TCS34725_PERS_30_CYCLE 0x09 /* interrupt for 30 RGBC cycle */ +#define TCS34725_PERS_35_CYCLE 0x0A /* interrupt for 35 RGBC cycle */ +#define TCS34725_PERS_40_CYCLE 0x0B /* interrupt for 40 RGBC cycle */ +#define TCS34725_PERS_45_CYCLE 0x0C /* interrupt for 45 RGBC cycle */ +#define TCS34725_PERS_50_CYCLE 0x0D /* interrupt for 50 RGBC cycle */ +#define TCS34725_PERS_55_CYCLE 0x0E /* interrupt for 55 RGBC cycle */ +#define TCS34725_PERS_60_CYCLE 0x0F /* interrupt for 60 RGBC cycle */ + +/* Configuration register */ +#define TCS34725_REG_CONFIG 0x0D +#define TCS34725_CONFIG_WLONG 0x02 /* 0x or 12x TCS34725_WTIME */ + +/* Set the gain level for the sensor */ +#define TCS34725_REG_CONTROL 0x0F + +/* Should be 0x44 for TCS34725 */ +#define TCS34725_REG_ID 0x12 + +/* Device status register */ +#define TCS34725_REG_STATUS 0x13 +#define TCS34725_STATUS_AINT 0x10 /* RGBC Clean channel interrupt */ +#define TCS34725_STATUS_AVALID 0x01 /* RGBC completed an integ cycle */ + +/* Clear channel data */ +#define TCS34725_REG_CDATAL 0x14 +#define TCS34725_REG_CDATAH 0x15 + +/* Red channel data */ +#define TCS34725_REG_RDATAL 0x16 +#define TCS34725_REG_RDATAH 0x17 + +/* Green channel data */ +#define TCS34725_REG_GDATAL 0x18 +#define TCS34725_REG_GDATAH 0x19 + +/* Blue channel data */ +#define TCS34725_REG_BDATAL 0x1A +#define TCS34725_REG_BDATAH 0x1B + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Writes a single byte to the specified register + * + * @param The register address to write to + * @param The value to write + * + * @return 0 on success, non-zero error on failure. + */ + +int tcs34725_write8(uint8_t reg, uint32_t value); + +/** + * Writes multiple bytes to the specified register + * + * @param The register address to write to + * @param The data buffer to write from + * + * @return 0 on success, non-zero error on failure. + */ +int +tcs34725_writelen(uint8_t reg, uint8_t *buffer, uint8_t len); + + +/** + * Reads a single byte from the specified register + * + * @param The register address to read from + * @param Pointer to where the register value should be written + * + * @return 0 on success, non-zero error on failure. + */ +int +tcs34725_read8(uint8_t reg, uint8_t *value); + +/** + * Read data from the sensor of variable length (MAX: 8 bytes) + * + * + * @param Register to read from + * @param Bufer to read into + * @param Length of the buffer + * + * @return 0 on success and non-zero on failure + */ +int +tcs34725_readlen(uint8_t reg, uint8_t *buffer, uint8_t len); + +/** + * Get chip ID from the sensor + * + * @param Pointer to the variable to fill up chip ID in + * @return 0 on success, non-zero on failure + */ +int +tcs34725_get_chip_id(uint8_t *id); + +/** + * Get gain of the sensor + * + * @return gain + */ +uint8_t +tcs34725_get_gain(void); + +/** + * Set gain of the sensor + * + * @param gain + * @return 0 on success, non-zero on failure + */ +int +tcs34725_set_gain(uint8_t gain); + +/** + * enables/disables interrupts + * + * @param enable/disable + * @return 0 on success, non-zero on failure + */ +int +tcs34725_enable_interrupt(uint8_t enable); + +/** + * Clears the interrupts + * + * @return 0 on success, non-zero on failure + */ +int +tcs34725_clear_interrupt(void); + +/** + * Sets threshold limits for interrupts, if the low threshold is set above + * the high threshold, the high threshold is ignored and only the low + * threshold is evaluated + * + * @param lower threshold + * @param higher threshold + * + * @return 0 on success, non-zero on failure + */ +int +tcs34725_set_int_limits(uint16_t low, uint16_t high); + +/** + * Sets integration time + * + * @param integration time to be set + * @return 0 on success, non-zero on failure + */ +int +tcs34725_set_integration_time(uint8_t int_time); + +/** + * Gets integration time set earlier + * + * @return integration time + */ +uint8_t +tcs34725_get_integration_time(void); + +/** + * + * Enables the device + * + * @param enable/disable + * @return 0 on success, non-zero on error + */ +int +tcs34725_enable(uint8_t enable); + +/** + * Indicates whether the sensor is enabled or not + * + * @return 1 if enabled, 0 if disabled + */ +uint8_t +tcs34725_get_enable (void); + +/** + * Reads the raw red, green, blue and clear channel values + * + * + * @param red value to return + * @param green value to return + * @param blue value to return + * @param clear channel value + * @param driver sturcture containing config + */ +int +tcs34725_get_rawdata(uint16_t *r, uint16_t *g, uint16_t *b, uint16_t *c, + struct tcs34725 *tcs34725); + +/** + * + * Gets threshold limits for interrupts, if the low threshold is set above + * the high threshold, the high threshold is ignored and only the low + * threshold is evaluated + * + * @param ptr to lower threshold + * @param ptr to higher threshold + * + * @return 0 on success, non-zero on failure + */ +int +tcs34725_get_int_limits(uint16_t *low, uint16_t *high); + +#ifdef __cplusplus +} +#endif + +#endif /* TCS34725_PRIV_H_ */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2d4f8a76/hw/drivers/sensors/tcs34725/src/tcs34725_shell.c ---------------------------------------------------------------------- diff --git a/hw/drivers/sensors/tcs34725/src/tcs34725_shell.c b/hw/drivers/sensors/tcs34725/src/tcs34725_shell.c new file mode 100644 index 0000000..e15b4fc --- /dev/null +++ b/hw/drivers/sensors/tcs34725/src/tcs34725_shell.c @@ -0,0 +1,471 @@ +/* + * 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 + * resarding 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. + */ + +#include <string.h> +#include "sysinit/sysinit.h" +#include "console/console.h" +#include "shell/shell.h" +#include "hal/hal_gpio.h" +#include "tcs34725/tcs34725.h" +#include "tcs34725_priv.h" +#include "defs/error.h" + +#if MYNEWT_VAL(TCS34725_CLI) +extern uint8_t g_tcs34725_integration_time; +extern uint8_t g_tcs34725_gain; + +static int tcs34725_shell_cmd(int argc, char **argv); + +static struct shell_cmd tcs34725_shell_cmd_struct = { + .sc_cmd = "tcs34725", + .sc_cmd_func = tcs34725_shell_cmd +}; + +static int +tcs34725_shell_stol(char *param_val, long min, long max, long *output) +{ + char *endptr; + long lval; + + lval = strtol(param_val, &endptr, 10); /* Base 10 */ + if (param_val != '\0' && *endptr == '\0' && + lval >= min && lval <= max) { + *output = lval; + } else { + return SYS_EINVAL; + } + + return 0; +} + +static int +tcs34725_shell_err_too_many_args(char *cmd_name) +{ + console_printf("Error: too many arguments for command \"%s\"\n", + cmd_name); + return SYS_EINVAL; +} + +static int +tcs34725_shell_err_unknown_arg(char *cmd_name) +{ + console_printf("Error: unknown argument \"%s\"\n", + cmd_name); + return SYS_EINVAL; +} + +static int +tcs34725_shell_err_invalid_arg(char *cmd_name) +{ + console_printf("Error: invalid argument \"%s\"\n", + cmd_name); + return SYS_EINVAL; +} + +static int +tcs34725_shell_help(void) +{ + console_printf("%s cmd [flags...]\n", tcs34725_shell_cmd_struct.sc_cmd); + console_printf("cmd:\n"); + console_printf("\tr [n_samples]\n"); + console_printf("\tgain [1|16]\n"); + console_printf("\ttime [13|101|402]\n"); + console_printf("\ten [0|1]\n"); + console_printf("\tint pin [p_num(0..255)]\n"); + console_printf("\tint on|off|clr\n"); + console_printf("\tint set [rate(0..15)] [lower(0..65535)] [upper(0..65535)]\n"); + console_printf("\tdump\n"); + + return 0; +} + +static int +tcs34725_shell_cmd_read(int argc, char **argv) +{ + uint16_t r; + uint16_t g; + uint16_t b; + uint16_t c; + uint16_t samples = 1; + long val; + int rc; + struct tcs34725 tcs34725; + + if (argc > 3) { + return tcs34725_shell_err_too_many_args(argv[1]); + } + + /* Check if more than one sample requested */ + if (argc == 3) { + if (tcs34725_shell_stol(argv[2], 1, UINT16_MAX, &val)) { + return tcs34725_shell_err_invalid_arg(argv[2]); + } + samples = (uint16_t)val; + } + + while(samples--) { + + tcs34725.cfg.gain = g_tcs34725_gain; + tcs34725.cfg.integration_time = g_tcs34725_integration_time; + + rc = tcs34725_get_rawdata(&r, &g, &b, &c, &tcs34725); + if (rc) { + console_printf("Read failed: %d\n", rc); + return rc; + } + + console_printf("r: %u g: %u b: %u c: %u \n", r, g, b, c); + } + + return 0; +} + + +static int +tcs34725_shell_cmd_gain(int argc, char **argv) +{ + long val; + uint8_t gain; + int rc; + + if (argc > 3) { + return tcs34725_shell_err_too_many_args(argv[1]); + } + + /* Display the gain */ + if (argc == 2) { + gain = tcs34725_get_gain(); + console_printf("\tgain [0: 1|1: 4|2: 16|3: 60]\n"); + console_printf("%u\n", gain); + } + + /* Update the gain */ + if (argc == 3) { + if (tcs34725_shell_stol(argv[2], 0, 3, &val)) { + return tcs34725_shell_err_invalid_arg(argv[2]); + } + /* Make sure gain is valid */ + if (val > 3) { + return tcs34725_shell_err_invalid_arg(argv[2]); + } + rc = tcs34725_set_gain(val); + if (rc) { + goto err; + } + } + + return 0; +err: + return rc; +} + + +static int +tcs34725_shell_cmd_time(int argc, char **argv) +{ + uint8_t time; + long val; + int rc; + + if (argc > 3) { + return tcs34725_shell_err_too_many_args(argv[1]); + } + + /* Display the integration time */ + if (argc == 2) { + time = tcs34725_get_integration_time(); + switch (time) { + case TCS34725_INTEGRATIONTIME_2_4MS: + console_printf("2.4\n"); + break; + case TCS34725_INTEGRATIONTIME_24MS: + console_printf("24\n"); + break; + case TCS34725_INTEGRATIONTIME_50MS: + console_printf("50\n"); + break; + case TCS34725_INTEGRATIONTIME_101MS: + console_printf("101\n"); + break; + case TCS34725_INTEGRATIONTIME_154MS: + console_printf("154\n"); + break; + case TCS34725_INTEGRATIONTIME_700MS: + console_printf("700\n"); + break; + default: + assert(0); + break; + } + } + + /* Set the integration time */ + if (argc == 3) { + if (tcs34725_shell_stol(argv[2], 0, 5, &val)) { + return tcs34725_shell_err_invalid_arg(argv[2]); + } + + switch(val) { + case 0: + time = TCS34725_INTEGRATIONTIME_2_4MS; + break; + case 1: + time = TCS34725_INTEGRATIONTIME_24MS; + break; + case 2: + time = TCS34725_INTEGRATIONTIME_50MS; + break; + case 3: + time = TCS34725_INTEGRATIONTIME_101MS; + break; + case 4: + time = TCS34725_INTEGRATIONTIME_154MS; + break; + case 5: + time = TCS34725_INTEGRATIONTIME_700MS; + break; + default: + assert(0); + } + + rc = tcs34725_set_integration_time(time); + if (rc) { + goto err; + } + } + + return 0; +err: + return rc; +} + + +static int +tcs34725_shell_cmd_int(int argc, char **argv) +{ + int rc; + int pin; + long val; + uint16_t lower; + uint16_t upper; + + if (argc > 6) { + return tcs34725_shell_err_too_many_args(argv[1]); + } + + if (argc == 2) { + rc = tcs34725_get_int_limits(&lower, &upper); + if (rc) { + return rc; + } + console_printf("Interrupt lower limit: %u upper limit: %u", + lower, upper); + return 0; + } + + /* Enable the interrupt */ + if (argc == 3 && strcmp(argv[2], "on") == 0) { + return tcs34725_enable_interrupt(1); + } + + /* Disable the interrupt */ + if (argc == 3 && strcmp(argv[2], "off") == 0) { + return tcs34725_enable_interrupt(0); + } + + /* Clear the interrupt on 'clr' */ + if (argc == 3 && strcmp(argv[2], "clr") == 0) { + return tcs34725_clear_interrupt(); + } + + /* Configure the interrupt on 'set' */ + if (argc == 3 && strcmp(argv[2], "set") == 0) { + /* Get lower threshold */ + if (tcs34725_shell_stol(argv[4], 0, UINT16_MAX, &val)) { + return tcs34725_shell_err_invalid_arg(argv[4]); + } + lower = (uint16_t)val; + /* Get upper threshold */ + if (tcs34725_shell_stol(argv[5], 0, UINT16_MAX, &val)) { + return tcs34725_shell_err_invalid_arg(argv[5]); + } + upper = (uint16_t)val; + /* Set the values */ + rc = tcs34725_set_int_limits(lower, upper); + console_printf("Configured interrupt as:\n"); + console_printf("\tlower: %u\n", lower); + console_printf("\tupper: %u\n", upper); + return rc; + } + + /* Setup INT pin on 'pin' */ + if (argc == 4 && strcmp(argv[2], "pin") == 0) { + /* Get the pin number */ + if (tcs34725_shell_stol(argv[3], 0, 0xFF, &val)) { + return tcs34725_shell_err_invalid_arg(argv[3]); + } + pin = (int)val; + /* INT is open drain, pullup is required */ + rc = hal_gpio_init_in(pin, HAL_GPIO_PULL_UP); + assert(rc == 0); + console_printf("Set pin \"%d\" to INPUT with pull up enabled\n", pin); + return 0; + } + + /* Unknown command */ + return tcs34725_shell_err_invalid_arg(argv[2]); +} + + +static int +tcs34725_shell_cmd_en(int argc, char **argv) +{ + char *endptr; + long lval; + + if (argc > 3) { + return tcs34725_shell_err_too_many_args(argv[1]); + } + + /* Display current enable state */ + if (argc == 2) { + console_printf("%u\n", tcs34725_get_enable()); + } + + /* Update the enable state */ + if (argc == 3) { + lval = strtol(argv[2], &endptr, 10); /* Base 10 */ + if (argv[2] != '\0' && *endptr == '\0' && + lval >= 0 && lval <= 1) { + tcs34725_enable(lval); + } else { + return tcs34725_shell_err_invalid_arg(argv[2]); + } + } + + return 0; +} + +static int +tcs34725_shell_cmd_dump(int argc, char **argv) +{ + uint8_t val; + + if (argc > 3) { + return tcs34725_shell_err_too_many_args(argv[1]); + } + + /* Dump all the register values for debug purposes */ + val = 0; + assert(0 == tcs34725_read8(TCS34725_REG_ENABLE, &val)); + console_printf("0x%02X (ENABLE): 0x%02X\n", TCS34725_REG_ENABLE, val); + assert(0 == tcs34725_read8(TCS34725_REG_ATIME, &val)); + console_printf("0x%02X (ATIME): 0x%02X\n", TCS34725_REG_ATIME, val); + assert(0 == tcs34725_read8(TCS34725_REG_WTIME, &val)); + console_printf("0x%02X (WTIME): 0x%02X\n", TCS34725_REG_WTIME, val); + assert(0 == tcs34725_read8(TCS34725_REG_AILTL, &val)); + console_printf("0x%02X (AILTL): 0x%02X\n", TCS34725_REG_AILTL, val); + assert(0 == tcs34725_read8(TCS34725_REG_AILTH, &val)); + console_printf("0x%02X (AILTH): 0x%02X\n", TCS34725_REG_AILTH, val); + assert(0 == tcs34725_read8(TCS34725_REG_AIHTL, &val)); + console_printf("0x%02X (AIHTL): 0x%02X\n", TCS34725_REG_AIHTL, val); + assert(0 == tcs34725_read8(TCS34725_REG_AIHTH, &val)); + console_printf("0x%02X (AIHTH): 0x%02X\n", TCS34725_REG_AIHTH, val); + assert(0 == tcs34725_read8(TCS34725_REG_PERS, &val)); + console_printf("0x%02X (PERS): 0x%02X\n", TCS34725_REG_PERS, val); + assert(0 == tcs34725_read8(TCS34725_REG_CONFIG, &val)); + console_printf("0x%02X (CONFIG): 0x%02X\n", TCS34725_REG_CONFIG, val); + assert(0 == tcs34725_read8(TCS34725_REG_CONTROL, &val)); + console_printf("0x%02X (CONTROL): 0x%02X\n", TCS34725_REG_CONTROL, val); + assert(0 == tcs34725_read8(TCS34725_REG_ID, &val)); + console_printf("0x%02X (ID): 0x%02X\n", TCS34725_REG_ID, val); + assert(0 == tcs34725_read8(TCS34725_REG_STATUS, &val)); + console_printf("0x%02X (STATUS): 0x%02X\n", TCS34725_REG_STATUS, val); + assert(0 == tcs34725_read8(TCS34725_REG_CDATAL, &val)); + console_printf("0x%02X (CDATAL): 0x%02X\n", TCS34725_REG_CDATAL, val); + assert(0 == tcs34725_read8(TCS34725_REG_CDATAH, &val)); + console_printf("0x%02X (CDATAH): 0x%02X\n", TCS34725_REG_CDATAH, val); + assert(0 == tcs34725_read8(TCS34725_REG_RDATAL, &val)); + console_printf("0x%02X (RDATAL): 0x%02X\n", TCS34725_REG_RDATAL, val); + assert(0 == tcs34725_read8(TCS34725_REG_RDATAH, &val)); + console_printf("0x%02X (RDATAH): 0x%02X\n", TCS34725_REG_RDATAH, val); + assert(0 == tcs34725_read8(TCS34725_REG_GDATAL, &val)); + console_printf("0x%02X (GDATAL): 0x%02X\n", TCS34725_REG_GDATAL, val); + assert(0 == tcs34725_read8(TCS34725_REG_GDATAH, &val)); + console_printf("0x%02X (GDATAH): 0x%02X\n", TCS34725_REG_GDATAH, val); + assert(0 == tcs34725_read8(TCS34725_REG_BDATAL, &val)); + console_printf("0x%02X (BDATAL): 0x%02X\n", TCS34725_REG_BDATAL, val); + assert(0 == tcs34725_read8(TCS34725_REG_BDATAH, &val)); + console_printf("0x%02X (BDATAH): 0x%02X\n", TCS34725_REG_BDATAH, val); + + return 0; +} + +static int +tcs34725_shell_cmd(int argc, char **argv) +{ + if (argc == 1) { + return tcs34725_shell_help(); + } + + /* Read command (get a new data sample) */ + if (argc > 1 && strcmp(argv[1], "r") == 0) { + return tcs34725_shell_cmd_read(argc, argv); + } + + /* Gain command */ + if (argc > 1 && strcmp(argv[1], "gain") == 0) { + return tcs34725_shell_cmd_gain(argc, argv); + } + + /* Integration time command */ + if (argc > 1 && strcmp(argv[1], "time") == 0) { + return tcs34725_shell_cmd_time(argc, argv); + } + + /* Enable */ + if (argc > 1 && strcmp(argv[1], "en") == 0) { + return tcs34725_shell_cmd_en(argc, argv); + } + + /* Interrupt */ + if (argc > 1 && strcmp(argv[1], "int") == 0) { + return tcs34725_shell_cmd_int(argc, argv); + } + + /* Debug */ + if (argc > 1 && strcmp(argv[1], "dumpreg") == 0) { + return tcs34725_shell_cmd_dump(argc, argv); + } + + return tcs34725_shell_err_unknown_arg(argv[1]); +} + +int +tcs34725_shell_init(void) +{ + int rc; + + rc = shell_cmd_register(&tcs34725_shell_cmd_struct); + SYSINIT_PANIC_ASSERT(rc == 0); + + return rc; +} + +#endif http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2d4f8a76/hw/drivers/sensors/tcs34725/syscfg.yml ---------------------------------------------------------------------- diff --git a/hw/drivers/sensors/tcs34725/syscfg.yml b/hw/drivers/sensors/tcs34725/syscfg.yml new file mode 100644 index 0000000..4df3b64 --- /dev/null +++ b/hw/drivers/sensors/tcs34725/syscfg.yml @@ -0,0 +1,35 @@ +# +# 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. +# + +syscfg.defs: + TCS34725_I2CADDR: + description: 'HW I2C address for the TCS34725 (0x29)' + value: 0x29 + TCS34725_I2CBUS: + description: 'I2C bus number for the TCS34725' + value: -1 + TCS34725_CLI: + description: 'Enable shell support for the TCS34725' + value: 0 + TCS34725_LOG: + description: 'Enable TCS34725 logging' + value: 0 + TCS34725_STATS: + description: 'Enable TCS34725 statistics' + value: 0 http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2d4f8a76/hw/sensor/include/sensor/color.h ---------------------------------------------------------------------- diff --git a/hw/sensor/include/sensor/color.h b/hw/sensor/include/sensor/color.h new file mode 100644 index 0000000..6f219d7 --- /dev/null +++ b/hw/sensor/include/sensor/color.h @@ -0,0 +1,51 @@ +/* + * 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 __SENSOR_COLOR_H__ +#define __SENSOR_COLOR_H__ + +#include "os/os.h" +#include "os/os_dev.h" +#include "sensor/sensor.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Data representing a singular read from a color sensor + */ +struct sensor_color_data { + uint16_t scd_r; /* Red data */ + uint16_t scd_g; /* Green data */ + uint16_t scd_b; /* Blue data */ + uint16_t scd_c; /* Clear data */ + uint16_t scd_lux; /* Lux data */ + uint16_t scd_colortemp; /* Color temp */ +} __attribute__((packed)); + +/** + * Color Sensor data is unused for this field. + */ +#define SENSOR_COLOR_DATA_UNUSED (-1) + +#ifdef __cplusplus +} +#endif + +#endif /* __SENSOR_COLOR_H__ */ http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2d4f8a76/hw/sensor/include/sensor/sensor.h ---------------------------------------------------------------------- diff --git a/hw/sensor/include/sensor/sensor.h b/hw/sensor/include/sensor/sensor.h index 813634b..9dc7cc0 100644 --- a/hw/sensor/include/sensor/sensor.h +++ b/hw/sensor/include/sensor/sensor.h @@ -72,12 +72,12 @@ typedef enum { SENSOR_TYPE_GRAVITY = (1 << 27), /* Euler Orientation Sensor */ SENSOR_TYPE_EULER = (1 << 28), + /* Color Sensor */ + SENSOR_TYPE_COLOR = (1 << 29), /* User defined sensor type 1 */ - SENSOR_TYPE_USER_DEFINED_1 = (1 << 29), + SENSOR_TYPE_USER_DEFINED_1 = (1 << 30), /* User defined sensor type 2 */ - SENSOR_TYPE_USER_DEFINED_2 = (1 << 30), - /* User defined sensor type 3 */ - SENSOR_TYPE_USER_DEFINED_3 = (1 << 31), + SENSOR_TYPE_USER_DEFINED_2 = (1 << 31), /* A selector, describes all sensors */ SENSOR_TYPE_ALL = 0xFFFFFFFF } sensor_type_t; http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/2d4f8a76/hw/sensor/src/sensor_shell.c ---------------------------------------------------------------------- diff --git a/hw/sensor/src/sensor_shell.c b/hw/sensor/src/sensor_shell.c index 291ae04..3d86beb 100644 --- a/hw/sensor/src/sensor_shell.c +++ b/hw/sensor/src/sensor_shell.c @@ -36,6 +36,7 @@ #include "sensor/light.h" #include "sensor/quat.h" #include "sensor/euler.h" +#include "sensor/color.h" #include "console/console.h" #include "shell/shell.h" #include "hal/hal_i2c.h" @@ -107,6 +108,7 @@ sensor_shell_read_listener(struct sensor *sensor, void *arg, void *data) struct sensor_light_data *sld; struct sensor_euler_data *sed; struct sensor_quat_data *sqd; + struct sensor_color_data *scd; int8_t *temperature; char tmpstr[13]; @@ -196,6 +198,29 @@ sensor_shell_read_listener(struct sensor *sensor, void *arg, void *data) console_printf("\n"); } + if (ctx->type == SENSOR_TYPE_COLOR) { + scd = (struct sensor_color_data *) data; + if (scd->scd_r != SENSOR_LIGHT_DATA_UNUSED) { + console_printf("red = %u, ", scd->scd_r); + } + if (scd->scd_g != SENSOR_LIGHT_DATA_UNUSED) { + console_printf("green = %u, ", scd->scd_g); + } + if (scd->scd_b != SENSOR_LIGHT_DATA_UNUSED) { + console_printf("blue = %u, ", scd->scd_b); + } + if (scd->scd_c != SENSOR_LIGHT_DATA_UNUSED) { + console_printf("clear = %u, ", scd->scd_c); + } + if (scd->scd_lux != SENSOR_LIGHT_DATA_UNUSED) { + console_printf("lux = %u, ", scd->scd_lux); + } + if (scd->scd_colortemp != SENSOR_LIGHT_DATA_UNUSED) { + console_printf("color temperature = %u, ", scd->scd_colortemp); + } + console_printf("\n"); + } + return (0); }
