diff --git a/app/Makefile b/app/Makefile index 8275a264..2d1933ba 100644 --- a/app/Makefile +++ b/app/Makefile @@ -39,7 +39,8 @@ SUBDIRS= \ spiffs \ cjson \ crypto \ - dhtlib + dhtlib \ + tsl2561 endif # } PDIR @@ -90,7 +91,8 @@ COMPONENTS_eagle.app.v6 = \ cjson/libcjson.a \ crypto/libcrypto.a \ dhtlib/libdhtlib.a \ - modules/libmodules.a + tsl2561/tsl2561lib.a \ + modules/libmodules.a LINKFLAGS_eagle.app.v6 = \ -L../lib \ diff --git a/app/include/user_modules.h b/app/include/user_modules.h index 18fc5cfa..cc23f794 100644 --- a/app/include/user_modules.h +++ b/app/include/user_modules.h @@ -40,6 +40,7 @@ #define LUA_USE_MODULES_RTCFIFO #define LUA_USE_MODULES_SNTP //#define LUA_USE_MODULES_BMP085 +#define LUA_USE_MODULES_TSL2561 #endif /* LUA_USE_MODULES */ diff --git a/app/modules/modules.h b/app/modules/modules.h index 176f4591..f9c4d595 100644 --- a/app/modules/modules.h +++ b/app/modules/modules.h @@ -221,6 +221,13 @@ #define ROM_MODULES_BMP085 #endif +#if defined(LUA_USE_MODULES_TSL2561) +#define MODULES_TSL2561 "tsl2561" +#define ROM_MODULES_TSL2561 \ + _ROM(MODULES_TSL2561, luaopen_tsl2561, tsl2561_map) +#else +#define ROM_MODULES_TSL2561 +#endif #define LUA_MODULES_ROM \ ROM_MODULES_GPIO \ @@ -250,5 +257,6 @@ ROM_MODULES_RTCFIFO \ ROM_MODULES_SNTP \ ROM_MODULES_BMP085 \ + ROM_MODULES_TSL2561 #endif diff --git a/app/modules/tsl2561.c b/app/modules/tsl2561.c new file mode 100644 index 00000000..a0abbb96 --- /dev/null +++ b/app/modules/tsl2561.c @@ -0,0 +1,139 @@ +/* + * tsl2561.c + * + * Created on: Aug 21, 2015 + * Author: Michael Lucas (Aeprox @github) + */ +#include "lualib.h" +#include "lauxlib.h" +#include "platform.h" +#include "auxmods.h" +#include "lrotable.h" +#include "../tsl2561/tsl2561.h" + +static uint16_t ch0; +static uint16_t ch1; + +/* Initialises the device on pins sdapin and sclpin + * Lua: status = tsl2561.init(sdapin, sclpin, address(optional), package(optional)) + */ +static int ICACHE_FLASH_ATTR tsl2561_init(lua_State* L) { + uint32_t sda; + uint32_t scl; + // check parameters + if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) { + return luaL_error(L, "wrong arg range"); + } + + sda = luaL_checkinteger(L, 1); + scl = luaL_checkinteger(L, 2); + + if (scl == 0 || sda == 0) { + return luaL_error(L, "no i2c for D0"); + } + // init I2C + uint8_t error = tsl2561Init(sda, scl); + + // Parse optional parameters + if (lua_isnumber(L, 3)) { + uint8_t address = luaL_checkinteger(L, 3); + if (!((address == TSL2561_ADDRESS_GND) || (address == TSL2561_ADDRESS_FLOAT) || (address == TSL2561_ADDRESS_VDD))) { + return luaL_error(L, "Invalid argument: address"); + } + else{ + tsl2561SetAddress(address); + } + } + if (lua_isnumber(L, 4)) { + uint8_t package = luaL_checkinteger(L, 4); + if (!((package == TSL2561_PACKAGE_T_FN_CL) || (package == TSL2561_PACKAGE_CS))) { + return luaL_error(L, "Invalid argument: package"); + } + else{ + tsl2561SetPackage(package); + } + } + lua_pushnumber(L, error); + return 1; +} +/* Sets the integration time and gain settings of the device + * Lua: status = tsl2561.settiming(integration, gain) + */ +static int ICACHE_FLASH_ATTR tsl2561_lua_settiming(lua_State* L) { + // check variables + if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) { + return luaL_error(L, "wrong arg range"); + } + uint8_t integration = luaL_checkinteger(L, 1); + if (!((integration == TSL2561_INTEGRATIONTIME_13MS) || (integration == TSL2561_INTEGRATIONTIME_101MS) || (integration == TSL2561_INTEGRATIONTIME_402MS))) { + return luaL_error(L, "Invalid argument: integration"); + } + uint8_t gain = luaL_checkinteger(L, 2); + if (!((gain == TSL2561_GAIN_16X) || (gain == TSL2561_GAIN_1X))) { + return luaL_error(L, "Invalid argument: gain"); + } + + lua_pushnumber(L, tsl2561SetTiming(integration, gain)); + return 1; +} +/* Reads sensor values from device and return calculated lux + * Lua: lux, status = tsl2561.getlux() + */ +static int ICACHE_FLASH_ATTR tsl2561_lua_calclux(lua_State* L) { + uint8_t error = tsl2561GetLuminosity(&ch0, &ch1); + if (error) { + lua_pushnumber(L, 0); + lua_pushnumber(L, error); + } else { + lua_pushnumber(L, tsl2561CalculateLux(ch0, ch1)); + lua_pushnumber(L, error); + } + return 2; +} +/* Reads sensor values from device and returns them + * Lua: ch0, ch1, status = tsl2561.getrawchannels() + */ +static int ICACHE_FLASH_ATTR tsl2561_lua_getchannels(lua_State* L) { + uint8_t error = tsl2561GetLuminosity(&ch0, &ch1); + lua_pushnumber(L, ch0); + lua_pushnumber(L, ch1); + lua_pushnumber(L, error); + + return 3; +} + +#define MIN_OPT_LEVEL 2 +#include "lrodefs.h" +const LUA_REG_TYPE tsl2561_map[] = +{ + { LSTRKEY( "settiming" ), LFUNCVAL( tsl2561_lua_settiming)}, + { LSTRKEY( "getlux" ), LFUNCVAL( tsl2561_lua_calclux )}, + { LSTRKEY( "getrawchannels" ), LFUNCVAL( tsl2561_lua_getchannels )}, + { LSTRKEY( "init" ), LFUNCVAL( tsl2561_init )}, + + { LSTRKEY( "TSL2561_OK" ), LNUMVAL( TSL2561_ERROR_OK )}, + { LSTRKEY( "TSL2561_ERROR_I2CINIT" ), LNUMVAL( TSL2561_ERROR_I2CINIT )}, + { LSTRKEY( "TSL2561_ERROR_I2CBUSY" ), LNUMVAL( TSL2561_ERROR_I2CBUSY )}, + { LSTRKEY( "TSL2561_ERROR_NOINIT" ), LNUMVAL( TSL2561_ERROR_NOINIT )}, + { LSTRKEY( "TSL2561_ERROR_LAST" ), LNUMVAL( TSL2561_ERROR_LAST )}, + + { LSTRKEY( "INTEGRATIONTIME_13MS" ), LNUMVAL( TSL2561_INTEGRATIONTIME_13MS )}, + { LSTRKEY( "INTEGRATIONTIME_101MS" ), LNUMVAL( TSL2561_INTEGRATIONTIME_101MS )}, + { LSTRKEY( "INTEGRATIONTIME_402MS" ), LNUMVAL( TSL2561_INTEGRATIONTIME_402MS )}, + { LSTRKEY( "GAIN_1X" ), LNUMVAL( TSL2561_GAIN_1X )}, + { LSTRKEY( "GAIN_16X" ), LNUMVAL( TSL2561_GAIN_16X )}, + + { LSTRKEY( "PACKAGE_CS" ), LNUMVAL( TSL2561_PACKAGE_CS )}, + { LSTRKEY( "PACKAGE_T_FN_CL" ), LNUMVAL( TSL2561_PACKAGE_T_FN_CL )}, + + { LSTRKEY( "ADDRESS_GND" ), LNUMVAL( TSL2561_ADDRESS_GND )}, + { LSTRKEY( "ADDRESS_FLOAT" ), LNUMVAL( TSL2561_ADDRESS_FLOAT )}, + { LSTRKEY( "ADDRESS_VDD" ), LNUMVAL( TSL2561_ADDRESS_VDD )}, + + { LNILKEY, LNILVAL} +}; + +LUALIB_API int luaopen_tsl2561(lua_State *L) { + LREGISTER(L, "tsl2561", tsl2561_map); + return 1; +} diff --git a/app/tsl2561/Makefile b/app/tsl2561/Makefile new file mode 100644 index 00000000..34d6e7dc --- /dev/null +++ b/app/tsl2561/Makefile @@ -0,0 +1,49 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR +GEN_LIBS = tsl2561lib.a +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +INCLUDES += -I ./include +INCLUDES += -I ../include +INCLUDES += -I ../../include +INCLUDES += -I ../libc +INCLUDES += -I ../platform +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/app/tsl2561/tsl2561.c b/app/tsl2561/tsl2561.c new file mode 100644 index 00000000..a2a1af49 --- /dev/null +++ b/app/tsl2561/tsl2561.c @@ -0,0 +1,364 @@ +/**************************************************************************/ +/*! + @file tsl2561.c + @author K. Townsend (microBuilder.eu)/ Adapted for nodeMCU by Michael Lucas (Aeprox @github) + + @brief Drivers for the TAOS TSL2561 I2C digital luminosity sensor + + @section DESCRIPTION + + The TSL2561 is a 16-bit digital luminosity sensor the approximates + the human eye's response to light. It contains one broadband + photodiode that measures visible plus infrared light (channel 0) + and one infrared photodiode (channel 1). + + @section EXAMPLE + + @code + #include "drivers/sensors/tsl2561/tsl2561.h" + ... + uint16_t broadband, ir; + uint32_t lux; + + // Initialise luminosity sensor + tsl2561Init(sda_pin, scl_pin); + + // Optional ... default setting is 400ms with no gain + // Set timing to 101ms with no gain + tsl2561SetTiming(TSL2561_INTEGRATIONTIME_101MS, TSL2561_GAIN_0X); + + // Check luminosity level and calculate lux + tsl2561GetLuminosity(&broadband, &ir); + lux = tsl2561CalculateLux(broadband, ir); + printf("Broadband: %u, IR: %u, Lux: %d %s", broadband, ir, lux, CFG_PRINTF_NEWLINE); + + @endcode + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2010, microBuilder SARL + All rights reserved. + + 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 of the copyright holders 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 ''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 HOLDER 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. + */ +/**************************************************************************/ +#include "tsl2561.h" +#include "platform.h" +#include "user_interface.h" + +static const uint32_t tsl2561_i2c_id = 0; +static bool _tsl2561Initialised = 0; +static tsl2561IntegrationTime_t _tsl2561IntegrationTime = TSL2561_INTEGRATIONTIME_402MS; +static tsl2561Gain_t _tsl2561Gain = TSL2561_GAIN_1X; +static tsl2561Address_t tsl2561Address = TSL2561_ADDRESS_FLOAT; +static tsl2561Package_t tsl2561Package = TSL2561_PACKAGE_T_FN_CL; + +/**************************************************************************/ +/*! + @brief Writes an 8 bit values over I2C + */ +/**************************************************************************/ +tsl2561Error_t tsl2561Write8(uint8_t reg, uint8_t value) { + platform_i2c_send_start(tsl2561_i2c_id); + platform_i2c_send_address(tsl2561_i2c_id, tsl2561Address, PLATFORM_I2C_DIRECTION_TRANSMITTER); + platform_i2c_send_byte(tsl2561_i2c_id, reg); + platform_i2c_send_byte(tsl2561_i2c_id, value); + platform_i2c_send_stop(tsl2561_i2c_id); + return TSL2561_ERROR_OK; +} + +/**************************************************************************/ +/*! + @brief Reads a 16 bit values over I2C + */ +/**************************************************************************/ +tsl2561Error_t tsl2561Read16(uint8_t reg, uint16_t *value) { + platform_i2c_send_start(tsl2561_i2c_id); + platform_i2c_send_address(tsl2561_i2c_id, tsl2561Address, PLATFORM_I2C_DIRECTION_TRANSMITTER); + platform_i2c_send_byte(tsl2561_i2c_id, reg); + platform_i2c_send_stop(tsl2561_i2c_id); + + platform_i2c_send_start(tsl2561_i2c_id); + platform_i2c_send_address(tsl2561_i2c_id, tsl2561Address, PLATFORM_I2C_DIRECTION_RECEIVER); + uint8_t ch_low = platform_i2c_recv_byte(tsl2561_i2c_id, 0); + platform_i2c_send_stop(tsl2561_i2c_id); + + platform_i2c_send_start(tsl2561_i2c_id); + platform_i2c_send_address(tsl2561_i2c_id, tsl2561Address, PLATFORM_I2C_DIRECTION_TRANSMITTER); + platform_i2c_send_byte(tsl2561_i2c_id, reg + 1); + platform_i2c_send_stop(tsl2561_i2c_id); + + platform_i2c_send_start(tsl2561_i2c_id); + platform_i2c_send_address(tsl2561_i2c_id, tsl2561Address, PLATFORM_I2C_DIRECTION_RECEIVER); + uint8_t ch_high = platform_i2c_recv_byte(tsl2561_i2c_id, 0); + platform_i2c_send_stop(tsl2561_i2c_id); + + // Shift values to create properly formed integer (low byte first) + *value = (ch_low | (ch_high << 8)); + + return TSL2561_ERROR_OK; +} + +/**************************************************************************/ +/*! + @brief Enables the device + */ +/**************************************************************************/ +tsl2561Error_t tsl2561Enable(void) { + if (!_tsl2561Initialised) + return TSL2561_ERROR_NOINIT; + + // Enable the device by setting the control bit to 0x03 + return tsl2561Write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, + TSL2561_CONTROL_POWERON); +} + +/**************************************************************************/ +/*! + @brief Disables the device (putting it in lower power sleep mode) + */ +/**************************************************************************/ +tsl2561Error_t tsl2561Disable(void) { + if (!_tsl2561Initialised) + return TSL2561_ERROR_NOINIT; + + // Turn the device off to save power + return tsl2561Write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, + TSL2561_CONTROL_POWEROFF); +} + +void tsl2561SetAddress(uint8_t address){ + tsl2561Address = address; + return; +} +void tsl2561SetPackage(uint8_t package){ + tsl2561Package = package; + return; +} + +/**************************************************************************/ +/*! + @brief Initialises the I2C block + */ +/**************************************************************************/ +tsl2561Error_t tsl2561Init(uint8_t sda, uint8_t scl) { + // Initialise I2C + platform_i2c_setup(tsl2561_i2c_id, sda, scl, PLATFORM_I2C_SPEED_SLOW); + + _tsl2561Initialised = 1; + + // Set default integration time and gain + tsl2561SetTiming(_tsl2561IntegrationTime, _tsl2561Gain); + + // Note: by default, the device is in power down mode on bootup + + return TSL2561_ERROR_OK; +} + +/**************************************************************************/ +/*! + @brief Sets the integration time and gain (controls sensitivity) + */ +/**************************************************************************/ +tsl2561Error_t tsl2561SetTiming(tsl2561IntegrationTime_t integration, tsl2561Gain_t gain) { + if (!_tsl2561Initialised) + return TSL2561_ERROR_NOINIT; + + tsl2561Error_t error = TSL2561_ERROR_OK; + + // Enable the device by setting the control bit to 0x03 + error = tsl2561Enable(); + if (error) + return error; + + // set timing and gain on device + error = tsl2561Write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, integration | gain); + if (error) + return error; + + // Update value placeholders + _tsl2561IntegrationTime = integration; + _tsl2561Gain = gain; + + // Turn the device off to save power + error = tsl2561Disable(); + if (error) + return error; + + return error; +} + +/**************************************************************************/ +/*! + @brief Reads the luminosity on both channels from the TSL2561 + */ +/**************************************************************************/ +tsl2561Error_t tsl2561GetLuminosity(uint16_t *broadband, uint16_t *ir) { + if (!_tsl2561Initialised) + return TSL2561_ERROR_NOINIT; + + tsl2561Error_t error = TSL2561_ERROR_OK; + + // Enable the device by setting the control bit to 0x03 + error = tsl2561Enable(); + if (error) + return error; + + // Wait x ms for ADC to complete + switch (_tsl2561IntegrationTime) { + case TSL2561_INTEGRATIONTIME_13MS: + os_delay_us(14000); //systickDelay(14); + break; + case TSL2561_INTEGRATIONTIME_101MS: + os_delay_us(102000); //systickDelay(102); + break; + default: + os_delay_us(404000); //systickDelay(404); + break; + } + + // Reads two byte value from channel 0 (visible + infrared) + error = tsl2561Read16( + TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW, broadband); + if (error) + return error; + + // Reads two byte value from channel 1 (infrared) + error = tsl2561Read16( + TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW, ir); + if (error) + return error; + + // Turn the device off to save power + error = tsl2561Disable(); + if (error) + return error; + + return error; +} + +/**************************************************************************/ +/*! + @brief Calculates LUX from the supplied ch0 (broadband) and ch1 + (IR) readings + */ +/**************************************************************************/ +uint32_t tsl2561CalculateLux(uint16_t ch0, uint16_t ch1) { + unsigned long chScale; + unsigned long channel1; + unsigned long channel0; + + switch (_tsl2561IntegrationTime) { + case TSL2561_INTEGRATIONTIME_13MS: + chScale = TSL2561_LUX_CHSCALE_TINT0; + break; + case TSL2561_INTEGRATIONTIME_101MS: + chScale = TSL2561_LUX_CHSCALE_TINT1; + break; + default: // No scaling ... integration time = 402ms + chScale = (1 << TSL2561_LUX_CHSCALE); + break; + } + + // Scale for gain (1x or 16x) + if (!_tsl2561Gain) + chScale = chScale << 4; + + // scale the channel values + channel0 = (ch0 * chScale) >> TSL2561_LUX_CHSCALE; + channel1 = (ch1 * chScale) >> TSL2561_LUX_CHSCALE; + + // find the ratio of the channel values (Channel1/Channel0) + unsigned long ratio1 = 0; + if (channel0 != 0) + ratio1 = (channel1 << (TSL2561_LUX_RATIOSCALE + 1)) / channel0; + + // round the ratio value + unsigned long ratio = (ratio1 + 1) >> 1; + + unsigned int b, m; + + if (tsl2561Package == TSL2561_PACKAGE_CS){ + if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1C)) { + b = TSL2561_LUX_B1C; + m = TSL2561_LUX_M1C; + } else if (ratio <= TSL2561_LUX_K2C) { + b = TSL2561_LUX_B2C; + m = TSL2561_LUX_M2C; + } else if (ratio <= TSL2561_LUX_K3C) { + b = TSL2561_LUX_B3C; + m = TSL2561_LUX_M3C; + } else if (ratio <= TSL2561_LUX_K4C) { + b = TSL2561_LUX_B4C; + m = TSL2561_LUX_M4C; + } else if (ratio <= TSL2561_LUX_K5C) { + b = TSL2561_LUX_B5C; + m = TSL2561_LUX_M5C; + } else if (ratio <= TSL2561_LUX_K6C) { + b = TSL2561_LUX_B6C; + m = TSL2561_LUX_M6C; + } else if (ratio <= TSL2561_LUX_K7C) { + b = TSL2561_LUX_B7C; + m = TSL2561_LUX_M7C; + } else if (ratio > TSL2561_LUX_K8C) { + b = TSL2561_LUX_B8C; + m = TSL2561_LUX_M8C; + } + } + else{ + if ((ratio >= 0) && (ratio <= TSL2561_LUX_K1T)) + { b=TSL2561_LUX_B1T; m=TSL2561_LUX_M1T;} + else if (ratio <= TSL2561_LUX_K2T) + { b=TSL2561_LUX_B2T; m=TSL2561_LUX_M2T;} + else if (ratio <= TSL2561_LUX_K3T) + { b=TSL2561_LUX_B3T; m=TSL2561_LUX_M3T;} + else if (ratio <= TSL2561_LUX_K4T) + { b=TSL2561_LUX_B4T; m=TSL2561_LUX_M4T;} + else if (ratio <= TSL2561_LUX_K5T) + { b=TSL2561_LUX_B5T; m=TSL2561_LUX_M5T;} + else if (ratio <= TSL2561_LUX_K6T) + { b=TSL2561_LUX_B6T; m=TSL2561_LUX_M6T;} + else if (ratio <= TSL2561_LUX_K7T) + { b=TSL2561_LUX_B7T; m=TSL2561_LUX_M7T;} + else if (ratio > TSL2561_LUX_K8T) + { b=TSL2561_LUX_B8T; m=TSL2561_LUX_M8T;} + } + + unsigned long temp; + temp = ((channel0 * b) - (channel1 * m)); + + // do not allow negative lux value + if (temp < 0) + temp = 0; + + // round lsb (2^(LUX_SCALE-1)) + temp += (1 << (TSL2561_LUX_LUXSCALE - 1)); + + // strip off fractional portion + uint32_t lux = temp >> TSL2561_LUX_LUXSCALE; + + // Signal I2C had no errors + return lux; +} diff --git a/app/tsl2561/tsl2561.h b/app/tsl2561/tsl2561.h new file mode 100644 index 00000000..dd166432 --- /dev/null +++ b/app/tsl2561/tsl2561.h @@ -0,0 +1,176 @@ +/**************************************************************************/ +/*! + @file tsl2561.h + @author K. Townsend (microBuilder.eu) / Adapted for nodeMCU by Michael Lucas (Aeprox @github) + + @section LICENSE + + Software License Agreement (BSD License) + + Copyright (c) 2010, microBuilder SARL + All rights reserved. + + 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 of the copyright holders 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 ''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 HOLDER 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. +*/ +/**************************************************************************/ +#include "c_types.h" + +#ifndef _TSL2561_H_ +#define _TSL2561_H_ + +#define TSL2561_READBIT (0x01) + +#define TSL2561_COMMAND_BIT (0x80) // Must be 1 +#define TSL2561_CLEAR_BIT (0x40) // Clears any pending interrupt (write 1 to clear) +#define TSL2561_WORD_BIT (0x20) // 1 = read/write word (rather than byte) +#define TSL2561_BLOCK_BIT (0x10) // 1 = using block read/write + +#define TSL2561_CONTROL_POWERON (0x03) +#define TSL2561_CONTROL_POWEROFF (0x00) + +#define TSL2561_LUX_LUXSCALE (14) // Scale by 2^14 +#define TSL2561_LUX_RATIOSCALE (9) // Scale ratio by 2^9 +#define TSL2561_LUX_CHSCALE (10) // Scale channel values by 2^10 +#define TSL2561_LUX_CHSCALE_TINT0 (0x7517) // 322/11 * 2^TSL2561_LUX_CHSCALE +#define TSL2561_LUX_CHSCALE_TINT1 (0x0FE7) // 322/81 * 2^TSL2561_LUX_CHSCALE + +// T, FN and CL package values +#define TSL2561_LUX_K1T (0x0040) // 0.125 * 2^RATIO_SCALE +#define TSL2561_LUX_B1T (0x01f2) // 0.0304 * 2^LUX_SCALE +#define TSL2561_LUX_M1T (0x01be) // 0.0272 * 2^LUX_SCALE +#define TSL2561_LUX_K2T (0x0080) // 0.250 * 2^RATIO_SCALE +#define TSL2561_LUX_B2T (0x0214) // 0.0325 * 2^LUX_SCALE +#define TSL2561_LUX_M2T (0x02d1) // 0.0440 * 2^LUX_SCALE +#define TSL2561_LUX_K3T (0x00c0) // 0.375 * 2^RATIO_SCALE +#define TSL2561_LUX_B3T (0x023f) // 0.0351 * 2^LUX_SCALE +#define TSL2561_LUX_M3T (0x037b) // 0.0544 * 2^LUX_SCALE +#define TSL2561_LUX_K4T (0x0100) // 0.50 * 2^RATIO_SCALE +#define TSL2561_LUX_B4T (0x0270) // 0.0381 * 2^LUX_SCALE +#define TSL2561_LUX_M4T (0x03fe) // 0.0624 * 2^LUX_SCALE +#define TSL2561_LUX_K5T (0x0138) // 0.61 * 2^RATIO_SCALE +#define TSL2561_LUX_B5T (0x016f) // 0.0224 * 2^LUX_SCALE +#define TSL2561_LUX_M5T (0x01fc) // 0.0310 * 2^LUX_SCALE +#define TSL2561_LUX_K6T (0x019a) // 0.80 * 2^RATIO_SCALE +#define TSL2561_LUX_B6T (0x00d2) // 0.0128 * 2^LUX_SCALE +#define TSL2561_LUX_M6T (0x00fb) // 0.0153 * 2^LUX_SCALE +#define TSL2561_LUX_K7T (0x029a) // 1.3 * 2^RATIO_SCALE +#define TSL2561_LUX_B7T (0x0018) // 0.00146 * 2^LUX_SCALE +#define TSL2561_LUX_M7T (0x0012) // 0.00112 * 2^LUX_SCALE +#define TSL2561_LUX_K8T (0x029a) // 1.3 * 2^RATIO_SCALE +#define TSL2561_LUX_B8T (0x0000) // 0.000 * 2^LUX_SCALE +#define TSL2561_LUX_M8T (0x0000) // 0.000 * 2^LUX_SCALE + +// CS package values +#define TSL2561_LUX_K1C (0x0043) // 0.130 * 2^RATIO_SCALE +#define TSL2561_LUX_B1C (0x0204) // 0.0315 * 2^LUX_SCALE +#define TSL2561_LUX_M1C (0x01ad) // 0.0262 * 2^LUX_SCALE +#define TSL2561_LUX_K2C (0x0085) // 0.260 * 2^RATIO_SCALE +#define TSL2561_LUX_B2C (0x0228) // 0.0337 * 2^LUX_SCALE +#define TSL2561_LUX_M2C (0x02c1) // 0.0430 * 2^LUX_SCALE +#define TSL2561_LUX_K3C (0x00c8) // 0.390 * 2^RATIO_SCALE +#define TSL2561_LUX_B3C (0x0253) // 0.0363 * 2^LUX_SCALE +#define TSL2561_LUX_M3C (0x0363) // 0.0529 * 2^LUX_SCALE +#define TSL2561_LUX_K4C (0x010a) // 0.520 * 2^RATIO_SCALE +#define TSL2561_LUX_B4C (0x0282) // 0.0392 * 2^LUX_SCALE +#define TSL2561_LUX_M4C (0x03df) // 0.0605 * 2^LUX_SCALE +#define TSL2561_LUX_K5C (0x014d) // 0.65 * 2^RATIO_SCALE +#define TSL2561_LUX_B5C (0x0177) // 0.0229 * 2^LUX_SCALE +#define TSL2561_LUX_M5C (0x01dd) // 0.0291 * 2^LUX_SCALE +#define TSL2561_LUX_K6C (0x019a) // 0.80 * 2^RATIO_SCALE +#define TSL2561_LUX_B6C (0x0101) // 0.0157 * 2^LUX_SCALE +#define TSL2561_LUX_M6C (0x0127) // 0.0180 * 2^LUX_SCALE +#define TSL2561_LUX_K7C (0x029a) // 1.3 * 2^RATIO_SCALE +#define TSL2561_LUX_B7C (0x0037) // 0.00338 * 2^LUX_SCALE +#define TSL2561_LUX_M7C (0x002b) // 0.00260 * 2^LUX_SCALE +#define TSL2561_LUX_K8C (0x029a) // 1.3 * 2^RATIO_SCALE +#define TSL2561_LUX_B8C (0x0000) // 0.000 * 2^LUX_SCALE +#define TSL2561_LUX_M8C (0x0000) // 0.000 * 2^LUX_SCALE + +enum +{ + TSL2561_REGISTER_CONTROL = 0x00, + TSL2561_REGISTER_TIMING = 0x01, + TSL2561_REGISTER_THRESHHOLDL_LOW = 0x02, + TSL2561_REGISTER_THRESHHOLDL_HIGH = 0x03, + TSL2561_REGISTER_THRESHHOLDH_LOW = 0x04, + TSL2561_REGISTER_THRESHHOLDH_HIGH = 0x05, + TSL2561_REGISTER_INTERRUPT = 0x06, + TSL2561_REGISTER_CRC = 0x08, + TSL2561_REGISTER_ID = 0x0A, + TSL2561_REGISTER_CHAN0_LOW = 0x0C, + TSL2561_REGISTER_CHAN0_HIGH = 0x0D, + TSL2561_REGISTER_CHAN1_LOW = 0x0E, + TSL2561_REGISTER_CHAN1_HIGH = 0x0F +}; + +typedef enum +{ + TSL2561_INTEGRATIONTIME_13MS = 0x00, // 13.7ms + TSL2561_INTEGRATIONTIME_101MS = 0x01, // 101ms + TSL2561_INTEGRATIONTIME_402MS = 0x02 // 402ms +} +tsl2561IntegrationTime_t; + +typedef enum +{ + TSL2561_GAIN_1X = 0x00, // No gain + TSL2561_GAIN_16X = 0x10, // 16x gain +} +tsl2561Gain_t; + +typedef enum +{ + TSL2561_ERROR_OK = 0, // Everything executed normally + TSL2561_ERROR_I2CINIT, // Unable to initialise I2C + TSL2561_ERROR_I2CBUSY, // I2C already in use + TSL2561_ERROR_NOINIT, // call init first + TSL2561_ERROR_LAST +} +tsl2561Error_t; + +// GND=>0x29, float=>0x39 or VDD=>0x49 +typedef enum +{ + TSL2561_ADDRESS_GND = 0x29, + TSL2561_ADDRESS_FLOAT = 0x39, + TSL2561_ADDRESS_VDD = 0x49, + +} +tsl2561Address_t; + +// Lux calculations differ slightly for CS package +typedef enum +{ + TSL2561_PACKAGE_CS = 0, + TSL2561_PACKAGE_T_FN_CL +}tsl2561Package_t; + +tsl2561Error_t tsl2561Init(uint8_t sda, uint8_t scl); +tsl2561Error_t tsl2561SetTiming(tsl2561IntegrationTime_t integration, tsl2561Gain_t gain); +tsl2561Error_t tsl2561GetLuminosity (uint16_t *broadband, uint16_t *ir); +uint32_t tsl2561CalculateLux(uint16_t ch0, uint16_t ch1); +void tsl2561SetAddress(uint8_t address); +void tsl2561SetPackage(uint8_t package); +#endif + +