diff --git a/I2CDEVICES.md b/I2CDEVICES.md index cb42d97a4..008f16c99 100644 --- a/I2CDEVICES.md +++ b/I2CDEVICES.md @@ -69,4 +69,6 @@ Index | Define | Driver | Device | Address(es) | Description 45 | USE_HDC1080 | xsns_65 | HDC1080 | 0x40 | Temperature and Humidity sensor 46 | USE_IAQ | xsns_66 | IAQ | 0x5a | Air quality sensor 47 | USE_DISPLAY_SEVENSEG| xdsp_11 | HT16K33 | 0x70 - 0x77 | Seven segment LED - 48 | USE_AS3935 | xsns_67 | AS3935 | 0x03 | Franklin Lightning Sensor \ No newline at end of file + 48 | USE_AS3935 | xsns_67 | AS3935 | 0x03 | Franklin Lightning Sensor + 49 | USE_VEML6075 | xsns_68 | VEML6075 | 0x10 | UVA/UVB/UVINDEX Sensor + 50 | USE_VEML7700 | xsns_69 | VEML7700 | 0x10 | Ambient light intensity sensor \ No newline at end of file diff --git a/lib/Adafruit_BusIO/.travis.yml b/lib/Adafruit_BusIO/.travis.yml new file mode 100644 index 000000000..40754054e --- /dev/null +++ b/lib/Adafruit_BusIO/.travis.yml @@ -0,0 +1,23 @@ +language: c +sudo: false +cache: + directories: + - ~/arduino_ide + - ~/.arduino15/packages/ +git: + depth: false + quiet: true +env: + global: + - PRETTYNAME="Adafruit BusIO Library" + +before_install: + - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh) + +script: + - build_main_platforms + +# Generate and deploy documentation +after_success: + - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/library_check.sh) + - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/doxy_gen_and_deploy.sh) \ No newline at end of file diff --git a/lib/Adafruit_BusIO/Adafruit_BusIO_Register.cpp b/lib/Adafruit_BusIO/Adafruit_BusIO_Register.cpp new file mode 100644 index 000000000..2c2b22e00 --- /dev/null +++ b/lib/Adafruit_BusIO/Adafruit_BusIO_Register.cpp @@ -0,0 +1,258 @@ +#include + +/*! + * @brief Create a register we access over an I2C Device (which defines the bus and address) + * @param i2cdevice The I2CDevice to use for underlying I2C access + * @param reg_addr The address pointer value for the I2C/SMBus register, can be 8 or 16 bits + * @param width The width of the register data itself, defaults to 1 byte + * @param bitorder The bit order of the register (used when width is > 1), defaults to LSBFIRST + * @param address_width The width of the register address itself, defaults to 1 byte + */ +Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice, uint16_t reg_addr, + uint8_t width, uint8_t bitorder, uint8_t address_width) { + _i2cdevice = i2cdevice; + _spidevice = NULL; + _addrwidth = address_width; + _address = reg_addr; + _bitorder = bitorder; + _width = width; +} + +/*! + * @brief Create a register we access over an SPI Device (which defines the bus and CS pin) + * @param spidevice The SPIDevice to use for underlying I2C access + * @param reg_addr The address pointer value for the I2C/SMBus register, can be 8 or 16 bits + * @param type The method we use to read/write data to SPI (which is not as well defined as I2C) + * @param width The width of the register data itself, defaults to 1 byte + * @param bitorder The bit order of the register (used when width is > 1), defaults to LSBFIRST + * @param address_width The width of the register address itself, defaults to 1 byte + */ +Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_SPIDevice *spidevice, uint16_t reg_addr, + Adafruit_BusIO_SPIRegType type, + uint8_t width, uint8_t bitorder, uint8_t address_width) { + _spidevice = spidevice; + _spiregtype = type; + _i2cdevice = NULL; + _addrwidth = address_width; + _address = reg_addr; + _bitorder = bitorder; + _width = width; +} + +/*! + * @brief Create a register we access over an I2C or SPI Device. This is a handy function because we + * can pass in NULL for the unused interface, allowing libraries to mass-define all the registers + * @param i2cdevice The I2CDevice to use for underlying I2C access, if NULL we use SPI + * @param spidevice The SPIDevice to use for underlying I2C access, if NULL we use I2C + * @param reg_addr The address pointer value for the I2C/SMBus register, can be 8 or 16 bits + * @param type The method we use to read/write data to SPI (which is not as well defined as I2C) + * @param width The width of the register data itself, defaults to 1 byte + * @param bitorder The bit order of the register (used when width is > 1), defaults to LSBFIRST + * @param address_width The width of the register address itself, defaults to 1 byte + */ +Adafruit_BusIO_Register::Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice, Adafruit_SPIDevice *spidevice, + Adafruit_BusIO_SPIRegType type, uint16_t reg_addr, + uint8_t width, uint8_t bitorder, uint8_t address_width) { + _spidevice = spidevice; + _i2cdevice = i2cdevice; + _spiregtype = type; + _addrwidth = address_width; + _address = reg_addr; + _bitorder = bitorder; + _width = width; +} + + +/*! + * @brief Write a buffer of data to the register location + * @param buffer Pointer to data to write + * @param len Number of bytes to write + * @return True on successful write (only really useful for I2C as SPI is uncheckable) + */ +bool Adafruit_BusIO_Register::write(uint8_t *buffer, uint8_t len) { + + uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF), (uint8_t)(_address>>8)}; + + if (_i2cdevice) { + return _i2cdevice->write(buffer, len, true, addrbuffer, _addrwidth); + } + if (_spidevice) { + if (_spiregtype == ADDRBIT8_HIGH_TOREAD) { + addrbuffer[0] &= ~0x80; + } + return _spidevice->write( buffer, len, addrbuffer, _addrwidth); + } + return false; +} + +/*! + * @brief Write up to 4 bytes of data to the register location + * @param value Data to write + * @param numbytes How many bytes from 'value' to write + * @return True on successful write (only really useful for I2C as SPI is uncheckable) + */ +bool Adafruit_BusIO_Register::write(uint32_t value, uint8_t numbytes) { + if (numbytes == 0) { + numbytes = _width; + } + if (numbytes > 4) { + return false; + } + + for (int i=0; i>= 8; + } + return write(_buffer, numbytes); +} + +/*! + * @brief Read data from the register location. This does not do any error checking! + * @return Returns 0xFFFFFFFF on failure, value otherwise + */ +uint32_t Adafruit_BusIO_Register::read(void) { + if (! read(_buffer, _width)) { + return -1; + } + + uint32_t value = 0; + + for (int i=0; i < _width; i++) { + value <<= 8; + if (_bitorder == LSBFIRST) { + value |= _buffer[_width-i-1]; + } else { + value |= _buffer[i]; + } + } + + return value; +} + + +/*! + * @brief Read a buffer of data from the register location + * @param buffer Pointer to data to read into + * @param len Number of bytes to read + * @return True on successful write (only really useful for I2C as SPI is uncheckable) + */ +bool Adafruit_BusIO_Register::read(uint8_t *buffer, uint8_t len) { + uint8_t addrbuffer[2] = {(uint8_t)(_address & 0xFF), (uint8_t)(_address>>8)}; + + if (_i2cdevice) { + return _i2cdevice->write_then_read(addrbuffer, _addrwidth, buffer, len); + } + if (_spidevice) { + if (_spiregtype == ADDRBIT8_HIGH_TOREAD) { + addrbuffer[0] |= 0x80; + } + return _spidevice->write_then_read(addrbuffer, _addrwidth, buffer, len); + } + return false; +} + +/*! + * @brief Read 2 bytes of data from the register location + * @param value Pointer to uint16_t variable to read into + * @return True on successful write (only really useful for I2C as SPI is uncheckable) + */ +bool Adafruit_BusIO_Register::read(uint16_t *value) { + if (! read(_buffer, 2)) { + return false; + } + + if (_bitorder == LSBFIRST) { + *value = _buffer[1]; + *value <<= 8; + *value |= _buffer[0]; + } else { + *value = _buffer[0]; + *value <<= 8; + *value |= _buffer[1]; + } + return true; +} + +/*! + * @brief Read 1 byte of data from the register location + * @param value Pointer to uint8_t variable to read into + * @return True on successful write (only really useful for I2C as SPI is uncheckable) + */ +bool Adafruit_BusIO_Register::read(uint8_t *value) { + if (! read(_buffer, 1)) { + return false; + } + + *value = _buffer[0]; + return true; +} + +/*! + * @brief Pretty printer for this register + * @param s The Stream to print to, defaults to &Serial + */ +void Adafruit_BusIO_Register::print(Stream *s) { + uint32_t val = read(); + s->print("0x"); s->print(val, HEX); +} + +/*! + * @brief Pretty printer for this register + * @param s The Stream to print to, defaults to &Serial + */ +void Adafruit_BusIO_Register::println(Stream *s) { + print(s); + s->println(); +} + + +/*! + * @brief Create a slice of the register that we can address without touching other bits + * @param reg The Adafruit_BusIO_Register which defines the bus/register + * @param bits The number of bits wide we are slicing + * @param shift The number of bits that our bit-slice is shifted from LSB + */ +Adafruit_BusIO_RegisterBits::Adafruit_BusIO_RegisterBits(Adafruit_BusIO_Register *reg, uint8_t bits, uint8_t shift) { + _register = reg; + _bits = bits; + _shift = shift; +} + +/*! + * @brief Read 4 bytes of data from the register + * @return data The 4 bytes to read + */ +uint32_t Adafruit_BusIO_RegisterBits::read(void) { + uint32_t val = _register->read(); + val >>= _shift; + return val & ((1 << (_bits)) - 1); +} + + +/*! + * @brief Write 4 bytes of data to the register + * @param data The 4 bytes to write + */ +void Adafruit_BusIO_RegisterBits::write(uint32_t data) { + uint32_t val = _register->read(); + + // mask off the data before writing + uint32_t mask = (1 << (_bits)) - 1; + data &= mask; + + mask <<= _shift; + val &= ~mask; // remove the current data at that spot + val |= data << _shift; // and add in the new data + + _register->write(val, _register->width()); +} + +/*! + * @brief The width of the register data, helpful for doing calculations + * @returns The data width used when initializing the register + */ +uint8_t Adafruit_BusIO_Register::width(void) { return _width; } diff --git a/lib/Adafruit_BusIO/Adafruit_BusIO_Register.h b/lib/Adafruit_BusIO/Adafruit_BusIO_Register.h new file mode 100644 index 000000000..45ae1e146 --- /dev/null +++ b/lib/Adafruit_BusIO/Adafruit_BusIO_Register.h @@ -0,0 +1,69 @@ +#include +#include +#include + + +#ifndef Adafruit_BusIO_Register_h +#define Adafruit_BusIO_Register_h + +typedef enum _Adafruit_BusIO_SPIRegType { + ADDRBIT8_HIGH_TOREAD = 0, +} Adafruit_BusIO_SPIRegType; + +/*! + * @brief The class which defines a device register (a location to read/write data from) + */ +class Adafruit_BusIO_Register { + public: + Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice, uint16_t reg_addr, + uint8_t width=1, uint8_t bitorder=LSBFIRST, + uint8_t address_width=1); + Adafruit_BusIO_Register(Adafruit_SPIDevice *spidevice, uint16_t reg_addr, + Adafruit_BusIO_SPIRegType type, + uint8_t width=1, uint8_t bitorder=LSBFIRST, + uint8_t address_width=1); + + Adafruit_BusIO_Register(Adafruit_I2CDevice *i2cdevice, + Adafruit_SPIDevice *spidevice, + Adafruit_BusIO_SPIRegType type, + uint16_t reg_addr, + uint8_t width=1, uint8_t bitorder=LSBFIRST, + uint8_t address_width=1); + + bool read(uint8_t *buffer, uint8_t len); + bool read(uint8_t *value); + bool read(uint16_t *value); + uint32_t read(void); + bool write(uint8_t *buffer, uint8_t len); + bool write(uint32_t value, uint8_t numbytes=0); + + uint8_t width(void); + + void print(Stream *s=&Serial); + void println(Stream *s=&Serial); + + private: + Adafruit_I2CDevice *_i2cdevice; + Adafruit_SPIDevice *_spidevice; + Adafruit_BusIO_SPIRegType _spiregtype; + uint16_t _address; + uint8_t _width, _addrwidth, _bitorder; + uint8_t _buffer[4]; // we wont support anything larger than uint32 for non-buffered read +}; + + +/*! + * @brief The class which defines a slice of bits from within a device register (a location to read/write data from) + */ +class Adafruit_BusIO_RegisterBits { + public: + Adafruit_BusIO_RegisterBits(Adafruit_BusIO_Register *reg, uint8_t bits, uint8_t shift); + void write(uint32_t value); + uint32_t read(void); + private: + Adafruit_BusIO_Register *_register; + uint8_t _bits, _shift; +}; + + +#endif //BusIO_Register_h diff --git a/lib/Adafruit_BusIO/Adafruit_I2CDevice.cpp b/lib/Adafruit_BusIO/Adafruit_I2CDevice.cpp new file mode 100644 index 000000000..7813a6df7 --- /dev/null +++ b/lib/Adafruit_BusIO/Adafruit_I2CDevice.cpp @@ -0,0 +1,213 @@ +#include +#include + +//#define DEBUG_SERIAL Serial + +/*! + * @brief Create an I2C device at a given address + * @param addr The 7-bit I2C address for the device + * @param theWire The I2C bus to use, defaults to &Wire + */ +Adafruit_I2CDevice::Adafruit_I2CDevice(uint8_t addr, TwoWire *theWire) { + _addr = addr; + _wire = theWire; + _begun = false; +#ifdef ARDUINO_ARCH_SAMD + _maxBufferSize = 250; // as defined in Wire.h's RingBuffer +#else + _maxBufferSize = 32; +#endif +} + +/*! + * @brief Initializes and does basic address detection + * @param addr_detect Whether we should attempt to detect the I2C address with a scan. + * 99% of sensors/devices don't mind but once in a while, they spaz on a scan! + * @return True if I2C initialized and a device with the addr found + */ +bool Adafruit_I2CDevice::begin(bool addr_detect) { + _wire->begin(); + _begun = true; + + if (addr_detect) { + return detected(); + } + return true; +} + + +/*! + * @brief Scans I2C for the address - note will give a false-positive + * if there's no pullups on I2C + * @return True if I2C initialized and a device with the addr found + */ +bool Adafruit_I2CDevice::detected(void) { + // Init I2C if not done yet + if (!_begun && !begin()) { + return false; + } + + // A basic scanner, see if it ACK's + _wire->beginTransmission(_addr); + if (_wire->endTransmission () == 0) { + return true; + } + return false; +} + +/*! + * @brief Write a buffer or two to the I2C device. Cannot be more than maxBufferSize() bytes. + * @param buffer Pointer to buffer of data to write + * @param len Number of bytes from buffer to write + * @param prefix_buffer Pointer to optional array of data to write before buffer. + * Cannot be more than maxBufferSize() bytes. + * @param prefix_len Number of bytes from prefix buffer to write + * @param stop Whether to send an I2C STOP signal on write + * @return True if write was successful, otherwise false. + */ +bool Adafruit_I2CDevice::write(uint8_t *buffer, size_t len, bool stop, uint8_t *prefix_buffer, size_t prefix_len) { + if ((len+prefix_len) > maxBufferSize()) { + // currently not guaranteed to work if more than 32 bytes! + // we will need to find out if some platforms have larger + // I2C buffer sizes :/ +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println(F("\tI2CDevice could not write such a large buffer")); +#endif + return false; + } + + _wire->beginTransmission(_addr); + + // Write the prefix data (usually an address) + if ((prefix_len != 0) && (prefix_buffer != NULL)) { + if (_wire->write(prefix_buffer, prefix_len) != prefix_len) { +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println(F("\tI2CDevice failed to write")); +#endif + return false; + } + } + + // Write the data itself + if (_wire->write(buffer, len) != len) { +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println(F("\tI2CDevice failed to write")); +#endif + return false; + } + +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.print(F("\tI2CDevice Wrote: ")); + if ((prefix_len != 0) && (prefix_buffer != NULL)) { + for (uint16_t i=0; iendTransmission(stop) == 0) { +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println("Sent!"); +#endif + return true; + } else { +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println("Failed to send!"); +#endif + return false; + } +} + + +/*! + * @brief Read from I2C into a buffer from the I2C device. + * Cannot be more than maxBufferSize() bytes. + * @param buffer Pointer to buffer of data to read into + * @param len Number of bytes from buffer to read. + * @param stop Whether to send an I2C STOP signal on read + * @return True if read was successful, otherwise false. + */ +bool Adafruit_I2CDevice::read(uint8_t *buffer, size_t len, bool stop) { + if (len > maxBufferSize()) { + // currently not guaranteed to work if more than 32 bytes! + // we will need to find out if some platforms have larger + // I2C buffer sizes :/ +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println(F("\tI2CDevice could not read such a large buffer")); +#endif + return false; + } + + size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len, (uint8_t)stop); + if (recv != len) { + // Not enough data available to fulfill our obligation! +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.print(F("\tI2CDevice did not receive enough data: ")); + DEBUG_SERIAL.println(recv); +#endif + return false; + } + + for (uint16_t i=0; iread(); + } + +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.print(F("\tI2CDevice Read: ")); + for (uint16_t i=0; i + +#ifndef Adafruit_I2CDevice_h +#define Adafruit_I2CDevice_h + +///< The class which defines how we will talk to this device over I2C +class Adafruit_I2CDevice { + public: + Adafruit_I2CDevice(uint8_t addr, TwoWire *theWire=&Wire); + uint8_t address(void); + bool begin(bool addr_detect=true); + bool detected(void); + + bool read(uint8_t *buffer, size_t len, bool stop=true); + bool write(uint8_t *buffer, size_t len, bool stop=true, uint8_t *prefix_buffer=NULL, size_t prefix_len=0); + bool write_then_read(uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len, bool stop=false); + + /*! @brief How many bytes we can read in a transaction + * @return The size of the Wire receive/transmit buffer */ + uint16_t maxBufferSize() { return _maxBufferSize; } + + private: + uint8_t _addr; + TwoWire *_wire; + bool _begun; + uint16_t _maxBufferSize; +}; + +#endif // Adafruit_I2CDevice_h diff --git a/lib/Adafruit_BusIO/Adafruit_I2CRegister.h b/lib/Adafruit_BusIO/Adafruit_I2CRegister.h new file mode 100644 index 000000000..703e93b76 --- /dev/null +++ b/lib/Adafruit_BusIO/Adafruit_I2CRegister.h @@ -0,0 +1,8 @@ +#include "Adafruit_BusIO_Register.h" +#ifndef _ADAFRUIT_I2C_REGISTER_H_ +#define _ADAFRUIT_I2C_REGISTER_H_ + +typedef Adafruit_BusIO_Register Adafruit_I2CRegister; +typedef Adafruit_BusIO_RegisterBits Adafruit_I2CRegisterBits; + +#endif diff --git a/lib/Adafruit_BusIO/Adafruit_SPIDevice.cpp b/lib/Adafruit_BusIO/Adafruit_SPIDevice.cpp new file mode 100644 index 000000000..1d599bb11 --- /dev/null +++ b/lib/Adafruit_BusIO/Adafruit_SPIDevice.cpp @@ -0,0 +1,301 @@ +#include +#include + +//#define DEBUG_SERIAL Serial + +/*! + * @brief Create an SPI device with the given CS pin and settins + * @param cspin The arduino pin number to use for chip select + * @param freq The SPI clock frequency to use, defaults to 1MHz + * @param dataOrder The SPI data order to use for bits within each byte, defaults to SPI_BITORDER_MSBFIRST + * @param dataMode The SPI mode to use, defaults to SPI_MODE0 + * @param theSPI The SPI bus to use, defaults to &theSPI + */ +Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, uint32_t freq, BitOrder dataOrder, uint8_t dataMode, SPIClass *theSPI) { + _cs = cspin; + _sck = _mosi = _miso = -1; + _spi = theSPI; + _begun = false; + _spiSetting = new SPISettings(freq, dataOrder, dataMode); + _freq = freq; + _dataOrder = dataOrder; + _dataMode = dataMode; +} + +/*! + * @brief Create an SPI device with the given CS pin and settins + * @param cspin The arduino pin number to use for chip select + * @param sckpin The arduino pin number to use for SCK + * @param misopin The arduino pin number to use for MISO, set to -1 if not used + * @param mosipin The arduino pin number to use for MOSI, set to -1 if not used + * @param freq The SPI clock frequency to use, defaults to 1MHz + * @param dataOrder The SPI data order to use for bits within each byte, defaults to SPI_BITORDER_MSBFIRST + * @param dataMode The SPI mode to use, defaults to SPI_MODE0 + */ +Adafruit_SPIDevice::Adafruit_SPIDevice(int8_t cspin, int8_t sckpin, int8_t misopin, int8_t mosipin, + uint32_t freq, BitOrder dataOrder, uint8_t dataMode) { + _cs = cspin; + _sck = sckpin; + _miso = misopin; + _mosi = mosipin; + _freq = freq; + _dataOrder = dataOrder; + _dataMode = dataMode; + _begun = false; + _spiSetting = new SPISettings(freq, dataOrder, dataMode); + _spi = NULL; +} + + +/*! + * @brief Initializes SPI bus and sets CS pin high + * @return Always returns true because there's no way to test success of SPI init + */ +bool Adafruit_SPIDevice::begin(void) { + pinMode(_cs, OUTPUT); + digitalWrite(_cs, HIGH); + + if (_spi) { // hardware SPI + _spi->begin(); + } else { + pinMode(_sck, OUTPUT); + + if (_dataMode==SPI_MODE0) { + digitalWrite(_sck, HIGH); + } else { + digitalWrite(_sck, LOW); + } + if (_mosi != -1) { + pinMode(_mosi, OUTPUT); + digitalWrite(_mosi, HIGH); + } + if (_miso != -1) { + pinMode(_miso, INPUT); + } + } + + _begun = true; + return true; +} + + +/*! + * @brief Transfer (send/receive) one byte over hard/soft SPI + * @param buffer The buffer to send and receive at the same time + * @param len The number of bytes to transfer + */ +void Adafruit_SPIDevice::transfer(uint8_t *buffer, size_t len) { + if (_spi) { + // hardware SPI is easy + _spi->transfer(buffer, len); + return; + } + + // for softSPI we'll do it by hand + for (size_t i=0; i> b) & 0x1) << (7-b); + } + send = temp; + } + for (int b=7; b>=0; b--) { + reply <<= 1; + if (_dataMode == SPI_MODE0) { + digitalWrite(_sck, LOW); + digitalWrite(_mosi, send & (1<> b) & 0x1) << (7-b); + } + reply = temp; + } + + buffer[i] = reply; + } + return; +} + + + +/*! + * @brief Transfer (send/receive) one byte over hard/soft SPI + * @param send The byte to send + * @return The byte received while transmitting + */ +uint8_t Adafruit_SPIDevice::transfer(uint8_t send) { + uint8_t data = send; + transfer(&data, 1); + return data; +} + + +/*! + * @brief Write a buffer or two to the SPI device. + * @param buffer Pointer to buffer of data to write + * @param len Number of bytes from buffer to write + * @param prefix_buffer Pointer to optional array of data to write before buffer. + * @param prefix_len Number of bytes from prefix buffer to write + * @return Always returns true because there's no way to test success of SPI writes + */ +bool Adafruit_SPIDevice::write(uint8_t *buffer, size_t len, uint8_t *prefix_buffer, size_t prefix_len) { + if (_spi) { + _spi->beginTransaction(*_spiSetting); + } + + digitalWrite(_cs, LOW); + // do the writing + for (size_t i=0; iendTransaction(); + } + +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.print(F("\tSPIDevice Wrote: ")); + if ((prefix_len != 0) && (prefix_buffer != NULL)) { + for (uint16_t i=0; ibeginTransaction(*_spiSetting); + } + digitalWrite(_cs, LOW); + transfer(buffer, len); + digitalWrite(_cs, HIGH); + + if (_spi) { + _spi->endTransaction(); + } + +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.print(F("\tSPIDevice Read: ")); + for (uint16_t i=0; ibeginTransaction(*_spiSetting); + } + + digitalWrite(_cs, LOW); + // do the writing + for (size_t i=0; iendTransaction(); + } + + return true; +} diff --git a/lib/Adafruit_BusIO/Adafruit_SPIDevice.h b/lib/Adafruit_BusIO/Adafruit_SPIDevice.h new file mode 100644 index 000000000..987cb3f62 --- /dev/null +++ b/lib/Adafruit_BusIO/Adafruit_SPIDevice.h @@ -0,0 +1,62 @@ +#include + +#ifndef Adafruit_SPIDevice_h +#define Adafruit_SPIDevice_h + +// some modern SPI definitions don't have BitOrder enum +#if (defined(__AVR__) && !defined(ARDUINO_ARCH_MEGAAVR)) || defined(ESP8266) || defined(TEENSYDUINO) +typedef enum _BitOrder { + SPI_BITORDER_MSBFIRST = MSBFIRST, + SPI_BITORDER_LSBFIRST = LSBFIRST, +} BitOrder; +#endif + +// some modern SPI definitions don't have BitOrder enum and have different SPI mode defines +#if defined(ESP32) +typedef enum _BitOrder { + SPI_BITORDER_MSBFIRST = SPI_MSBFIRST, + SPI_BITORDER_LSBFIRST = SPI_LSBFIRST, +} BitOrder; +#endif + +// Some platforms have a BitOrder enum but its named MSBFIRST/LSBFIRST +#if defined(ARDUINO_ARCH_SAMD) || defined(__SAM3X8E__) || defined(NRF52_SERIES) || defined(ARDUINO_ARCH_ARDUINO_CORE_STM32) || defined(ARDUINO_ARCH_MEGAAVR) || defined(_STM32_DEF_) + #define SPI_BITORDER_MSBFIRST MSBFIRST + #define SPI_BITORDER_LSBFIRST LSBFIRST +#endif + +///< The class which defines how we will talk to this device over SPI +class Adafruit_SPIDevice { + public: + Adafruit_SPIDevice(int8_t cspin, + uint32_t freq=1000000, + BitOrder dataOrder=SPI_BITORDER_MSBFIRST, + uint8_t dataMode=SPI_MODE0, + SPIClass *theSPI=&SPI); + + Adafruit_SPIDevice(int8_t cspin, int8_t sck, int8_t miso, int8_t mosi, + uint32_t freq=1000000, + BitOrder dataOrder=SPI_BITORDER_MSBFIRST, + uint8_t dataMode=SPI_MODE0); + + bool begin(void); + bool read(uint8_t *buffer, size_t len, uint8_t sendvalue=0xFF); + bool write(uint8_t *buffer, size_t len, uint8_t *prefix_buffer=NULL, size_t prefix_len=0); + bool write_then_read(uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len, uint8_t sendvalue=0xFF); + + uint8_t transfer(uint8_t send); + void transfer(uint8_t *buffer, size_t len); + + private: + + SPIClass *_spi; + SPISettings *_spiSetting; + uint32_t _freq; + BitOrder _dataOrder; + uint8_t _dataMode; + + int8_t _cs, _sck, _mosi, _miso; + bool _begun; +}; + +#endif // Adafruit_SPIDevice_h diff --git a/lib/Adafruit_BusIO/LICENSE b/lib/Adafruit_BusIO/LICENSE new file mode 100644 index 000000000..860e3e285 --- /dev/null +++ b/lib/Adafruit_BusIO/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Adafruit Industries + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/lib/Adafruit_BusIO/README.md b/lib/Adafruit_BusIO/README.md new file mode 100644 index 000000000..a1830809c --- /dev/null +++ b/lib/Adafruit_BusIO/README.md @@ -0,0 +1,7 @@ +# Adafruit Bus IO Library [![Build Status](https://travis-ci.com/adafruit/Adafruit_BusIO.svg?branch=master)](https://travis-ci.com/adafruit/Adafruit_BusIO) + +This is a helper libary to abstract away I2C & SPI transactions and registers + +Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! + +MIT license, all text above must be included in any redistribution diff --git a/lib/Adafruit_BusIO/examples/i2c_address_detect/i2c_address_detect.ino b/lib/Adafruit_BusIO/examples/i2c_address_detect/i2c_address_detect.ino new file mode 100644 index 000000000..b1505254e --- /dev/null +++ b/lib/Adafruit_BusIO/examples/i2c_address_detect/i2c_address_detect.ino @@ -0,0 +1,21 @@ +#include + +Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(0x10); + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("I2C address detection test"); + + if (!i2c_dev.begin()) { + Serial.print("Did not find device at 0x"); + Serial.println(i2c_dev.address(), HEX); + while (1); + } + Serial.print("Device found on address 0x"); + Serial.println(i2c_dev.address(), HEX); +} + +void loop() { + +} diff --git a/lib/Adafruit_BusIO/examples/i2c_readwrite/i2c_readwrite.ino b/lib/Adafruit_BusIO/examples/i2c_readwrite/i2c_readwrite.ino new file mode 100644 index 000000000..909cf3118 --- /dev/null +++ b/lib/Adafruit_BusIO/examples/i2c_readwrite/i2c_readwrite.ino @@ -0,0 +1,41 @@ +#include + +#define I2C_ADDRESS 0x60 +Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(I2C_ADDRESS); + + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("I2C device read and write test"); + + if (!i2c_dev.begin()) { + Serial.print("Did not find device at 0x"); + Serial.println(i2c_dev.address(), HEX); + while (1); + } + Serial.print("Device found on address 0x"); + Serial.println(i2c_dev.address(), HEX); + + uint8_t buffer[32]; + // Try to read 32 bytes + i2c_dev.read(buffer, 32); + Serial.print("Read: "); + for (uint8_t i=0; i<32; i++) { + Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", "); + } + Serial.println(); + + // read a register by writing first, then reading + buffer[0] = 0x0C; // we'll reuse the same buffer + i2c_dev.write_then_read(buffer, 1, buffer, 2, false); + Serial.print("Write then Read: "); + for (uint8_t i=0; i<2; i++) { + Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", "); + } + Serial.println(); +} + +void loop() { + +} diff --git a/lib/Adafruit_BusIO/examples/i2c_registers/i2c_registers.ino b/lib/Adafruit_BusIO/examples/i2c_registers/i2c_registers.ino new file mode 100644 index 000000000..41a30436e --- /dev/null +++ b/lib/Adafruit_BusIO/examples/i2c_registers/i2c_registers.ino @@ -0,0 +1,38 @@ +#include +#include + +#define I2C_ADDRESS 0x60 +Adafruit_I2CDevice i2c_dev = Adafruit_I2CDevice(I2C_ADDRESS); + + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("I2C device register test"); + + if (!i2c_dev.begin()) { + Serial.print("Did not find device at 0x"); + Serial.println(i2c_dev.address(), HEX); + while (1); + } + Serial.print("Device found on address 0x"); + Serial.println(i2c_dev.address(), HEX); + + Adafruit_BusIO_Register id_reg = Adafruit_BusIO_Register(&i2c_dev, 0x0C, 2, LSBFIRST); + uint16_t id; + id_reg.read(&id); + Serial.print("ID register = 0x"); Serial.println(id, HEX); + + Adafruit_BusIO_Register thresh_reg = Adafruit_BusIO_Register(&i2c_dev, 0x01, 2, LSBFIRST); + uint16_t thresh; + thresh_reg.read(&thresh); + Serial.print("Initial threshold register = 0x"); Serial.println(thresh, HEX); + + thresh_reg.write(~thresh); + + Serial.print("Post threshold register = 0x"); Serial.println(thresh_reg.read(), HEX); +} + +void loop() { + +} \ No newline at end of file diff --git a/lib/Adafruit_BusIO/examples/i2corspi_register/i2corspi_register.ino b/lib/Adafruit_BusIO/examples/i2corspi_register/i2corspi_register.ino new file mode 100644 index 000000000..555cf3b0d --- /dev/null +++ b/lib/Adafruit_BusIO/examples/i2corspi_register/i2corspi_register.ino @@ -0,0 +1,38 @@ +#include + +// Define which interface to use by setting the unused interface to NULL! + +#define SPIDEVICE_CS 10 +Adafruit_SPIDevice *spi_dev = NULL; // new Adafruit_SPIDevice(SPIDEVICE_CS); + +#define I2C_ADDRESS 0x5D +Adafruit_I2CDevice *i2c_dev = new Adafruit_I2CDevice(I2C_ADDRESS); + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("I2C or SPI device register test"); + + if (spi_dev && !spi_dev->begin()) { + Serial.println("Could not initialize SPI device"); + } + + if (i2c_dev) { + if (i2c_dev->begin()) { + Serial.print("Device found on I2C address 0x"); + Serial.println(i2c_dev->address(), HEX); + } else { + Serial.print("Did not find I2C device at 0x"); + Serial.println(i2c_dev->address(), HEX); + } + } + + Adafruit_BusIO_Register id_reg = Adafruit_BusIO_Register(i2c_dev, spi_dev, ADDRBIT8_HIGH_TOREAD, 0x0F); + uint8_t id; + id_reg.read(&id); + Serial.print("ID register = 0x"); Serial.println(id, HEX); +} + +void loop() { + +} \ No newline at end of file diff --git a/lib/Adafruit_BusIO/examples/spi_modetest/spi_modetest.ino b/lib/Adafruit_BusIO/examples/spi_modetest/spi_modetest.ino new file mode 100644 index 000000000..10168c5ff --- /dev/null +++ b/lib/Adafruit_BusIO/examples/spi_modetest/spi_modetest.ino @@ -0,0 +1,29 @@ +#include + +#define SPIDEVICE_CS 10 +Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS, 100000, SPI_BITORDER_MSBFIRST, SPI_MODE1); +//Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS, 13, 12, 11, 100000, SPI_BITORDER_MSBFIRST, SPI_MODE1); + + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("SPI device mode test"); + + if (!spi_dev.begin()) { + Serial.println("Could not initialize SPI device"); + while (1); + } +} + +void loop() { + Serial.println("\n\nTransfer test"); + for (uint16_t x=0; x<=0xFF; x++) { + uint8_t i = x; + Serial.print("0x"); Serial.print(i, HEX); + spi_dev.read(&i, 1, i); + Serial.print("/"); Serial.print(i, HEX); + Serial.print(", "); + delay(25); + } +} \ No newline at end of file diff --git a/lib/Adafruit_BusIO/examples/spi_readwrite/spi_readwrite.ino b/lib/Adafruit_BusIO/examples/spi_readwrite/spi_readwrite.ino new file mode 100644 index 000000000..6f2c063f0 --- /dev/null +++ b/lib/Adafruit_BusIO/examples/spi_readwrite/spi_readwrite.ino @@ -0,0 +1,39 @@ +#include + +#define SPIDEVICE_CS 10 +Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS); + + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("SPI device read and write test"); + + if (!spi_dev.begin()) { + Serial.println("Could not initialize SPI device"); + while (1); + } + + uint8_t buffer[32]; + + // Try to read 32 bytes + spi_dev.read(buffer, 32); + Serial.print("Read: "); + for (uint8_t i=0; i<32; i++) { + Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", "); + } + Serial.println(); + + // read a register by writing first, then reading + buffer[0] = 0x8F; // we'll reuse the same buffer + spi_dev.write_then_read(buffer, 1, buffer, 2, false); + Serial.print("Write then Read: "); + for (uint8_t i=0; i<2; i++) { + Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", "); + } + Serial.println(); +} + +void loop() { + +} diff --git a/lib/Adafruit_BusIO/examples/spi_registers/spi_registers.ino b/lib/Adafruit_BusIO/examples/spi_registers/spi_registers.ino new file mode 100644 index 000000000..e24f1aa9a --- /dev/null +++ b/lib/Adafruit_BusIO/examples/spi_registers/spi_registers.ino @@ -0,0 +1,34 @@ +#include +#include + +#define SPIDEVICE_CS 10 +Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS); + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("SPI device register test"); + + if (!spi_dev.begin()) { + Serial.println("Could not initialize SPI device"); + while (1); + } + + Adafruit_BusIO_Register id_reg = Adafruit_BusIO_Register(&spi_dev, 0x0F, ADDRBIT8_HIGH_TOREAD); + uint8_t id; + id_reg.read(&id); + Serial.print("ID register = 0x"); Serial.println(id, HEX); + + Adafruit_BusIO_Register thresh_reg = Adafruit_BusIO_Register(&spi_dev, 0x0C, ADDRBIT8_HIGH_TOREAD, 2, LSBFIRST); + uint16_t thresh; + thresh_reg.read(&thresh); + Serial.print("Initial threshold register = 0x"); Serial.println(thresh, HEX); + + thresh_reg.write(~thresh); + + Serial.print("Post threshold register = 0x"); Serial.println(thresh_reg.read(), HEX); +} + +void loop() { + +} \ No newline at end of file diff --git a/lib/Adafruit_BusIO/library.properties b/lib/Adafruit_BusIO/library.properties new file mode 100644 index 000000000..f63425a7d --- /dev/null +++ b/lib/Adafruit_BusIO/library.properties @@ -0,0 +1,9 @@ +name=Adafruit BusIO +version=1.0.10 +author=Adafruit +maintainer=Adafruit +sentence=This is a library for abstracting away UART, I2C and SPI interfacing +paragraph=This is a library for abstracting away UART, I2C and SPI interfacing +category=Signal Input/Output +url=https://github.com/adafruit/Adafruit_BusIO +architectures=* diff --git a/lib/Adafruit_VEML7700/.github/ISSUE_TEMPLATE.md b/lib/Adafruit_VEML7700/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..f0e26146f --- /dev/null +++ b/lib/Adafruit_VEML7700/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,46 @@ +Thank you for opening an issue on an Adafruit Arduino library repository. To +improve the speed of resolution please review the following guidelines and +common troubleshooting steps below before creating the issue: + +- **Do not use GitHub issues for troubleshooting projects and issues.** Instead use + the forums at http://forums.adafruit.com to ask questions and troubleshoot why + something isn't working as expected. In many cases the problem is a common issue + that you will more quickly receive help from the forum community. GitHub issues + are meant for known defects in the code. If you don't know if there is a defect + in the code then start with troubleshooting on the forum first. + +- **If following a tutorial or guide be sure you didn't miss a step.** Carefully + check all of the steps and commands to run have been followed. Consult the + forum if you're unsure or have questions about steps in a guide/tutorial. + +- **For Arduino projects check these very common issues to ensure they don't apply**: + + - For uploading sketches or communicating with the board make sure you're using + a **USB data cable** and **not** a **USB charge-only cable**. It is sometimes + very hard to tell the difference between a data and charge cable! Try using the + cable with other devices or swapping to another cable to confirm it is not + the problem. + + - **Be sure you are supplying adequate power to the board.** Check the specs of + your board and plug in an external power supply. In many cases just + plugging a board into your computer is not enough to power it and other + peripherals. + + - **Double check all soldering joints and connections.** Flakey connections + cause many mysterious problems. See the [guide to excellent soldering](https://learn.adafruit.com/adafruit-guide-excellent-soldering/tools) for examples of good solder joints. + + - **Ensure you are using an official Arduino or Adafruit board.** We can't + guarantee a clone board will have the same functionality and work as expected + with this code and don't support them. + +If you're sure this issue is a defect in the code and checked the steps above +please fill in the following fields to provide enough troubleshooting information. +You may delete the guideline and text above to just leave the following details: + +- Arduino board: **INSERT ARDUINO BOARD NAME/TYPE HERE** + +- Arduino IDE version (found in Arduino -> About Arduino menu): **INSERT ARDUINO + VERSION HERE** + +- List the steps to reproduce the problem below (if possible attach a sketch or + copy the sketch code in too): **LIST REPRO STEPS BELOW** diff --git a/lib/Adafruit_VEML7700/.github/PULL_REQUEST_TEMPLATE.md b/lib/Adafruit_VEML7700/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..7b641eb86 --- /dev/null +++ b/lib/Adafruit_VEML7700/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,26 @@ +Thank you for creating a pull request to contribute to Adafruit's GitHub code! +Before you open the request please review the following guidelines and tips to +help it be more easily integrated: + +- **Describe the scope of your change--i.e. what the change does and what parts + of the code were modified.** This will help us understand any risks of integrating + the code. + +- **Describe any known limitations with your change.** For example if the change + doesn't apply to a supported platform of the library please mention it. + +- **Please run any tests or examples that can exercise your modified code.** We + strive to not break users of the code and running tests/examples helps with this + process. + +Thank you again for contributing! We will try to test and integrate the change +as soon as we can, but be aware we have many GitHub repositories to manage and +can't immediately respond to every request. There is no need to bump or check in +on a pull request (it will clutter the discussion of the request). + +Also don't be worried if the request is closed or not integrated--sometimes the +priorities of Adafruit's GitHub code (education, ease of use) might not match the +priorities of the pull request. Don't fret, the open source community thrives on +forks and GitHub makes it easy to keep your changes in a forked repo. + +After reviewing the guidelines above you can delete this text from the pull request. diff --git a/lib/Adafruit_VEML7700/.gitignore b/lib/Adafruit_VEML7700/.gitignore new file mode 100644 index 000000000..542d266a9 --- /dev/null +++ b/lib/Adafruit_VEML7700/.gitignore @@ -0,0 +1,8 @@ +# osx +.DS_Store + +# doxygen +Doxyfile* +doxygen_sqlite3.db +html +*.tmp diff --git a/lib/Adafruit_VEML7700/.travis.yml b/lib/Adafruit_VEML7700/.travis.yml new file mode 100644 index 000000000..b967e9a08 --- /dev/null +++ b/lib/Adafruit_VEML7700/.travis.yml @@ -0,0 +1,26 @@ +language: c +sudo: false +cache: + directories: + - ~/arduino_ide + - ~/.arduino15/packages/ +git: + depth: false + quiet: true +env: + global: + - PRETTYNAME="Adafruit VEML7700 Arduino Library" + +before_install: + - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh) + +install: + - arduino --install-library "Adafruit BusIO" + +script: + - build_main_platforms + +# Generate and deploy documentation +after_success: + - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/library_check.sh) + - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/doxy_gen_and_deploy.sh) \ No newline at end of file diff --git a/lib/Adafruit_VEML7700/Adafruit_VEML7700.cpp b/lib/Adafruit_VEML7700/Adafruit_VEML7700.cpp new file mode 100644 index 000000000..001d4995e --- /dev/null +++ b/lib/Adafruit_VEML7700/Adafruit_VEML7700.cpp @@ -0,0 +1,322 @@ +/*! + * @file Adafruit_VEML7700.cpp + * + * @mainpage Adafruit VEML7700 I2C Lux Sensor + * + * @section intro_sec Introduction + * + * I2C Driver for the VEML7700 I2C Lux sensor + * + * This is a library for the Adafruit VEML7700 breakout: + * http://www.adafruit.com/ + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing products from + * Adafruit! + * + * @section author Author + * + * Limor Fried (Adafruit Industries) + * + * @section license License + * + * BSD (see license.txt) + * + * @section HISTORY + * + * v1.0 - First release + */ + +#include "Arduino.h" +#include + +#include "Adafruit_VEML7700.h" + +/*! + * @brief Instantiates a new VEML7700 class + */ +Adafruit_VEML7700::Adafruit_VEML7700(void) {} + +/*! + * @brief Setups the hardware for talking to the VEML7700 + * @param theWire An optional pointer to an I2C interface + * @return True if initialization was successful, otherwise false. + */ +boolean Adafruit_VEML7700::begin(TwoWire *theWire) { + i2c_dev = new Adafruit_I2CDevice(VEML7700_I2CADDR_DEFAULT, theWire); + + if (!i2c_dev->begin()) { + return false; + } + + ALS_Config = new Adafruit_I2CRegister(i2c_dev, VEML7700_ALS_CONFIG, 2, LSBFIRST); + ALS_HighThreshold = new Adafruit_I2CRegister(i2c_dev, VEML7700_ALS_THREHOLD_HIGH, 2, LSBFIRST); + ALS_LowThreshold = new Adafruit_I2CRegister(i2c_dev, VEML7700_ALS_THREHOLD_LOW, 2, LSBFIRST); + Power_Saving = new Adafruit_I2CRegister(i2c_dev, VEML7700_ALS_POWER_SAVE, 2, LSBFIRST); + ALS_Data = new Adafruit_I2CRegister(i2c_dev, VEML7700_ALS_DATA, 2, LSBFIRST); + White_Data = new Adafruit_I2CRegister(i2c_dev, VEML7700_WHITE_DATA, 2, LSBFIRST); + Interrupt_Status = new Adafruit_I2CRegister(i2c_dev, VEML7700_INTERRUPTSTATUS, 2, LSBFIRST); + + ALS_Shutdown = new Adafruit_I2CRegisterBits(ALS_Config, 1, 0); // # bits, bit_shift + ALS_Interrupt_Enable = new Adafruit_I2CRegisterBits(ALS_Config, 1, 1); + ALS_Persistence = new Adafruit_I2CRegisterBits(ALS_Config, 2, 4); + ALS_Integration_Time = new Adafruit_I2CRegisterBits(ALS_Config, 4, 6); + ALS_Gain = new Adafruit_I2CRegisterBits(ALS_Config, 2, 11); + PowerSave_Enable = new Adafruit_I2CRegisterBits(Power_Saving, 1, 0); + PowerSave_Mode = new Adafruit_I2CRegisterBits(Power_Saving, 2, 1); + + enable(false); + interruptEnable(false); + setPersistence(VEML7700_PERS_1); + setGain(VEML7700_GAIN_1); + setIntegrationTime(VEML7700_IT_100MS); + powerSaveEnable(false); + enable(true); + + return true; +} + + +float Adafruit_VEML7700::normalize_resolution(float value) { + // adjust for gain (1x is normalized) + switch (getGain()) { + case VEML7700_GAIN_2: + value /= 2.0; break; + case VEML7700_GAIN_1_4: + value *= 4; break; + case VEML7700_GAIN_1_8: + value *= 8; break; + } + + // adjust for integrationtime (100ms is normalized) + switch (getIntegrationTime()) { + case VEML7700_IT_25MS: + value *= 4; break; + case VEML7700_IT_50MS: + value *= 2; break; + case VEML7700_IT_200MS: + value /= 2.0; break; + case VEML7700_IT_400MS: + value /= 4.0; break; + case VEML7700_IT_800MS: + value /= 8.0; break; + } + + return value; +} + +/*! + * @brief Read the calibrated lux value. See app note lux table on page 5 + * @returns Floating point Lux data (ALS multiplied by 0.0576) + */ +float Adafruit_VEML7700::readLux() { + return ( normalize_resolution(ALS_Data->read()) * 0.0576); // see app note lux table on page 5 +} + +/*! + * @brief Read the lux value with correction for non-linearity at high-lux settings + * @returns Floating point Lux data (ALS multiplied by 0.0576 and corrected for high-lux settings) + */ +float Adafruit_VEML7700::readLuxNormalized() { + float lux = readLux(); + + // user-provided correction for non-linearities at high lux/white values: + // https://forums.adafruit.com/viewtopic.php?f=19&t=152997&p=758582#p759346 + if ((getGain() == VEML7700_GAIN_1_8) && (getIntegrationTime() == VEML7700_IT_25MS)){ + lux = 6.0135e-13*pow(lux,4) - 9.3924e-9*pow(lux,3) + 8.1488e-5*pow(lux,2) + 1.0023*lux; + } + + return lux; +} + +/*! + * @brief Read the raw ALS data + * @returns 16-bit data value from the ALS register + */ +uint16_t Adafruit_VEML7700::readALS() { + return ALS_Data->read(); +} + +/*! + * @brief Read the white light data + * @returns Floating point 'white light' data multiplied by 0.0576 + */ +float Adafruit_VEML7700::readWhite() { + // white_corrected= 2E-15*pow(VEML_white,4) + 4E-12*pow(VEML_white,3) + 9E-06*pow(VEML_white,)2 + 1.0179*VEML_white - 11.052; + return normalize_resolution(White_Data->read()) * 0.0576; // Unclear if this is the right multiplier +} + +/*! + * @brief Read the 'white light' value with correction for non-linearity at high-lux settings + * @returns Floating point 'white light' data multiplied by 0.0576 and corrected for high-lux settings + */ +float Adafruit_VEML7700::readWhiteNormalized() { + float white = readWhite(); + + // user-provided correction for non-linearities at high lux values: + // https://forums.adafruit.com/viewtopic.php?f=19&t=152997&p=758582#p759346 + if ((getGain() == VEML7700_GAIN_1_8) && (getIntegrationTime() == VEML7700_IT_25MS)){ + white = 2E-15*pow(white,4) + 4E-12*pow(white,3) + 9E-06*pow(white,2) + 1.0179*white - 11.052; + } + + return white; +} + +/*! + * @brief Enable or disable the sensor + * @param enable The flag to enable/disable + */ +void Adafruit_VEML7700::enable(bool enable) { + ALS_Shutdown->write(!enable); +} + +/*! + * @brief Ask if the interrupt is enabled + * @returns True if enabled, false otherwise + */ +bool Adafruit_VEML7700::enabled(void) { + return !ALS_Shutdown->read(); +} + +/*! + * @brief Enable or disable the interrupt + * @param enable The flag to enable/disable + */ +void Adafruit_VEML7700::interruptEnable(bool enable) { + ALS_Interrupt_Enable->write(enable); +} + + +/*! + * @brief Ask if the interrupt is enabled + * @returns True if enabled, false otherwise + */ +bool Adafruit_VEML7700::interruptEnabled(void) { + return ALS_Interrupt_Enable->read(); +} + + +/*! + * @brief Set the ALS IRQ persistance setting + * @param pers Persistance constant, can be VEML7700_PERS_1, VEML7700_PERS_2, + * VEML7700_PERS_4 or VEML7700_PERS_8 + */ +void Adafruit_VEML7700::setPersistence(uint8_t pers) { + ALS_Persistence->write(pers); +} + +/*! + * @brief Get the ALS IRQ persistance setting + * @returns Persistance constant, can be VEML7700_PERS_1, VEML7700_PERS_2, + * VEML7700_PERS_4 or VEML7700_PERS_8 + */ +uint8_t Adafruit_VEML7700::getPersistence(void) { + return ALS_Persistence->read(); +} + +/*! + * @brief Set ALS integration time + * @param it Can be VEML7700_IT_100MS, VEML7700_IT_200MS, VEML7700_IT_400MS, + * VEML7700_IT_800MS, VEML7700_IT_50MS or VEML7700_IT_25MS + */ +void Adafruit_VEML7700::setIntegrationTime(uint8_t it) { + ALS_Integration_Time->write(it); +} + +/*! + * @brief Get ALS integration time + * @returns IT index, can be VEML7700_IT_100MS, VEML7700_IT_200MS, VEML7700_IT_400MS, + * VEML7700_IT_800MS, VEML7700_IT_50MS or VEML7700_IT_25MS + */ +uint8_t Adafruit_VEML7700::getIntegrationTime(void) { + return ALS_Integration_Time->read(); +} + +/*! + * @brief Set ALS gain + * @param gain Can be VEML7700_GAIN_1, VEML7700_GAIN_2, VEML7700_GAIN_1_8 or VEML7700_GAIN_1_4 + */ +void Adafruit_VEML7700::setGain(uint8_t gain) { + ALS_Gain->write(gain); +} + +/*! + * @brief Get ALS gain + * @returns Gain index, can be VEML7700_GAIN_1, VEML7700_GAIN_2, VEML7700_GAIN_1_8 or VEML7700_GAIN_1_4 + */ +uint8_t Adafruit_VEML7700::getGain(void) { + return ALS_Gain->read(); +} + + +/*! + * @brief Enable power save mode + * @param enable True if power save should be enabled + */ +void Adafruit_VEML7700::powerSaveEnable(bool enable) { + PowerSave_Enable->write(enable); +} + +/*! + * @brief Check if power save mode is enabled + * @returns True if power save is enabled + */ +bool Adafruit_VEML7700::powerSaveEnabled(void) { + return PowerSave_Enable->read(); +} + +/*! + * @brief Assign the power save register data + * @param mode The 16-bit data to write to VEML7700_ALS_POWER_SAVE + */ +void Adafruit_VEML7700::setPowerSaveMode(uint8_t mode) { + PowerSave_Mode->write(mode); +} + +/*! + * @brief Retrieve the power save register data + * @return 16-bit data from VEML7700_ALS_POWER_SAVE + */ +uint8_t Adafruit_VEML7700::getPowerSaveMode(void) { + return PowerSave_Mode->read(); +} + +/*! + * @brief Assign the low threshold register data + * @param value The 16-bit data to write to VEML7700_ALS_THREHOLD_LOW + */ +void Adafruit_VEML7700::setLowThreshold(uint16_t value) { + ALS_LowThreshold->write(value); +} + +/*! + * @brief Retrieve the low threshold register data + * @return 16-bit data from VEML7700_ALS_THREHOLD_LOW + */ +uint16_t Adafruit_VEML7700::getLowThreshold(void) { + return ALS_LowThreshold->read(); +} + +/*! + * @brief Assign the high threshold register data + * @param value The 16-bit data to write to VEML7700_ALS_THREHOLD_HIGH + */ +void Adafruit_VEML7700::setHighThreshold(uint16_t value) { + ALS_HighThreshold->write(value); +} + +/*! + * @brief Retrieve the high threshold register data + * @return 16-bit data from VEML7700_ALS_THREHOLD_HIGH + */ +uint16_t Adafruit_VEML7700::getHighThreshold(void) { + return ALS_HighThreshold->read(); +} + +/*! + * @brief Retrieve the interrupt status register data + * @return 16-bit data from VEML7700_INTERRUPTSTATUS + */ +uint16_t Adafruit_VEML7700::interruptStatus(void) { + return Interrupt_Status->read(); +} diff --git a/lib/Adafruit_VEML7700/Adafruit_VEML7700.h b/lib/Adafruit_VEML7700/Adafruit_VEML7700.h new file mode 100644 index 000000000..b842a7bc1 --- /dev/null +++ b/lib/Adafruit_VEML7700/Adafruit_VEML7700.h @@ -0,0 +1,113 @@ +/*! + * @file Adafruit_VEML7700.h + * + * I2C Driver for VEML7700 Lux sensor + * + * This is a library for the Adafruit VEML7700 breakout: + * http://www.adafruit.com/ + * + * Adafruit invests time and resources providing this open source code, + *please support Adafruit and open-source hardware by purchasing products from + * Adafruit! + * + * + * BSD license (see license.txt) + */ + +#ifndef _ADAFRUIT_VEML7700_H +#define _ADAFRUIT_VEML7700_H + +#include "Arduino.h" +#include +#include +#include + +#define VEML7700_I2CADDR_DEFAULT 0x10 ///< I2C address + +#define VEML7700_ALS_CONFIG 0x00 ///< Light configuration register +#define VEML7700_ALS_THREHOLD_HIGH 0x01 ///< Light high threshold for irq +#define VEML7700_ALS_THREHOLD_LOW 0x02 ///< Light low threshold for irq +#define VEML7700_ALS_POWER_SAVE 0x03 ///< Power save regiester +#define VEML7700_ALS_DATA 0x04 ///< The light data output +#define VEML7700_WHITE_DATA 0x05 ///< The white light data output +#define VEML7700_INTERRUPTSTATUS 0x06 ///< What IRQ (if any) + +#define VEML7700_INTERRUPT_HIGH 0x4000 ///< Interrupt status for high threshold +#define VEML7700_INTERRUPT_LOW 0x8000 ///< Interrupt status for low threshold + +#define VEML7700_GAIN_1 0x00 ///< ALS gain 1x +#define VEML7700_GAIN_2 0x01 ///< ALS gain 2x +#define VEML7700_GAIN_1_8 0x02 ///< ALS gain 1/8x +#define VEML7700_GAIN_1_4 0x03 ///< ALS gain 1/4x + +#define VEML7700_IT_100MS 0x00 ///< ALS intetgration time 100ms +#define VEML7700_IT_200MS 0x01 ///< ALS intetgration time 200ms +#define VEML7700_IT_400MS 0x02 ///< ALS intetgration time 400ms +#define VEML7700_IT_800MS 0x03 ///< ALS intetgration time 800ms +#define VEML7700_IT_50MS 0x08 ///< ALS intetgration time 50ms +#define VEML7700_IT_25MS 0x0C ///< ALS intetgration time 25ms + +#define VEML7700_PERS_1 0x00 ///< ALS irq persisance 1 sample +#define VEML7700_PERS_2 0x01 ///< ALS irq persisance 2 samples +#define VEML7700_PERS_4 0x02 ///< ALS irq persisance 4 samples +#define VEML7700_PERS_8 0x03 ///< ALS irq persisance 8 samples + +#define VEML7700_POWERSAVE_MODE1 0x00 ///< Power saving mode 1 +#define VEML7700_POWERSAVE_MODE2 0x01 ///< Power saving mode 2 +#define VEML7700_POWERSAVE_MODE3 0x02 ///< Power saving mode 3 +#define VEML7700_POWERSAVE_MODE4 0x03 ///< Power saving mode 4 + + +/*! + * @brief Class that stores state and functions for interacting with + * VEML7700 Temp Sensor + */ +class Adafruit_VEML7700 { +public: + Adafruit_VEML7700(); + boolean begin(TwoWire *theWire = &Wire); + + void enable(bool enable); + bool enabled(void); + + void interruptEnable(bool enable); + bool interruptEnabled(void); + void setPersistence(uint8_t pers); + uint8_t getPersistence(void); + void setIntegrationTime(uint8_t it); + uint8_t getIntegrationTime(void); + void setGain(uint8_t gain); + uint8_t getGain(void); + void powerSaveEnable(bool enable); + bool powerSaveEnabled(void); + void setPowerSaveMode(uint8_t mode); + uint8_t getPowerSaveMode(void); + + void setLowThreshold(uint16_t value); + uint16_t getLowThreshold(void); + void setHighThreshold(uint16_t value); + uint16_t getHighThreshold(void); + uint16_t interruptStatus(void); + + + float readLux(); + float readLuxNormalized(); + + uint16_t readALS(); + float readWhite(); + float readWhiteNormalized(); + +private: + Adafruit_I2CRegister *ALS_Config, *ALS_Data, *White_Data, + *ALS_HighThreshold, *ALS_LowThreshold, *Power_Saving, *Interrupt_Status; + Adafruit_I2CRegisterBits *ALS_Shutdown, *ALS_Interrupt_Enable, + *ALS_Persistence, *ALS_Integration_Time, *ALS_Gain, + *PowerSave_Enable, *PowerSave_Mode; + + float normalize_resolution(float value); + + Adafruit_I2CDevice *i2c_dev; + +}; + +#endif diff --git a/lib/Adafruit_VEML7700/README.md b/lib/Adafruit_VEML7700/README.md new file mode 100644 index 000000000..fe3f3c898 --- /dev/null +++ b/lib/Adafruit_VEML7700/README.md @@ -0,0 +1,16 @@ +Adafruit_VEML7700 [![Build Status](https://travis-ci.com/adafruit/Adafruit_VEML7700.svg?branch=master)](https://travis-ci.com/adafruit/Adafruit_VEML7700) +================ + +This is the Adafruit VEML7700 Lux sensor library + +Tested and works great with the [Adafruit VEML7700 Breakout Board](http://www.adafruit.com/) + +This chip uses I2C to communicate, 2 pins are required to interface + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +Written by Kevin Townsend/Limor Fried for Adafruit Industries. +BSD license, check license.txt for more information +All text above must be included in any redistribution diff --git a/lib/Adafruit_VEML7700/examples/veml7700_test/veml7700_test.ino b/lib/Adafruit_VEML7700/examples/veml7700_test/veml7700_test.ino new file mode 100644 index 000000000..64718112d --- /dev/null +++ b/lib/Adafruit_VEML7700/examples/veml7700_test/veml7700_test.ino @@ -0,0 +1,58 @@ +#include "Adafruit_VEML7700.h" + +Adafruit_VEML7700 veml = Adafruit_VEML7700(); + +void setup() { + while (!Serial) { delay(10); } + Serial.begin(115200); + Serial.println("Adafruit VEML7700 Test"); + + if (!veml.begin()) { + Serial.println("Sensor not found"); + while (1); + } + Serial.println("Sensor found"); + + veml.setGain(VEML7700_GAIN_1); + veml.setIntegrationTime(VEML7700_IT_800MS); + + Serial.print(F("Gain: ")); + switch (veml.getGain()) { + case VEML7700_GAIN_1: Serial.println("1"); break; + case VEML7700_GAIN_2: Serial.println("2"); break; + case VEML7700_GAIN_1_4: Serial.println("1/4"); break; + case VEML7700_GAIN_1_8: Serial.println("1/8"); break; + } + + Serial.print(F("Integration Time (ms): ")); + switch (veml.getIntegrationTime()) { + case VEML7700_IT_25MS: Serial.println("25"); break; + case VEML7700_IT_50MS: Serial.println("50"); break; + case VEML7700_IT_100MS: Serial.println("100"); break; + case VEML7700_IT_200MS: Serial.println("200"); break; + case VEML7700_IT_400MS: Serial.println("400"); break; + case VEML7700_IT_800MS: Serial.println("800"); break; + } + + //veml.powerSaveEnable(true); + //veml.setPowerSaveMode(VEML7700_POWERSAVE_MODE4); + + veml.setLowThreshold(10000); + veml.setHighThreshold(20000); + veml.interruptEnable(true); +} + +void loop() { + Serial.print("Lux: "); Serial.println(veml.readLux()); + Serial.print("White: "); Serial.println(veml.readWhite()); + Serial.print("Raw ALS: "); Serial.println(veml.readALS()); + + uint16_t irq = veml.interruptStatus(); + if (irq & VEML7700_INTERRUPT_LOW) { + Serial.println("** Low threshold"); + } + if (irq & VEML7700_INTERRUPT_HIGH) { + Serial.println("** High threshold"); + } + delay(500); +} diff --git a/lib/Adafruit_VEML7700/library.properties b/lib/Adafruit_VEML7700/library.properties new file mode 100644 index 000000000..754bd2fd7 --- /dev/null +++ b/lib/Adafruit_VEML7700/library.properties @@ -0,0 +1,9 @@ +name=Adafruit VEML7700 Library +version=1.0.0 +author=Adafruit +maintainer=Adafruit +sentence=Arduino library for the VEML7700 sensors in the Adafruit shop +paragraph=Arduino library for the VEML7700 sensors in the Adafruit shop +category=Sensors +url=https://github.com/adafruit/Adafruit_VEML7700 +architectures=* diff --git a/lib/Adafruit_VEML7700/license.txt b/lib/Adafruit_VEML7700/license.txt new file mode 100644 index 000000000..f6a0f22b8 --- /dev/null +++ b/lib/Adafruit_VEML7700/license.txt @@ -0,0 +1,26 @@ +Software License Agreement (BSD License) + +Copyright (c) 2012, Adafruit Industries +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. diff --git a/tasmota/i18n.h b/tasmota/i18n.h index e8286e585..698192e99 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -586,6 +586,16 @@ // Commands xsns_02_analog.ino #define D_CMND_ADCPARAM "AdcParam" +// xsns_70_veml6075.ino +#define D_JSON_UVA_INTENSITY "UvaIntensity" +#define D_JSON_UVB_INTENSITY "UvbItensity" +#define D_CMND_VEML6075_POWER "power" +#define D_CMND_VEML6075_DYNAMIC "dynamic" +#define D_CMND_VEML6075_INTTIME "inttime" + +// xsns_71_veml7700.ino +#define D_JSON_WHITE_CONTENT "WhiteContent" + /********************************************************************************************/ // Log message prefix diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 9b04a2ea2..1a65eb571 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -516,6 +516,8 @@ // #define USE_HDC1080 // [I2cDriver45] Enable HDC1080 temperature/humidity sensor (I2C address 0x40) (+1k5 code) // #define USE_IAQ // [I2cDriver46] Enable iAQ-core air quality sensor (I2C address 0x5a) (+0k6 code) // #define USE_AS3935 // [I2cDriver48] Enable AS3935 Franklin Lightning Sensor (I2C address 0x03) (+5k4 code) +// #define USE_VEML6075 // [I2cDriver49] Enable VEML6075 UVA/UVB/UVINDEX Sensor (I2C address 0x10) (+2k1 code) +// #define USE_VEML7700 // [I2cDriver50] Enable VEML7700 Ambient Light sensor (I2C addresses 0x10) (+4k5 code) // #define USE_DISPLAY // Add I2C Display Support (+2k code) #define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0 diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index 02a04a962..ef757e5b6 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -563,10 +563,13 @@ void GetFeatures(void) #ifdef USE_THERMOSTAT feature6 |= 0x00000400; // xdrv_39_heating.ino #endif +#ifdef USE_VEML6075 + feature6 |= 0x00000800; // xsns_70_veml6075.ino +#endif +#ifdef USE_VEML7700 + feature6 |= 0x00001000; // xsns_71_veml7700.ino +#endif -// feature6 |= 0x00000800; - -// feature6 |= 0x00001000; // feature6 |= 0x00002000; // feature6 |= 0x00004000; // feature6 |= 0x00008000; diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index 37ac20237..8ba54e60b 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -83,6 +83,8 @@ #define USE_BME680 // Add additional support for BME680 sensor using Bosch BME680 library (+4k code) #define USE_BH1750 // Add I2C code for BH1750 sensor (+0k5 code) #define USE_VEML6070 // Add I2C code for VEML6070 sensor (+0k5 code) +// #define USE_VEML6075 // Add I2C code for VEML6075 UVA/UVB/UVINDEX Sensor (+2k1 code) +// #define USE_VEML7700 // Add I2C code for VEML7700 Ambient Light sensor (+4k5 code) #define USE_ADS1115 // Add I2C code for ADS1115 16 bit A/D converter based on Adafruit ADS1x15 library (no library needed) (+0k7 code) #define USE_INA219 // Add I2C code for INA219 Low voltage and current sensor (+1k code) //#define USE_INA226 // Enable INA226 (I2C address 0x40, 0x41 0x44 or 0x45) Low voltage and current sensor (+2k3 code) diff --git a/tasmota/xsns_70_veml6075.ino b/tasmota/xsns_70_veml6075.ino new file mode 100644 index 000000000..00a8ebc8e --- /dev/null +++ b/tasmota/xsns_70_veml6075.ino @@ -0,0 +1,306 @@ +/* + xsns_70_veml6075.ino - VEML6075 Franklin Lightning Sensor support for Tasmota + + Copyright (C) 2020 Martin Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_I2C +#ifdef USE_VEML6075 +/*********************************************************************************************\ + * VEML6075 UVA/UVB/UVINDEX Sensor + * + * I2C Address: 0x10 +\*********************************************************************************************/ + +#define XSNS_70 70 +#define XI2C_49 49 // See I2CDEVICES.md + + +#define VEML6075_ADDR 0x10 // I2C address +#define VEML6075_CHIP_ID 0x26 // Manufacture ID + +// I2C register +#define VEML6075_REG_CONF 0x00 // Configuration register +#define VEML6075_REG_UVA 0x07 // UVA band raw measurement +#define VEML6075_REG_DARK 0x08 // Dark current (?) measurement +#define VEML6075_REG_UVB 0x09 // UVB band raw measurement +#define VEML6075_REG_UVCOMP1 0x0A // UV1 compensation value +#define VEML6075_REG_UVCOMP2 0x0B // UV2 compensation value +#define VEML6075_REG_ID 0x0C // ID Register + +// global constants for Calc +#define VEML6075_DEFAULT_UVA_A_COEFF 2.22 // Default for no coverglass +#define VEML6075_DEFAULT_UVA_B_COEFF 1.33 // Default for no coverglass +#define VEML6075_DEFAULT_UVB_C_COEFF 2.95 // Default for no coverglass +#define VEML6075_DEFAULT_UVB_D_COEFF 1.74 // Default for no coverglass +#define UVA_RESPONSIVITY_100MS_UNCOVERED 0.001461 // Default for no coverglass +#define UVB_RESPONSIVITY_100MS_UNCOVERED 0.002591 // Default for no coverglass + +const float UVA_RESPONSIVITY[] PROGMEM = +{ + UVA_RESPONSIVITY_100MS_UNCOVERED / 0.5016286645, // 50ms + UVA_RESPONSIVITY_100MS_UNCOVERED, // 100ms + UVA_RESPONSIVITY_100MS_UNCOVERED / 2.039087948, // 200ms + UVA_RESPONSIVITY_100MS_UNCOVERED / 3.781758958, // 400ms + UVA_RESPONSIVITY_100MS_UNCOVERED / 7.371335505 // 800ms +}; + +const float UVB_RESPONSIVITY[] PROGMEM = +{ + UVB_RESPONSIVITY_100MS_UNCOVERED / 0.5016286645, // 50ms + UVB_RESPONSIVITY_100MS_UNCOVERED, // 100ms + UVB_RESPONSIVITY_100MS_UNCOVERED / 2.039087948, // 200ms + UVB_RESPONSIVITY_100MS_UNCOVERED / 3.781758958, // 400ms + UVB_RESPONSIVITY_100MS_UNCOVERED / 7.371335505 // 800ms +}; + +// http and json defines +#define D_NAME_VEML6075 "VEML6075" +#define D_UVA_INTENSITY "UVA intensity" +#define D_UVB_INTENSITY "UVB intensity" + +const char HTTP_SNS_UVA[] PROGMEM = "{s}%s " D_UVA_INTENSITY "{m}%d " D_UNIT_WATT_METER_QUADRAT "{e}"; +const char HTTP_SNS_UVB[] PROGMEM = "{s}%s " D_UVB_INTENSITY "{m}%d " D_UNIT_WATT_METER_QUADRAT "{e}"; +const char HTTP_SNS_UVINDEX[] PROGMEM = "{s}%s " D_UV_INDEX "{m}%s {e}"; +const char JSON_SNS_VEML6075[] PROGMEM = ",\"%s\":{\"" D_JSON_UVA_INTENSITY "\":%d,\"" D_JSON_UVB_INTENSITY "\":%d,\"" D_JSON_UV_INDEX "\":%s}"; +const char S_JSON_VEML6075_COMMAND_NVALUE[] PROGMEM = "{\"" D_NAME_VEML6075 "\":{\"%s\":%d}}"; + +const char kVEML6075_Commands[] PROGMEM = D_CMND_VEML6075_POWER "|" D_CMND_VEML6075_DYNAMIC "|" D_CMND_VEML6075_INTTIME; + +enum VEML6075_Commands { // commands for Console + CMND_VEML6075_PWR, + CMND_VEML6075_SET_HD, + CMND_VEML6075_SET_UVIT, + }; + +// global variables +struct VEML6075STRUCT +{ + char types[9] = D_NAME_VEML6075; + uint8_t address = VEML6075_ADDR; + uint8_t inttime = 0; + uint16_t uva = 0; + uint16_t uvb = 0; + uint16_t uva_raw = 0; + uint16_t uvb_raw = 0; + uint16_t comp1 = 0; + uint16_t comp2 = 0; + uint16_t conf = 0; + float uvi = 0.0f; +} veml6075_sensor; + +uint8_t veml6075_active = 0; + +// typedef of config register +typedef union { + struct { + uint8_t pwr:1; // Shut Down + uint8_t forded_auto:1; // Auto or forced + uint8_t forced_trigger:1; // Trigger forced mode + uint8_t hd:1; // High dynamic + uint8_t inttime:3; // Integration Time + uint8_t spare7:1; // spare + }; + uint16_t config; +} veml6075configRegister; + +veml6075configRegister veml6075Config; + +/********************************************************************************************/ + +uint16_t VEML6075read16 (uint8_t reg) { + uint16_t swap = I2cRead16(VEML6075_ADDR, reg); + uint16_t ret = ((swap & 0xFF) << 8) | (swap >> 8); + return ret; +} + +void VEML6075write16 (uint8_t reg, uint16_t val) { + uint16_t swap = ((val & 0xFF) << 8) | (val >> 8); + I2cWrite16(VEML6075_ADDR, reg, swap); +} + +float VEML6075calcUVA (void) { + float uva_calc = veml6075_sensor.uva_raw - (VEML6075_DEFAULT_UVA_A_COEFF * veml6075_sensor.comp1) - (VEML6075_DEFAULT_UVA_B_COEFF * veml6075_sensor.comp2); + return uva_calc; +} + +float VEML6075calcUVB (void) { + float uvb_calc = veml6075_sensor.uvb_raw - (VEML6075_DEFAULT_UVB_C_COEFF * veml6075_sensor.comp1) - (VEML6075_DEFAULT_UVB_D_COEFF * veml6075_sensor.comp2); + return uvb_calc; +} + +float VEML6075calcUVI (void) { + float uvi_calc = ((veml6075_sensor.uva * UVA_RESPONSIVITY[veml6075_sensor.inttime]) + (veml6075_sensor.uvb * UVB_RESPONSIVITY[veml6075_sensor.inttime])) / 2; + return uvi_calc; +} + +void VEML6075SetHD(uint8_t val){ + veml6075Config.hd = val; + VEML6075write16 (VEML6075_REG_CONF, veml6075Config.config); +} + +uint8_t VEML6075ReadHD(void){ + veml6075Config.config = VEML6075read16 (VEML6075_REG_CONF); + return veml6075Config.hd; +} + +void VEML6075SetUvIt(uint8_t val){ + veml6075Config.inttime = val; + VEML6075Pwr(1); + VEML6075write16 (VEML6075_REG_CONF, veml6075Config.config); + VEML6075Pwr(0); +} + +uint8_t VEML6075GetUvIt(void){ + veml6075Config.config = VEML6075read16 (VEML6075_REG_CONF); + return veml6075Config.inttime; +} + +void VEML6075Pwr(uint8_t val){ + veml6075Config.pwr = val; + VEML6075write16 (VEML6075_REG_CONF, veml6075Config.config); +} + +uint8_t VEML6075GetPwr(void){ + veml6075Config.config = VEML6075read16 (VEML6075_REG_CONF); + return veml6075Config.pwr; +} + +void VEML6075ReadData(void) +{ + veml6075_sensor.uva_raw = VEML6075read16 (VEML6075_REG_UVA); + veml6075_sensor.uvb_raw = VEML6075read16 (VEML6075_REG_UVB); + veml6075_sensor.comp1 = VEML6075read16 (VEML6075_REG_UVCOMP1); + veml6075_sensor.comp2 = VEML6075read16 (VEML6075_REG_UVCOMP2); + veml6075_sensor.inttime = VEML6075GetUvIt(); + veml6075_sensor.uva = VEML6075calcUVA(); + veml6075_sensor.uvb = VEML6075calcUVB(); + veml6075_sensor.uvi = VEML6075calcUVI(); +} + +bool VEML6075init(void) +{ + uint8_t id = VEML6075read16 (VEML6075_REG_ID); + if(id == VEML6075_CHIP_ID) // Sensor id + return true; + return false; +} + +void VEML6075Detect(void) { + if (I2cActive(veml6075_sensor.address)) return; + + if (VEML6075init()) { + I2cSetActiveFound(veml6075_sensor.address, veml6075_sensor.types); + VEML6075write16 (VEML6075_REG_CONF, 0x10); // set default + veml6075_active = 1; + } +} + +void VEML6075EverySecond(void) { + VEML6075ReadData(); +} + +bool VEML6075Cmd(void) { + char command[CMDSZ]; + uint8_t name_len = strlen(D_NAME_VEML6075); + if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_NAME_VEML6075), name_len)) { + uint32_t command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + name_len, kVEML6075_Commands); + switch (command_code) { + case CMND_VEML6075_PWR: + if (XdrvMailbox.data_len) { + if (2 >= XdrvMailbox.payload) { + VEML6075Pwr(XdrvMailbox.payload); + } + } + Response_P(S_JSON_VEML6075_COMMAND_NVALUE, command, VEML6075GetPwr()); + break; + case CMND_VEML6075_SET_HD: + if (XdrvMailbox.data_len) { + if (2 >= XdrvMailbox.payload) { + VEML6075SetHD(XdrvMailbox.payload); + } + } + Response_P(S_JSON_VEML6075_COMMAND_NVALUE, command, VEML6075ReadHD()); + break; + case CMND_VEML6075_SET_UVIT: + if (XdrvMailbox.data_len) { + if (4 >= XdrvMailbox.payload) { + VEML6075SetUvIt(XdrvMailbox.payload); + } + } + Response_P(S_JSON_VEML6075_COMMAND_NVALUE, command, VEML6075GetUvIt()); + break; + default: + return false; + } + return true; + } else { + return false; + } +} + +void VEML6075Show(bool json) +{ + char s_uvindex[FLOATSZ]; + dtostrfd(veml6075_sensor.uvi,1, s_uvindex); + + if (json) { + ResponseAppend_P(JSON_SNS_VEML6075, D_NAME_VEML6075, veml6075_sensor.uva, veml6075_sensor.uvb, s_uvindex); +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_SNS_UVA, D_NAME_VEML6075, veml6075_sensor.uva); + WSContentSend_PD(HTTP_SNS_UVB, D_NAME_VEML6075, veml6075_sensor.uvb); + WSContentSend_PD(HTTP_SNS_UVINDEX, D_NAME_VEML6075 ,s_uvindex); +#endif // USE_WEBSERVER + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns70(uint8_t function) +{ + if (!I2cEnabled(XI2C_49)) { return false; } + + bool result = false; + + if (FUNC_INIT == function) { + VEML6075Detect(); + } + else if (veml6075_active) { + switch (function) { + case FUNC_EVERY_SECOND: + VEML6075EverySecond(); + break; + case FUNC_COMMAND: + result = VEML6075Cmd(); + break; + case FUNC_JSON_APPEND: + VEML6075Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + VEML6075Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_VEML6075 +#endif // USE_I2C diff --git a/tasmota/xsns_71_veml7700.ino b/tasmota/xsns_71_veml7700.ino new file mode 100644 index 000000000..89bae9320 --- /dev/null +++ b/tasmota/xsns_71_veml7700.ino @@ -0,0 +1,117 @@ +/* + xsns_71_VEML7700.ino - VEML7700 Franklin Lightning Sensor support for Tasmota + + Copyright (C) 2020 Martin Wagner + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_I2C +#ifdef USE_VEML7700 +/*********************************************************************************************\ + * VEML7700 ALS Sensor + * Using the Adafruit VEML7700 Libary + * I2C Address: 0x10 +\*********************************************************************************************/ + +#define XSNS_71 71 +#define XI2C_50 50 // See I2CDEVICES.md + +#include "Adafruit_VEML7700.h" +Adafruit_VEML7700 veml7700 = Adafruit_VEML7700(); //create object copy + +#define D_NAME_VEML7700 "VEML7700" +#define D_WHITE_CONTENT "White content" + +const char HTTP_SNS_LUX[] PROGMEM = "{s}%s " D_ILLUMINANCE "{m}%d " D_UNIT_LUX " {e}"; +const char HTTP_SNS_WHITE[] PROGMEM = "{s}%s " D_WHITE_CONTENT "{m}%d {e}"; +const char JSON_SNS_VEML7700[] PROGMEM = ",\"%s\":{\"" D_JSON_ILLUMINANCE "\":%d,\"" D_JSON_WHITE_CONTENT "\":%d}"; + +struct VEML7700STRUCT +{ + char types[9] = D_NAME_VEML7700; + uint8_t address = VEML7700_I2CADDR_DEFAULT; + uint16_t lux = 0; + uint16_t white = 0; +} veml7700_sensor; + +uint8_t veml7700_active = 0; + +/********************************************************************************************/ + +void VEML7700Detect(void) { + if (I2cActive(veml7700_sensor.address)) return; + if (veml7700.begin()) { + I2cSetActiveFound(veml7700_sensor.address, veml7700_sensor.types); + veml7700_active = 1; + } +} + +void VEML7700EverySecond(void) { + veml7700_sensor.lux = (uint16_t) veml7700.readLux(); + veml7700_sensor.white = (uint16_t) veml7700.readWhite(); +} + +void VEML7700Show(bool json) +{ + if (json) { + ResponseAppend_P(JSON_SNS_VEML7700, D_NAME_VEML7700, veml7700_sensor.lux, veml7700_sensor.white); + +#ifdef USE_DOMOTICZ + if (0 == tele_period) DomoticzSensor(DZ_ILLUMINANCE, veml7700_sensor.lux); +#endif // USE_DOMOTICZ +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_SNS_LUX, D_NAME_VEML7700, veml7700_sensor.lux); + WSContentSend_PD(HTTP_SNS_WHITE, D_NAME_VEML7700, veml7700_sensor.white); +#endif // USE_WEBSERVER + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns71(uint8_t function) +{ + if (!I2cEnabled(XI2C_50)) { return false; } + + bool result = false; + + if (FUNC_INIT == function) { + VEML7700Detect(); + } + else if (veml7700_active) { + switch (function) { + case FUNC_EVERY_SECOND: + VEML7700EverySecond(); + break; + case FUNC_COMMAND: + //result = VEML7700Cmd(); + break; + case FUNC_JSON_APPEND: + VEML7700Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + VEML7700Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_VEML7700 +#endif // USE_I2C