commit ec125f27dbd7a183993629bf1169cb77410eda7f Author: Gašper Dobrovoljc Date: Sat Mar 11 15:11:03 2023 +0100 IP Configuration diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/include/README b/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/lib/Adafruit MPR121/Adafruit_MPR121.cpp b/lib/Adafruit MPR121/Adafruit_MPR121.cpp new file mode 100644 index 0000000..721a61f --- /dev/null +++ b/lib/Adafruit MPR121/Adafruit_MPR121.cpp @@ -0,0 +1,277 @@ +/*! + * @file Adafruit_MPR121.cpp + * + * @mainpage Adafruit MPR121 arduino driver + * + * @section intro_sec Introduction + * + * This is a library for the MPR121 I2C 12-chan Capacitive Sensor + * + * Designed specifically to work with the MPR121 sensor from Adafruit + * ----> https://www.adafruit.com/products/1982 + * + * These sensors use 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! + * + * @section author Author + * + * Written by Limor Fried/Ladyada for Adafruit Industries. + * + * @section license License + * + * BSD license, all text here must be included in any redistribution. + */ + +#include "Adafruit_MPR121.h" + +// uncomment to use autoconfig ! +//#define AUTOCONFIG // use autoconfig (Yes it works pretty well!) + +/*! + * @brief Default constructor + */ +Adafruit_MPR121::Adafruit_MPR121() {} + +/*! + * @brief Begin an MPR121 object on a given I2C bus. This function resets + * the device and writes the default settings. + * @param sensibility5C + * together with sensibility5D sets the sensibility of the touch sensors + * @param sensibility5D + * @param i2caddr + * the i2c address the device can be found on. Defaults to 0x5A. + * @param *theWire + * Wire object + * @param touchThreshold + * touch detection threshold value + * @param releaseThreshold + * release detection threshold value + * @returns true on success, false otherwise + */ +bool Adafruit_MPR121::begin(uint8_t sensibility5C, uint8_t sensibility5D, + uint8_t i2caddr, TwoWire *theWire, + uint8_t touchThreshold, uint8_t releaseThreshold) { + if (i2c_dev) { + delete i2c_dev; + } + i2c_dev = new Adafruit_I2CDevice(i2caddr, theWire); + + if (!i2c_dev->begin()) { + return false; + } + + // soft reset + writeRegister(MPR121_SOFTRESET, 0x63); + delay(1); + for (uint8_t i = 0; i < 0x7F; i++) { + // Serial.print("$"); Serial.print(i, HEX); + // Serial.print(": 0x"); Serial.println(readRegister8(i)); + } + + writeRegister(MPR121_ECR, 0x80); + // writeRegister(MPR121_ECR, 0x0); + + uint8_t c = readRegister8(MPR121_CONFIG2); + + if (c != 0x24) return false; + + setThresholds(touchThreshold, releaseThreshold); + writeRegister(MPR121_MHDR, 0x01); + writeRegister(MPR121_NHDR, 0x01); + writeRegister(MPR121_NCLR, 0x0E); + writeRegister(MPR121_FDLR, 0x00); + + writeRegister(MPR121_MHDF, 0x01); + writeRegister(MPR121_NHDF, 0x05); + writeRegister(MPR121_NCLF, 0x01); + writeRegister(MPR121_FDLF, 0x00); + + writeRegister(MPR121_NHDT, 0x00); + writeRegister(MPR121_NCLT, 0x00); + writeRegister(MPR121_FDLT, 0x00); + + // writeRegister(MPR121_DEBOUNCE, 0x32); + // change this values to extend the range of the sensibility of the sensors + writeRegister(MPR121_CONFIG1, sensibility5C); + writeRegister(MPR121_CONFIG2, sensibility5D); + +#ifdef AUTOCONFIG + writeRegister(MPR121_AUTOCONFIG0, 0x2B); + // writeRegister(MPR121_AUTOCONFIG0, 0x20); + + // correct values for Vdd = 3.3V + writeRegister(MPR121_UPLIMIT, 200); // ((Vdd - 0.7)/Vdd) * 256 + writeRegister(MPR121_TARGETLIMIT, 180); // UPLIMIT * 0.9 + writeRegister(MPR121_LOWLIMIT, 130); // UPLIMIT * 0.65 +#endif + + // enable X electrodes and start MPR121 + byte ECR_SETTING = + 0b10000000 + 12; // 5 bits for baseline tracking & proximity disabled + X + // amount of electrodes running (12) + writeRegister(MPR121_ECR, ECR_SETTING); // start with above ECR setting + + return true; +} + +/*! + * @brief DEPRECATED. Use Adafruit_MPR121::setThresholds(uint8_t touch, + * uint8_t release) instead. + * @param touch + * see Adafruit_MPR121::setThresholds(uint8_t touch, uint8_t + * *release) + * @param release + * see Adafruit_MPR121::setThresholds(uint8_t touch, *uint8_t + * release) + */ +void Adafruit_MPR121::setThreshholds(uint8_t touch, uint8_t release) { + setThresholds(touch, release); +} + +/*! + * @brief Set the touch and release thresholds for all 13 channels on the + * device to the passed values. The threshold is defined as a + * deviation value from the baseline value, so it remains constant + * even baseline value changes. Typically the touch threshold is a little bigger + * than the release threshold to touch debounce and hysteresis. For typical + * touch application, the value can be in range 0x05~0x30 for example. The + * setting of the threshold is depended on the actual application. For the + * operation details and how to set the threshold refer to application note + * AN3892 and MPR121 design guidelines. + * @param touch + * the touch threshold value from 0 to 255. + * @param release + * the release threshold from 0 to 255. + */ +void Adafruit_MPR121::setThresholds(uint8_t touch, uint8_t release) { + // set all thresholds (the same) + for (uint8_t i = 0; i < 12; i++) { + writeRegister(MPR121_TOUCHTH_0 + 2 * i, touch); + writeRegister(MPR121_RELEASETH_0 + 2 * i, release); + } +} + +/*! + * @brief Read the filtered data from channel t. The ADC raw data outputs + * run through 3 levels of digital filtering to filter out the high + * frequency and low frequency noise encountered. For detailed information on + * this filtering see page 6 of the device datasheet. + * @param t + * the channel to read + * @returns the filtered reading as a 10 bit unsigned value + */ +uint16_t Adafruit_MPR121::filteredData(uint8_t t) { + if (t > 12) return 0; + return readRegister16(MPR121_FILTDATA_0L + t * 2); +} + +/*! + * @brief Read the baseline value for the channel. The 3rd level filtered + * result is internally 10bit but only high 8 bits are readable + * from registers 0x1E~0x2A as the baseline value output for each channel. + * @param t + * the channel to read. + * @returns the baseline data that was read + */ +uint16_t Adafruit_MPR121::baselineData(uint8_t t) { + if (t > 12) return 0; + uint16_t bl = readRegister8(MPR121_BASELINE_0 + t); + return (bl << 2); +} + +/** + * @brief Read the touch status of all 13 channels and the over current + * status in a 16 bit integer. + * @returns a 16 bit integer where the 12 lower bits contain the touch status of + * the 12 touch sensors. Then, the 13th bit contains the status of the proximiti sensor, + * if used. The highest bit contains the status of the over current flag. + */ +uint16_t Adafruit_MPR121::touched(void) { + uint16_t t = readRegister16(MPR121_TOUCHSTATUS_L); + return t & 0x9FFF; +} + +/*! + * @brief Read the contents of an 8 bit device register. + * @param reg the register address to read from + * @returns the 8 bit value that was read. + */ +uint8_t Adafruit_MPR121::readRegister8(uint8_t reg) { + Adafruit_BusIO_Register thereg = Adafruit_BusIO_Register(i2c_dev, reg, 1); + + return (thereg.read()); +} + +/*! + * @brief Check if during the configuration or the auto-configuration the sensors + went out of range, hence no touch could be sensed. Only the 2 ightest bits are checked + because they are the bits that inform about this error. Even if the ids of the failing + channels are set in the lowest bits, this is not used here. + * @returns true if the configuration or the auto-configuration could not be performed. + */ +bool Adafruit_MPR121::wentOutOfRange(void) { + uint16_t e = readRegister8(MPR121_STATUS_H); + + // check for bits 1100 0000. + return (e & 0xC0); +} + +/*! +* @brief Check if the sensor had an over current, hence it's in an error status an no +* sensing could be performed. It does it by checking the highest bit of the touched array +* (see page 11 in sensor documnetation). +* @param touched the array with the results of the touch check, where the highest contains +* the error status +* @returns true if the sensor had an over current, false otherwise +*/ +bool Adafruit_MPR121::hadOverCurrent(uint16_t touched) { + return (touched & 0x8000); + } + +/*! + * @brief Read the contents of a 16 bit device register. + * @param reg the register address to read from + * @returns the 16 bit value that was read. + */ +uint16_t Adafruit_MPR121::readRegister16(uint8_t reg) { + Adafruit_BusIO_Register thereg = + Adafruit_BusIO_Register(i2c_dev, reg, 2, LSBFIRST); + + return (thereg.read()); +} + +/*! + @brief Writes 8-bits to the specified destination register + @param reg the register address to write to + @param value the value to write +*/ +void Adafruit_MPR121::writeRegister(uint8_t reg, uint8_t value) { + // MPR121 must be put in Stop Mode to write to most registers + bool stop_required = true; + + // first get the current set value of the MPR121_ECR register + Adafruit_BusIO_Register ecr_reg = + Adafruit_BusIO_Register(i2c_dev, MPR121_ECR, 1); + + uint8_t ecr_backup = ecr_reg.read(); + if ((reg == MPR121_ECR) || ((0x73 <= reg) && (reg <= 0x7A))) { + stop_required = false; + } + + if (stop_required) { + // clear this register to set stop mode + ecr_reg.write(0x00); + } + + Adafruit_BusIO_Register the_reg = Adafruit_BusIO_Register(i2c_dev, reg, 1); + the_reg.write(value); + + if (stop_required) { + // write back the previous set ECR settings + ecr_reg.write(ecr_backup); + } +} diff --git a/lib/Adafruit MPR121/Adafruit_MPR121.h b/lib/Adafruit MPR121/Adafruit_MPR121.h new file mode 100644 index 0000000..5f2d597 --- /dev/null +++ b/lib/Adafruit MPR121/Adafruit_MPR121.h @@ -0,0 +1,119 @@ +/*! + * @file Adafruit_MPR121.h + * + * This is a library for the MPR121 12-Channel Capacitive Sensor + * + * Designed specifically to work with the MPR121 board. + * + * Pick one up today in the adafruit shop! + * ------> https://www.adafruit.com/product/1982 + * + * These sensors use I2C to communicate, 2+ pins are required to interface + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit andopen-source hardware by purchasing products + * from Adafruit! + * + * Limor Fried/Ladyada (Adafruit Industries). + * + * BSD license, all text above must be included in any redistribution + */ + +#ifndef ADAFRUIT_MPR121_H +#define ADAFRUIT_MPR121_H + +#include "Arduino.h" +#include +#include + +// The default I2C address +#define MPR121_I2CADDR_DEFAULT 0x5A ///< default I2C address +#define MPR121_TOUCH_THRESHOLD_DEFAULT 12 ///< default touch threshold value +#define MPR121_RELEASE_THRESHOLD_DEFAULT 6 ///< default relese threshold value + +/*! + * Device register map + */ +enum { + MPR121_TOUCHSTATUS_L = 0x00, + MPR121_TOUCHSTATUS_H = 0x01, + MPR121_STATUS_L = 0x02, + MPR121_STATUS_H = 0x03, + MPR121_FILTDATA_0L = 0x04, + MPR121_FILTDATA_0H = 0x05, + MPR121_BASELINE_0 = 0x1E, + MPR121_MHDR = 0x2B, + MPR121_NHDR = 0x2C, + MPR121_NCLR = 0x2D, + MPR121_FDLR = 0x2E, + MPR121_MHDF = 0x2F, + MPR121_NHDF = 0x30, + MPR121_NCLF = 0x31, + MPR121_FDLF = 0x32, + MPR121_NHDT = 0x33, + MPR121_NCLT = 0x34, + MPR121_FDLT = 0x35, + + MPR121_TOUCHTH_0 = 0x41, + MPR121_RELEASETH_0 = 0x42, + MPR121_DEBOUNCE = 0x5B, + MPR121_CONFIG1 = 0x5C, + MPR121_CONFIG2 = 0x5D, + MPR121_CHARGECURR_0 = 0x5F, + MPR121_CHARGETIME_1 = 0x6C, + MPR121_ECR = 0x5E, + MPR121_AUTOCONFIG0 = 0x7B, + MPR121_AUTOCONFIG1 = 0x7C, + MPR121_UPLIMIT = 0x7D, + MPR121_LOWLIMIT = 0x7E, + MPR121_TARGETLIMIT = 0x7F, + + MPR121_GPIODIR = 0x76, + MPR121_GPIOEN = 0x77, + MPR121_GPIOSET = 0x78, + MPR121_GPIOCLR = 0x79, + MPR121_GPIOTOGGLE = 0x7A, + + MPR121_SOFTRESET = 0x80, +}; + +//.. thru to 0x1C/0x1D + +/*! + * @brief Class that stores state and functions for interacting with MPR121 + * proximity capacitive touch sensor controller. + */ +class Adafruit_MPR121 { +public: + // Hardware I2C + Adafruit_MPR121(); + + bool begin(uint8_t sensibility5C, uint8_t sensibility5D, + uint8_t i2caddr = MPR121_I2CADDR_DEFAULT, + TwoWire *theWire = &Wire, + uint8_t touchThreshold = MPR121_TOUCH_THRESHOLD_DEFAULT, + uint8_t releaseThreshold = MPR121_RELEASE_THRESHOLD_DEFAULT); + + uint16_t filteredData(uint8_t t); + uint16_t baselineData(uint8_t t); + + uint8_t readRegister8(uint8_t reg); + uint16_t readRegister16(uint8_t reg); + void writeRegister(uint8_t reg, uint8_t value); + uint16_t touched(void); + // Add deprecated attribute so that the compiler shows a warning + void setThreshholds(uint8_t touch, uint8_t release) + __attribute__((deprecated)); + void setThresholds(uint8_t touch, uint8_t release); + + // Function that checks if any of the sensors went our of rance + bool wentOutOfRange(); + + // Function that checks if any of the sensors had an overcurrent + bool hadOverCurrent(uid_t touched); + +private: + Adafruit_I2CDevice *i2c_dev = NULL; +}; + +#endif diff --git a/lib/Adafruit MPR121/README.md b/lib/Adafruit MPR121/README.md new file mode 100644 index 0000000..d0ef698 --- /dev/null +++ b/lib/Adafruit MPR121/README.md @@ -0,0 +1,17 @@ +# Adafruit MPR121 Library [![Build Status](https://github.com/adafruit/Adafruit_MPR121/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_MPR121/actions) + + + + +Tested and works great with the Adafruit MPR121 + * https://www.adafruit.com/products/1982 + * https://www.adafruit.com/product/2024 + * https://www.adafruit.com/product/2340 + +Check out the links above for our tutorials and wiring diagrams. +These sensors use 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 Limor Fried/Ladyada (Adafruit Industries). +MIT license, all text above must be included in any redistribution diff --git a/lib/Adafruit MPR121/keywords.txt b/lib/Adafruit MPR121/keywords.txt new file mode 100644 index 0000000..6e5e79c --- /dev/null +++ b/lib/Adafruit MPR121/keywords.txt @@ -0,0 +1,6 @@ +Adafruit_MPR121 KEYWORD1 +begin KEYWORD2 +filteredData KEYWORD2 +baselineData KEYWORD2 +touched KEYWORD2 +setThresholds KEYWORD2 \ No newline at end of file diff --git a/lib/Adafruit MPR121/library.properties b/lib/Adafruit MPR121/library.properties new file mode 100644 index 0000000..02abaa2 --- /dev/null +++ b/lib/Adafruit MPR121/library.properties @@ -0,0 +1,10 @@ +name=Adafruit MPR121 +version=1.1.0 +author=Adafruit +maintainer=Adafruit +sentence=Arduino library for the MPR121-based capacitive sensors in the Adafruit shop. +paragraph=Designed specifically to work with the MPR121 Breakout in the Adafruit shop. +category=Sensors +url=https://github.com/adafruit/Adafruit_MPR121 +architectures=* +depends=Adafruit BusIO diff --git a/lib/Adafruit-MCP23008/.github/ISSUE_TEMPLATE.md b/lib/Adafruit-MCP23008/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..f0e2614 --- /dev/null +++ b/lib/Adafruit-MCP23008/.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-MCP23008/.github/PULL_REQUEST_TEMPLATE.md b/lib/Adafruit-MCP23008/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..7b641eb --- /dev/null +++ b/lib/Adafruit-MCP23008/.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-MCP23008/Adafruit_MCP23008.cpp b/lib/Adafruit-MCP23008/Adafruit_MCP23008.cpp new file mode 100644 index 0000000..40898fa --- /dev/null +++ b/lib/Adafruit-MCP23008/Adafruit_MCP23008.cpp @@ -0,0 +1,187 @@ +/*************************************************** + This is a library for the MCP23008 i2c port expander + + These displays use 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 Limor Fried/Ladyada for Adafruit Industries. + BSD license, all text above must be included in any redistribution + ****************************************************/ + +#if ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif +#ifdef __AVR_ATtiny85__ + #include + #define Wire TinyWireM +#else + #include +#endif + +#ifdef __AVR + #include +#elif defined(ESP8266) + #include +#endif +#include "Adafruit_MCP23008.h" + + +//////////////////////////////////////////////////////////////////////////////// +// RTC_DS1307 implementation + +void Adafruit_MCP23008::begin(uint8_t addr) { + if (addr > 7) { + addr = 7; + } + i2caddr = addr; + + Wire.begin(); + + // set defaults! + Wire.beginTransmission(MCP23008_ADDRESS | i2caddr); +#if ARDUINO >= 100 + Wire.write((byte)MCP23008_IODIR); + Wire.write((byte)0xFF); // all inputs + Wire.write((byte)0x00); + Wire.write((byte)0x00); + Wire.write((byte)0x00); + Wire.write((byte)0x00); + Wire.write((byte)0x00); + Wire.write((byte)0x00); + Wire.write((byte)0x00); + Wire.write((byte)0x00); + Wire.write((byte)0x00); +#else + Wire.send(MCP23008_IODIR); + Wire.send(0xFF); // all inputs + Wire.send(0x00); + Wire.send(0x00); + Wire.send(0x00); + Wire.send(0x00); + Wire.send(0x00); + Wire.send(0x00); + Wire.send(0x00); + Wire.send(0x00); + Wire.send(0x00); +#endif + Wire.endTransmission(); + +} + +void Adafruit_MCP23008::begin(void) { + begin(0); +} + +void Adafruit_MCP23008::pinMode(uint8_t p, uint8_t d) { + uint8_t iodir; + + + // only 8 bits! + if (p > 7) + return; + + iodir = read8(MCP23008_IODIR); + + // set the pin and direction + if (d == INPUT) { + iodir |= 1 << p; + } else { + iodir &= ~(1 << p); + } + + // write the new IODIR + write8(MCP23008_IODIR, iodir); +} + +uint8_t Adafruit_MCP23008::readGPIO(void) { + // read the current GPIO input + return read8(MCP23008_GPIO); +} + +void Adafruit_MCP23008::writeGPIO(uint8_t gpio) { + write8(MCP23008_GPIO, gpio); +} + + +void Adafruit_MCP23008::digitalWrite(uint8_t p, uint8_t d) { + uint8_t gpio; + + // only 8 bits! + if (p > 7) + return; + + // read the current GPIO output latches + gpio = readGPIO(); + + // set the pin and direction + if (d == HIGH) { + gpio |= 1 << p; + } else { + gpio &= ~(1 << p); + } + + // write the new GPIO + writeGPIO(gpio); +} + +void Adafruit_MCP23008::pullUp(uint8_t p, uint8_t d) { + uint8_t gppu; + + // only 8 bits! + if (p > 7) + return; + + gppu = read8(MCP23008_GPPU); + // set the pin and direction + if (d == HIGH) { + gppu |= 1 << p; + } else { + gppu &= ~(1 << p); + } + // write the new GPIO + write8(MCP23008_GPPU, gppu); +} + +uint8_t Adafruit_MCP23008::digitalRead(uint8_t p) { + // only 8 bits! + if (p > 7) + return 0; + + // read the current GPIO + return (readGPIO() >> p) & 0x1; +} + +uint8_t Adafruit_MCP23008::read8(uint8_t addr) { + Wire.beginTransmission(MCP23008_ADDRESS | i2caddr); +#if ARDUINO >= 100 + Wire.write((byte)addr); +#else + Wire.send(addr); +#endif + Wire.endTransmission(); + Wire.requestFrom(MCP23008_ADDRESS | i2caddr, 1); + +#if ARDUINO >= 100 + return Wire.read(); +#else + return Wire.receive(); +#endif +} + + +void Adafruit_MCP23008::write8(uint8_t addr, uint8_t data) { + Wire.beginTransmission(MCP23008_ADDRESS | i2caddr); +#if ARDUINO >= 100 + Wire.write((byte)addr); + Wire.write((byte)data); +#else + Wire.send(addr); + Wire.send(data); +#endif + Wire.endTransmission(); +} diff --git a/lib/Adafruit-MCP23008/Adafruit_MCP23008.h b/lib/Adafruit-MCP23008/Adafruit_MCP23008.h new file mode 100644 index 0000000..549eb43 --- /dev/null +++ b/lib/Adafruit-MCP23008/Adafruit_MCP23008.h @@ -0,0 +1,56 @@ +/*************************************************** + This is a library for the MCP23008 i2c port expander + + These displays use 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 Limor Fried/Ladyada for Adafruit Industries. + BSD license, all text above must be included in any redistribution + ****************************************************/ + +#ifndef _ADAFRUIT_MCP23008_H +#define _ADAFRUIT_MCP23008_H +// Don't forget the Wire library +#ifdef __AVR_ATtiny85__ + #include +#else + #include +#endif + +class Adafruit_MCP23008 { +public: + void begin(uint8_t addr); + void begin(void); + + void pinMode(uint8_t p, uint8_t d); + void digitalWrite(uint8_t p, uint8_t d); + void pullUp(uint8_t p, uint8_t d); + uint8_t digitalRead(uint8_t p); + uint8_t readGPIO(void); + void writeGPIO(uint8_t); + + private: + uint8_t i2caddr; + uint8_t read8(uint8_t addr); + void write8(uint8_t addr, uint8_t data); +}; + +#define MCP23008_ADDRESS 0x20 + +// registers +#define MCP23008_IODIR 0x00 +#define MCP23008_IPOL 0x01 +#define MCP23008_GPINTEN 0x02 +#define MCP23008_DEFVAL 0x03 +#define MCP23008_INTCON 0x04 +#define MCP23008_IOCON 0x05 +#define MCP23008_GPPU 0x06 +#define MCP23008_INTF 0x07 +#define MCP23008_INTCAP 0x08 +#define MCP23008_GPIO 0x09 +#define MCP23008_OLAT 0x0A + +#endif diff --git a/lib/Adafruit-MCP23008/README b/lib/Adafruit-MCP23008/README new file mode 100644 index 0000000..3b5f77e --- /dev/null +++ b/lib/Adafruit-MCP23008/README @@ -0,0 +1,19 @@ +To download, click "Download Source" in the top right corner. Then install as indicated in our tutorial: +--> http://www.ladyada.net/library/arduino/libraries.html +in a folder called Adafruit_MCP23008. + +This is very much beta, it seems to work fine but its not optimized and doesn't currently suport the interrupt capability of the chip + +Currently it can do: setting pin directions, inputs and outputs and turning on/off the pull-up resistors + +To use: +Connect pin #1 of the expander to Analog 5 (i2c clock) +Connect pin #2 of the expander to Analog 4 (i2c data) +Connect pins #3, 4 and 5 of the expander to ground (address selection) +Connect pin #6 and 18 of the expander to 5V (power and reset disable) +Connect pin #9 of the expander to ground (common ground) +Pins 10 thru 17 are your input/output pins + +Check the datasheet for more info: http://ww1.microchip.com/downloads/en/DeviceDoc/21919b.pdf + +Enjoy and send pull requests! \ No newline at end of file diff --git a/lib/Adafruit-MCP23008/examples/button/button.pde b/lib/Adafruit-MCP23008/examples/button/button.pde new file mode 100644 index 0000000..17e8a12 --- /dev/null +++ b/lib/Adafruit-MCP23008/examples/button/button.pde @@ -0,0 +1,31 @@ +#include +#include "Adafruit_MCP23008.h" + +// Basic pin reading and pullup test for the MCP23008 I/O expander +// public domain! + +// Connect pin #1 of the expander to Analog 5 (i2c clock) +// Connect pin #2 of the expander to Analog 4 (i2c data) +// Connect pins #3, 4 and 5 of the expander to ground (address selection) +// Connect pin #6 and 18 of the expander to 5V (power and reset disable) +// Connect pin #9 of the expander to ground (common ground) + +// Input #0 is on pin 10 so connect a button or switch from there to ground + +Adafruit_MCP23008 mcp; + +void setup() { + mcp.begin(); // use default address 0 + + mcp.pinMode(0, INPUT); + mcp.pullUp(0, HIGH); // turn on a 100K pullup internally + + pinMode(13, OUTPUT); // use the p13 LED as debugging +} + + + +void loop() { + // The LED will 'echo' the button + digitalWrite(13, mcp.digitalRead(0)); +} \ No newline at end of file diff --git a/lib/Adafruit-MCP23008/examples/toggle/toggle.pde b/lib/Adafruit-MCP23008/examples/toggle/toggle.pde new file mode 100644 index 0000000..e984abe --- /dev/null +++ b/lib/Adafruit-MCP23008/examples/toggle/toggle.pde @@ -0,0 +1,34 @@ +#include +#include "Adafruit_MCP23008.h" + +// Basic toggle test for i/o expansion. flips pin #0 of a MCP23008 i2c +// pin expander up and down. Public domain + +// Connect pin #1 of the expander to Analog 5 (i2c clock) +// Connect pin #2 of the expander to Analog 4 (i2c data) +// Connect pins #3, 4 and 5 of the expander to ground (address selection) +// Connect pin #6 and 18 of the expander to 5V (power and reset disable) +// Connect pin #9 of the expander to ground (common ground) + +// Output #0 is on pin 10 so connect an LED or whatever from that to ground + +Adafruit_MCP23008 mcp; + +void setup() { + mcp.begin(); // use default address 0 + + mcp.pinMode(0, OUTPUT); +} + + +// flip the pin #0 up and down + +void loop() { + delay(100); + + mcp.digitalWrite(0, HIGH); + + delay(100); + + mcp.digitalWrite(0, LOW); +} \ No newline at end of file diff --git a/lib/Adafruit-MCP23008/keywords.txt b/lib/Adafruit-MCP23008/keywords.txt new file mode 100644 index 0000000..5d42b84 --- /dev/null +++ b/lib/Adafruit-MCP23008/keywords.txt @@ -0,0 +1,20 @@ +####################################### +# Syntax Coloring Map for MCP23008 +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +MCP23008 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +pullUp KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/lib/Adafruit-MCP23008/library.properties b/lib/Adafruit-MCP23008/library.properties new file mode 100644 index 0000000..07f1b0e --- /dev/null +++ b/lib/Adafruit-MCP23008/library.properties @@ -0,0 +1,9 @@ +name=Adafruit MCP23008 library +version=1.0.2 +author=Adafruit +maintainer=Adafruit +sentence=Arduino Library for the MCP23008 (and '9) I2C I/O expander +paragraph=Arduino Library for the MCP23008 (and '9) I2C I/O expander +category=Signal Input/Output +url=https://github.com/adafruit/Adafruit-MCP23008-library +architectures=* diff --git a/lib/Adafruit_AM2320_sensor_library/Adafruit_AM2320.cpp b/lib/Adafruit_AM2320_sensor_library/Adafruit_AM2320.cpp new file mode 100644 index 0000000..648023c --- /dev/null +++ b/lib/Adafruit_AM2320_sensor_library/Adafruit_AM2320.cpp @@ -0,0 +1,321 @@ +/*! + * @file Adafruit_AM2320.cpp + * + * @mainpage Adafruit AM2320 Temperature & Humidity Unified Sensor driver + * + * @section intro_sec Introduction + * + * This is the documentation for Adafruit's AM2320 driver for the + * Arduino platform. It is designed specifically to work with the + * Adafruit AM2320 breakout: https://www.adafruit.com/products/xxxx + * + * These sensors use I2C to communicate, 2 pins (SCL+SDA) are required + * to interface with the breakout. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * @section dependencies Dependencies + * + * This library depends on + * Adafruit_Sensor being present on your system. Please make sure you have + * installed the latest version before using this library. + * + * @section author Author + * + * Written by Limor Fried for Adafruit Industries. + * + * @section license License + * + * 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. + * + */ + +#include "Adafruit_AM2320.h" + + /**************************************************************************/ + /*! + @brief Instantiates a new AM2320 class + @param theI2C Optional pointer to a TwoWire object that should be used for I2C communication. Defaults to &Wire. + @param tempSensorId the id that should be used for the temperature sensor. Defaults to -1 + @param humiditySensorId the id that should be used for the humidity sensor. Defaults to -1 + */ + /**************************************************************************/ +Adafruit_AM2320::Adafruit_AM2320(TwoWire *theI2C, int32_t tempSensorId, int32_t humiditySensorId): + _temp(this, tempSensorId), + _humidity(this, humiditySensorId), + _i2c(theI2C) +{} + +/**************************************************************************/ +/*! + @brief Setups the hardware + @return true +*/ +/**************************************************************************/ +bool Adafruit_AM2320::begin() { + _i2caddr = 0x5C; // fixed addr + _i2c->begin(); + return true; +} + +/**************************************************************************/ +/*! + @brief read the temperature from the device + @return the temperature reading as a floating point value +*/ +/**************************************************************************/ +float Adafruit_AM2320::readTemperature() { + uint16_t t = readRegister16(AM2320_REG_TEMP_H); + float ft; + if (t == 0xFFFF) return NAN; + // check sign bit - the temperature MSB is signed , bit 0-15 are magnitude + if(t & 0x8000){ + ft = -(int16_t)(t&0x7fff); + } + else { + ft = (int16_t)t; + } + return ft / 10.0; +} + +/**************************************************************************/ +/*! + @brief read the humidity from the device + @return the humidity reading as a floating point value +*/ +/**************************************************************************/ +float Adafruit_AM2320::readHumidity() { + uint16_t h = readRegister16(AM2320_REG_HUM_H); + if (h == 0xFFFF) return NAN; + + float fh = h; + return fh / 10.0; +} + +/**************************************************************************/ +/*! + @brief read 2 bytes from a hardware register + @param reg the register to read + @return the read value as a 2 byte unsigned integer +*/ +/**************************************************************************/ +uint16_t Adafruit_AM2320::readRegister16(uint8_t reg) { + // wake up + Wire.beginTransmission(_i2caddr); + Wire.write(0x00); + Wire.endTransmission(); + delay(10); // wait 10 ms + + // send a command to read register + Wire.beginTransmission(_i2caddr); + Wire.write(AM2320_CMD_READREG); + Wire.write(reg); + Wire.write(2); // 2 bytes + Wire.endTransmission(); + + delay(2); // wait 2 ms + + // 2 bytes preamble, 2 bytes data, 2 bytes CRC + Wire.requestFrom(_i2caddr, (uint8_t)6); + if (Wire.available() != 6) + return 0xFFFF; + + uint8_t buffer[6]; + for (int i=0; i<6; i++) { + buffer[i] = Wire.read(); + //Serial.print("byte #"); Serial.print(i); Serial.print(" = 0x"); Serial.println(buffer[i], HEX); + } + + if (buffer[0] != 0x03) return 0xFFFF; // must be 0x03 modbus reply + if (buffer[1] != 2) return 0xFFFF; // must be 2 bytes reply + + uint16_t the_crc = buffer[5]; + the_crc <<= 8; + the_crc |= buffer[4]; + uint16_t calc_crc = crc16(buffer, 4); // preamble + data + //Serial.print("CRC: 0x"); Serial.println(calc_crc, HEX); + if (the_crc != calc_crc) + return 0xFFFF; + + // All good! + uint16_t ret = buffer[2]; + ret <<= 8; + ret |= buffer[3]; + + return ret; +} + +/**************************************************************************/ +/*! + @brief perfor a CRC check to verify data + @param buffer the pointer to the data to check + @param nbytes the number of bytes to calculate the CRC over + @return the calculated CRC +*/ +/**************************************************************************/ +uint16_t Adafruit_AM2320::crc16(uint8_t *buffer, uint8_t nbytes) { + uint16_t crc = 0xffff; + for (int i=0; i>= 1; + crc ^= 0xA001; + } else { + crc >>= 1; + } + } + } + return crc; +} + +/**************************************************************************/ +/*! + @brief set the name of the sensor + @param sensor a pointer to the sensor +*/ +/**************************************************************************/ +void Adafruit_AM2320::setName(sensor_t* sensor) { + strncpy(sensor->name, "AM2320", sizeof(sensor->name) - 1); +} + +/**************************************************************************/ +/*! + @brief set minimum delay to a fixed value of 2 seconds + @param sensor a pointer to the sensor +*/ +/**************************************************************************/ +void Adafruit_AM2320::setMinDelay(sensor_t* sensor) { + sensor->min_delay = 2000000L; // 2 seconds (in microseconds) +} + +/**************************************************************************/ +/*! + @brief create a temperature sensor instance + @param parent the pointer to the parent sensor + @param id the id value for the sensor +*/ +/**************************************************************************/ +Adafruit_AM2320::Temperature::Temperature(Adafruit_AM2320* parent, int32_t id): + _parent(parent), + _id(id) +{} + +/**************************************************************************/ +/*! + @brief read the temperature from the device and populate a sensor_event_t with the value + @param event a pointer to the event to populate + @return true +*/ +/**************************************************************************/ +bool Adafruit_AM2320::Temperature::getEvent(sensors_event_t* event) { + // Clear event definition. + memset(event, 0, sizeof(sensors_event_t)); + // Populate sensor reading values. + event->version = sizeof(sensors_event_t); + event->sensor_id = _id; + event->type = SENSOR_TYPE_AMBIENT_TEMPERATURE; + event->timestamp = millis(); + event->temperature = _parent->readTemperature(); + + return true; +} + +/**************************************************************************/ +/*! + @brief populate a sensor_t with data for this sensor + @param sensor a pointer to the sensor_t to populate +*/ +/**************************************************************************/ +void Adafruit_AM2320::Temperature::getSensor(sensor_t* sensor) { + // Clear sensor definition. + memset(sensor, 0, sizeof(sensor_t)); + // Set sensor name. + _parent->setName(sensor); + // Set version and ID + sensor->version = AM2320_SENSOR_VERSION; + sensor->sensor_id = _id; + // Set type and characteristics. + sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE; + _parent->setMinDelay(sensor); + + // This isn't documented, of course + sensor->max_value = 80.0F; + sensor->min_value = -20.0F; + sensor->resolution = 2.0F; +} + +/**************************************************************************/ +/*! + @brief create a humidity sensor instance + @param parent the pointer to the parent sensor + @param id the id value for the sensor +*/ +/**************************************************************************/ +Adafruit_AM2320::Humidity::Humidity(Adafruit_AM2320* parent, int32_t id): + _parent(parent), + _id(id) +{} + +/**************************************************************************/ +/*! + @brief read the humidity from the device and populate a sensor_event_t with the value + @param event a pointer to the event to populate + @return true +*/ +/**************************************************************************/ +bool Adafruit_AM2320::Humidity::getEvent(sensors_event_t* event) { + // Clear event definition. + memset(event, 0, sizeof(sensors_event_t)); + // Populate sensor reading values. + event->version = sizeof(sensors_event_t); + event->sensor_id = _id; + event->type = SENSOR_TYPE_RELATIVE_HUMIDITY; + event->timestamp = millis(); + event->relative_humidity = _parent->readHumidity(); + + return true; +} + +/**************************************************************************/ +/*! + @brief populate a sensor_t with data for this sensor + @param sensor a pointer to the sensor_t to populate +*/ +/**************************************************************************/ +void Adafruit_AM2320::Humidity::getSensor(sensor_t* sensor) { + // Clear sensor definition. + memset(sensor, 0, sizeof(sensor_t)); + // Set sensor name. + _parent->setName(sensor); + // Set version and ID + sensor->version = AM2320_SENSOR_VERSION; + sensor->sensor_id = _id; + // Set type and characteristics. + sensor->type = SENSOR_TYPE_RELATIVE_HUMIDITY; + _parent->setMinDelay(sensor); + + // This isn't documented, of course + sensor->max_value = 100.0F; + sensor->min_value = 0.0F; + sensor->resolution = 1.0F; +} diff --git a/lib/Adafruit_AM2320_sensor_library/Adafruit_AM2320.h b/lib/Adafruit_AM2320_sensor_library/Adafruit_AM2320.h new file mode 100644 index 0000000..3adb757 --- /dev/null +++ b/lib/Adafruit_AM2320_sensor_library/Adafruit_AM2320.h @@ -0,0 +1,122 @@ +/*! + * @file Adafruit_AM2320.h + * + * This is a library for the AM2320 Temperature & Humidity Unified Sensor breakout board + * ----> https://www.adafruit.com/products/xxxx + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Written by Limor Fried for 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. + * + */ + + +#ifndef ADAFRUIT_AM2320 +#define ADAFRUIT_AM2320 + +#define AM2320_SENSOR_VERSION 1 ///< the sensor version +#define AM2320_CMD_READREG 0x03 ///< read register command +#define AM2320_REG_TEMP_H 0x02 ///< temp register address +#define AM2320_REG_HUM_H 0x00 ///< humidity register address +#include +#include + +/**************************************************************************/ +/*! + @brief Class that stores state and functions for interacting with AM2320 Temperature & Humidity Unified Sensor +*/ +/**************************************************************************/ +class Adafruit_AM2320 { +public: + Adafruit_AM2320(TwoWire *theI2C = &Wire, int32_t tempSensorId=-1, int32_t humiditySensorId=-1); + bool begin(); + + float readTemperature(); + float readHumidity(); + uint16_t readRegister16(uint8_t reg); + uint16_t crc16(uint8_t *buffer, uint8_t nbytes); + + /**************************************************************************/ + /*! + @brief temperature sensor class + */ + /**************************************************************************/ + class Temperature : public Adafruit_Sensor { + public: + Temperature(Adafruit_AM2320* parent, int32_t id); + bool getEvent(sensors_event_t* event); + void getSensor(sensor_t* sensor); + + private: + Adafruit_AM2320* _parent; ///< the parent sensor object + int32_t _id; ///< the sensor id + }; + + /**************************************************************************/ + /*! + @brief humidity sensor class + */ + /**************************************************************************/ + class Humidity : public Adafruit_Sensor { + public: + Humidity(Adafruit_AM2320* parent, int32_t id); + bool getEvent(sensors_event_t* event); + void getSensor(sensor_t* sensor); + + private: + Adafruit_AM2320* _parent; ///< the parent sensor object + int32_t _id; ///< the sensor id + + }; + + /**************************************************************************/ + /*! + @brief get the temperature sensor object belonging to this class + @return the temperature sensor object + */ + /**************************************************************************/ + Temperature temperature() { + return _temp; + } + + /**************************************************************************/ + /*! + @brief get the humidity sensor object belonging to this class + @return the humidity sensor object + */ + /**************************************************************************/ + Humidity humidity() { + return _humidity; + } + +private: + Temperature _temp; ///< the temperature sensor object + Humidity _humidity; ///< the humidity sensor object + TwoWire *_i2c; ///< the TwoWire object used for I2C connumication + uint8_t _i2caddr; ///< the i2c address the device can be found on + + void setName(sensor_t* sensor); + void setMinDelay(sensor_t* sensor); +}; + +#endif diff --git a/lib/Adafruit_AM2320_sensor_library/README.md b/lib/Adafruit_AM2320_sensor_library/README.md new file mode 100644 index 0000000..18b5136 --- /dev/null +++ b/lib/Adafruit_AM2320_sensor_library/README.md @@ -0,0 +1,15 @@ +# Adafruit AM2320 Library [![Build Status](https://travis-ci.org/adafruit/Adafruit_AM2320.svg?branch=master)](https://travis-ci.org/adafruit/Adafruit_AM2320) + + + +This is a library for the Adafruit AM2320 Temperature & Humidity Unified Sensor + * https://www.adafruit.com/products/3721 + +Also supports AM2320 chips (and maybe other compatible chips!) + +Check out the links above for our tutorials and wiring diagrams. This chip uses I2C to communicate + +Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! + +Written by Limor Fried/Ladyada for Adafruit Industries. +MIT license, all text above must be included in any redistribution diff --git a/lib/Adafruit_AM2320_sensor_library/examples/basic_am2320/basic_am2320.ino b/lib/Adafruit_AM2320_sensor_library/examples/basic_am2320/basic_am2320.ino new file mode 100644 index 0000000..332de27 --- /dev/null +++ b/lib/Adafruit_AM2320_sensor_library/examples/basic_am2320/basic_am2320.ino @@ -0,0 +1,21 @@ +#include "Adafruit_Sensor.h" +#include "Adafruit_AM2320.h" + +Adafruit_AM2320 am2320 = Adafruit_AM2320(); + +void setup() { + Serial.begin(9600); + while (!Serial) { + delay(10); // hang out until serial port opens + } + + Serial.println("Adafruit AM2320 Basic Test"); + am2320.begin(); +} + +void loop() { + Serial.print("Temp: "); Serial.println(am2320.readTemperature()); + Serial.print("Hum: "); Serial.println(am2320.readHumidity()); + + delay(2000); +} \ No newline at end of file diff --git a/lib/Adafruit_AM2320_sensor_library/library.properties b/lib/Adafruit_AM2320_sensor_library/library.properties new file mode 100644 index 0000000..34c9394 --- /dev/null +++ b/lib/Adafruit_AM2320_sensor_library/library.properties @@ -0,0 +1,9 @@ +name=Adafruit AM2320 sensor library +version=1.1.1 +author=Adafruit +maintainer=Adafruit +sentence=Arduino library for AM2320 I2C Temp & Humidity Sensors +paragraph=Arduino library for AM2320 I2C Temp & Humidity Sensors +category=Sensors +url=https://github.com/adafruit/Adafruit_AM2320 +architectures=* diff --git a/lib/Adafruit_BME280_Library/Adafruit_BME280.cpp b/lib/Adafruit_BME280_Library/Adafruit_BME280.cpp new file mode 100644 index 0000000..29179cf --- /dev/null +++ b/lib/Adafruit_BME280_Library/Adafruit_BME280.cpp @@ -0,0 +1,614 @@ +/*! + * @file Adafruit_BME280.cpp + * + * @mainpage Adafruit BME280 humidity, temperature & pressure sensor + * + * @section intro_sec Introduction + * + * Driver for the BME280 humidity, temperature & pressure sensor + * + * These sensors use I2C or SPI to communicate, 2 or 4 pins are required + * to interface. + * + * Designed specifically to work with the Adafruit BME280 Breakout + * ----> http://www.adafruit.com/products/2650 + * + * 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 + * + * Written by Kevin "KTOWN" Townsend for Adafruit Industries. + * + * @section license License + * + * BSD license, all text here must be included in any redistribution. + * + */ + +#include "Arduino.h" +#include +#include +#include "Adafruit_BME280.h" + +/**************************************************************************/ +/*! + @brief class constructor +*/ +/**************************************************************************/ +Adafruit_BME280::Adafruit_BME280() + : _cs(-1), _mosi(-1), _miso(-1), _sck(-1) +{ } + +/**************************************************************************/ +/*! + @brief class constructor if using hardware SPI + @param cspin the chip select pin to use +*/ +/**************************************************************************/ +Adafruit_BME280::Adafruit_BME280(int8_t cspin) + : _cs(cspin), _mosi(-1), _miso(-1), _sck(-1) +{ } + +/**************************************************************************/ +/*! + @brief class constructor if using software SPI + @param cspin the chip select pin to use + @param mosipin the MOSI pin to use + @param misopin the MISO pin to use + @param sckpin the SCK pin to use +*/ +/**************************************************************************/ +Adafruit_BME280::Adafruit_BME280(int8_t cspin, int8_t mosipin, int8_t misopin, int8_t sckpin) + : _cs(cspin), _mosi(mosipin), _miso(misopin), _sck(sckpin) +{ } + + +/**************************************************************************/ +/*! + @brief Initialise sensor with given parameters / settings + @param theWire the I2C object to use + @returns true on success, false otherwise +*/ +/**************************************************************************/ +bool Adafruit_BME280::begin(TwoWire *theWire) +{ + _wire = theWire; + _i2caddr = BME280_ADDRESS; + return init(); +} + +/**************************************************************************/ +/*! + @brief Initialise sensor with given parameters / settings + @param addr the I2C address the device can be found on + @returns true on success, false otherwise +*/ +/**************************************************************************/ +bool Adafruit_BME280::begin(uint8_t addr) +{ + _i2caddr = addr; + _wire = &Wire; + return init(); +} + +/**************************************************************************/ +/*! + @brief Initialise sensor with given parameters / settings + @param addr the I2C address the device can be found on + @param theWire the I2C object to use + @returns true on success, false otherwise +*/ +/**************************************************************************/ +bool Adafruit_BME280::begin(uint8_t addr, TwoWire *theWire) +{ + _i2caddr = addr; + _wire = theWire; + return init(); +} + +/**************************************************************************/ +/*! + @brief Initialise sensor with given parameters / settings + @returns true on success, false otherwise +*/ +/**************************************************************************/ +bool Adafruit_BME280::begin(void) +{ + _i2caddr = BME280_ADDRESS; + _wire = &Wire; + return init(); +} + +/**************************************************************************/ +/*! + @brief Initialise sensor with given parameters / settings + @returns true on success, false otherwise +*/ +/**************************************************************************/ +bool Adafruit_BME280::init() +{ + // init I2C or SPI sensor interface + if (_cs == -1) { + // I2C + _wire -> begin(); + } else { + digitalWrite(_cs, HIGH); + pinMode(_cs, OUTPUT); + if (_sck == -1) { + // hardware SPI + SPI.begin(); + } else { + // software SPI + pinMode(_sck, OUTPUT); + pinMode(_mosi, OUTPUT); + pinMode(_miso, INPUT); + } + } + + // check if sensor, i.e. the chip ID is correct + if (read8(BME280_REGISTER_CHIPID) != 0x60) + return false; + + // reset the device using soft-reset + // this makes sure the IIR is off, etc. + write8(BME280_REGISTER_SOFTRESET, 0xB6); + + // wait for chip to wake up. + delay(300); + + // if chip is still reading calibration, delay + while (isReadingCalibration()) + delay(100); + + readCoefficients(); // read trimming parameters, see DS 4.2.2 + + setSampling(); // use defaults + + delay(100); + + return true; +} + +/**************************************************************************/ +/*! + @brief setup sensor with given parameters / settings + + This is simply a overload to the normal begin()-function, so SPI users + don't get confused about the library requiring an address. + @param mode the power mode to use for the sensor + @param tempSampling the temp samping rate to use + @param pressSampling the pressure sampling rate to use + @param humSampling the humidity sampling rate to use + @param filter the filter mode to use + @param duration the standby duration to use +*/ +/**************************************************************************/ +void Adafruit_BME280::setSampling(sensor_mode mode, + sensor_sampling tempSampling, + sensor_sampling pressSampling, + sensor_sampling humSampling, + sensor_filter filter, + standby_duration duration) { + _measReg.mode = mode; + _measReg.osrs_t = tempSampling; + _measReg.osrs_p = pressSampling; + + + _humReg.osrs_h = humSampling; + _configReg.filter = filter; + _configReg.t_sb = duration; + + + // you must make sure to also set REGISTER_CONTROL after setting the + // CONTROLHUMID register, otherwise the values won't be applied (see DS 5.4.3) + write8(BME280_REGISTER_CONTROLHUMID, _humReg.get()); + write8(BME280_REGISTER_CONFIG, _configReg.get()); + write8(BME280_REGISTER_CONTROL, _measReg.get()); +} + + +/**************************************************************************/ +/*! + @brief Encapsulate hardware and software SPI transfer into one function + @param x the data byte to transfer + @returns the data byte read from the device +*/ +/**************************************************************************/ +uint8_t Adafruit_BME280::spixfer(uint8_t x) { + // hardware SPI + if (_sck == -1) + return SPI.transfer(x); + + // software SPI + uint8_t reply = 0; + for (int i=7; i>=0; i--) { + reply <<= 1; + digitalWrite(_sck, LOW); + digitalWrite(_mosi, x & (1< beginTransmission((uint8_t)_i2caddr); + _wire -> write((uint8_t)reg); + _wire -> write((uint8_t)value); + _wire -> endTransmission(); + } else { + if (_sck == -1) + SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); + digitalWrite(_cs, LOW); + spixfer(reg & ~0x80); // write, bit 7 low + spixfer(value); + digitalWrite(_cs, HIGH); + if (_sck == -1) + SPI.endTransaction(); // release the SPI bus + } +} + + +/**************************************************************************/ +/*! + @brief Reads an 8 bit value over I2C or SPI + @param reg the register address to read from + @returns the data byte read from the device +*/ +/**************************************************************************/ +uint8_t Adafruit_BME280::read8(byte reg) { + uint8_t value; + + if (_cs == -1) { + _wire -> beginTransmission((uint8_t)_i2caddr); + _wire -> write((uint8_t)reg); + _wire -> endTransmission(); + _wire -> requestFrom((uint8_t)_i2caddr, (byte)1); + value = _wire -> read(); + } else { + if (_sck == -1) + SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); + digitalWrite(_cs, LOW); + spixfer(reg | 0x80); // read, bit 7 high + value = spixfer(0); + digitalWrite(_cs, HIGH); + if (_sck == -1) + SPI.endTransaction(); // release the SPI bus + } + return value; +} + + +/**************************************************************************/ +/*! + @brief Reads a 16 bit value over I2C or SPI + @param reg the register address to read from + @returns the 16 bit data value read from the device +*/ +/**************************************************************************/ +uint16_t Adafruit_BME280::read16(byte reg) +{ + uint16_t value; + + if (_cs == -1) { + _wire -> beginTransmission((uint8_t)_i2caddr); + _wire -> write((uint8_t)reg); + _wire -> endTransmission(); + _wire -> requestFrom((uint8_t)_i2caddr, (byte)2); + value = (_wire -> read() << 8) | _wire -> read(); + } else { + if (_sck == -1) + SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); + digitalWrite(_cs, LOW); + spixfer(reg | 0x80); // read, bit 7 high + value = (spixfer(0) << 8) | spixfer(0); + digitalWrite(_cs, HIGH); + if (_sck == -1) + SPI.endTransaction(); // release the SPI bus + } + + return value; +} + + +/**************************************************************************/ +/*! + @brief Reads a signed 16 bit little endian value over I2C or SPI + @param reg the register address to read from + @returns the 16 bit data value read from the device +*/ +/**************************************************************************/ +uint16_t Adafruit_BME280::read16_LE(byte reg) { + uint16_t temp = read16(reg); + return (temp >> 8) | (temp << 8); +} + + +/**************************************************************************/ +/*! + @brief Reads a signed 16 bit value over I2C or SPI + @param reg the register address to read from + @returns the 16 bit data value read from the device +*/ +/**************************************************************************/ +int16_t Adafruit_BME280::readS16(byte reg) +{ + return (int16_t)read16(reg); +} + + +/**************************************************************************/ +/*! + @brief Reads a signed little endian 16 bit value over I2C or SPI + @param reg the register address to read from + @returns the 16 bit data value read from the device +*/ +/**************************************************************************/ +int16_t Adafruit_BME280::readS16_LE(byte reg) +{ + return (int16_t)read16_LE(reg); +} + + +/**************************************************************************/ +/*! + @brief Reads a 24 bit value over I2C + @param reg the register address to read from + @returns the 24 bit data value read from the device +*/ +/**************************************************************************/ +uint32_t Adafruit_BME280::read24(byte reg) +{ + uint32_t value; + + if (_cs == -1) { + _wire -> beginTransmission((uint8_t)_i2caddr); + _wire -> write((uint8_t)reg); + _wire -> endTransmission(); + _wire -> requestFrom((uint8_t)_i2caddr, (byte)3); + + value = _wire -> read(); + value <<= 8; + value |= _wire -> read(); + value <<= 8; + value |= _wire -> read(); + } else { + if (_sck == -1) + SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); + digitalWrite(_cs, LOW); + spixfer(reg | 0x80); // read, bit 7 high + + value = spixfer(0); + value <<= 8; + value |= spixfer(0); + value <<= 8; + value |= spixfer(0); + + digitalWrite(_cs, HIGH); + if (_sck == -1) + SPI.endTransaction(); // release the SPI bus + } + + return value; +} + + +/**************************************************************************/ +/*! + @brief Take a new measurement (only possible in forced mode) +*/ +/**************************************************************************/ +void Adafruit_BME280::takeForcedMeasurement() +{ + // If we are in forced mode, the BME sensor goes back to sleep after each + // measurement and we need to set it to forced mode once at this point, so + // it will take the next measurement and then return to sleep again. + // In normal mode simply does new measurements periodically. + if (_measReg.mode == MODE_FORCED) { + // set to forced mode, i.e. "take next measurement" + write8(BME280_REGISTER_CONTROL, _measReg.get()); + // wait until measurement has been completed, otherwise we would read + // the values from the last measurement + while (read8(BME280_REGISTER_STATUS) & 0x08) + delay(1); + } +} + + +/**************************************************************************/ +/*! + @brief Reads the factory-set coefficients +*/ +/**************************************************************************/ +void Adafruit_BME280::readCoefficients(void) +{ + _bme280_calib.dig_T1 = read16_LE(BME280_REGISTER_DIG_T1); + _bme280_calib.dig_T2 = readS16_LE(BME280_REGISTER_DIG_T2); + _bme280_calib.dig_T3 = readS16_LE(BME280_REGISTER_DIG_T3); + + _bme280_calib.dig_P1 = read16_LE(BME280_REGISTER_DIG_P1); + _bme280_calib.dig_P2 = readS16_LE(BME280_REGISTER_DIG_P2); + _bme280_calib.dig_P3 = readS16_LE(BME280_REGISTER_DIG_P3); + _bme280_calib.dig_P4 = readS16_LE(BME280_REGISTER_DIG_P4); + _bme280_calib.dig_P5 = readS16_LE(BME280_REGISTER_DIG_P5); + _bme280_calib.dig_P6 = readS16_LE(BME280_REGISTER_DIG_P6); + _bme280_calib.dig_P7 = readS16_LE(BME280_REGISTER_DIG_P7); + _bme280_calib.dig_P8 = readS16_LE(BME280_REGISTER_DIG_P8); + _bme280_calib.dig_P9 = readS16_LE(BME280_REGISTER_DIG_P9); + + _bme280_calib.dig_H1 = read8(BME280_REGISTER_DIG_H1); + _bme280_calib.dig_H2 = readS16_LE(BME280_REGISTER_DIG_H2); + _bme280_calib.dig_H3 = read8(BME280_REGISTER_DIG_H3); + _bme280_calib.dig_H4 = (read8(BME280_REGISTER_DIG_H4) << 4) | (read8(BME280_REGISTER_DIG_H4+1) & 0xF); + _bme280_calib.dig_H5 = (read8(BME280_REGISTER_DIG_H5+1) << 4) | (read8(BME280_REGISTER_DIG_H5) >> 4); + _bme280_calib.dig_H6 = (int8_t)read8(BME280_REGISTER_DIG_H6); +} + +/**************************************************************************/ +/*! + @brief return true if chip is busy reading cal data + @returns true if reading calibration, false otherwise +*/ +/**************************************************************************/ +bool Adafruit_BME280::isReadingCalibration(void) +{ + uint8_t const rStatus = read8(BME280_REGISTER_STATUS); + + return (rStatus & (1 << 0)) != 0; +} + + +/**************************************************************************/ +/*! + @brief Returns the temperature from the sensor + @returns the temperature read from the device +*/ +/**************************************************************************/ +float Adafruit_BME280::readTemperature(void) +{ + int32_t var1, var2; + + int32_t adc_T = read24(BME280_REGISTER_TEMPDATA); + if (adc_T == 0x800000) // value in case temp measurement was disabled + return NAN; + adc_T >>= 4; + + var1 = ((((adc_T>>3) - ((int32_t)_bme280_calib.dig_T1 <<1))) * + ((int32_t)_bme280_calib.dig_T2)) >> 11; + + var2 = (((((adc_T>>4) - ((int32_t)_bme280_calib.dig_T1)) * + ((adc_T>>4) - ((int32_t)_bme280_calib.dig_T1))) >> 12) * + ((int32_t)_bme280_calib.dig_T3)) >> 14; + + t_fine = var1 + var2; + + float T = (t_fine * 5 + 128) >> 8; + return T/100; +} + + +/**************************************************************************/ +/*! + @brief Returns the pressure from the sensor + @returns the pressure value (in Pascal) read from the device +*/ +/**************************************************************************/ +float Adafruit_BME280::readPressure(void) { + int64_t var1, var2, p; + + readTemperature(); // must be done first to get t_fine + + int32_t adc_P = read24(BME280_REGISTER_PRESSUREDATA); + if (adc_P == 0x800000) // value in case pressure measurement was disabled + return NAN; + adc_P >>= 4; + + var1 = ((int64_t)t_fine) - 128000; + var2 = var1 * var1 * (int64_t)_bme280_calib.dig_P6; + var2 = var2 + ((var1*(int64_t)_bme280_calib.dig_P5)<<17); + var2 = var2 + (((int64_t)_bme280_calib.dig_P4)<<35); + var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3)>>8) + + ((var1 * (int64_t)_bme280_calib.dig_P2)<<12); + var1 = (((((int64_t)1)<<47)+var1))*((int64_t)_bme280_calib.dig_P1)>>33; + + if (var1 == 0) { + return 0; // avoid exception caused by division by zero + } + p = 1048576 - adc_P; + p = (((p<<31) - var2)*3125) / var1; + var1 = (((int64_t)_bme280_calib.dig_P9) * (p>>13) * (p>>13)) >> 25; + var2 = (((int64_t)_bme280_calib.dig_P8) * p) >> 19; + + p = ((p + var1 + var2) >> 8) + (((int64_t)_bme280_calib.dig_P7)<<4); + return (float)p/256; +} + + +/**************************************************************************/ +/*! + @brief Returns the humidity from the sensor + @returns the humidity value read from the device +*/ +/**************************************************************************/ +float Adafruit_BME280::readHumidity(void) { + readTemperature(); // must be done first to get t_fine + + int32_t adc_H = read16(BME280_REGISTER_HUMIDDATA); + if (adc_H == 0x8000) // value in case humidity measurement was disabled + return NAN; + + int32_t v_x1_u32r; + + v_x1_u32r = (t_fine - ((int32_t)76800)); + + v_x1_u32r = (((((adc_H << 14) - (((int32_t)_bme280_calib.dig_H4) << 20) - + (((int32_t)_bme280_calib.dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) * + (((((((v_x1_u32r * ((int32_t)_bme280_calib.dig_H6)) >> 10) * + (((v_x1_u32r * ((int32_t)_bme280_calib.dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + + ((int32_t)2097152)) * ((int32_t)_bme280_calib.dig_H2) + 8192) >> 14)); + + v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * + ((int32_t)_bme280_calib.dig_H1)) >> 4)); + + v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r; + v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r; + float h = (v_x1_u32r>>12); + return h / 1024.0; +} + + +/**************************************************************************/ +/*! + Calculates the altitude (in meters) from the specified atmospheric + pressure (in hPa), and sea-level pressure (in hPa). + + @param seaLevel Sea-level pressure in hPa + @returns the altitude value read from the device +*/ +/**************************************************************************/ +float Adafruit_BME280::readAltitude(float seaLevel) +{ + // Equation taken from BMP180 datasheet (page 16): + // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf + + // Note that using the equation from wikipedia can give bad results + // at high altitude. See this thread for more information: + // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 + + float atmospheric = readPressure() / 100.0F; + return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903)); +} + + +/**************************************************************************/ +/*! + Calculates the pressure at sea level (in hPa) from the specified altitude + (in meters), and atmospheric pressure (in hPa). + @param altitude Altitude in meters + @param atmospheric Atmospheric pressure in hPa + @returns the pressure at sea level (in hPa) from the specified altitude +*/ +/**************************************************************************/ +float Adafruit_BME280::seaLevelForAltitude(float altitude, float atmospheric) +{ + // Equation taken from BMP180 datasheet (page 17): + // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf + + // Note that using the equation from wikipedia can give bad results + // at high altitude. See this thread for more information: + // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 + + return atmospheric / pow(1.0 - (altitude/44330.0), 5.255); +} diff --git a/lib/Adafruit_BME280_Library/Adafruit_BME280.h b/lib/Adafruit_BME280_Library/Adafruit_BME280.h new file mode 100644 index 0000000..db88379 --- /dev/null +++ b/lib/Adafruit_BME280_Library/Adafruit_BME280.h @@ -0,0 +1,331 @@ +/*! + * @file Adafruit_BME280.h + * + * Designed specifically to work with the Adafruit BME280 Breakout + * ----> http://www.adafruit.com/products/2650 + * + * These sensors use I2C or SPI to communicate, 2 or 4 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 "KTOWN" Townsend for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * + */ + +#ifndef __BME280_H__ +#define __BME280_H__ + +#if (ARDUINO >= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#include +#include + +/**************************************************************************/ +/*! + @brief default I2C address +*/ +/**************************************************************************/ + #define BME280_ADDRESS (0x77) +/*=========================================================================*/ + +/**************************************************************************/ +/*! + @brief Register addresses +*/ +/**************************************************************************/ + enum + { + BME280_REGISTER_DIG_T1 = 0x88, + BME280_REGISTER_DIG_T2 = 0x8A, + BME280_REGISTER_DIG_T3 = 0x8C, + + BME280_REGISTER_DIG_P1 = 0x8E, + BME280_REGISTER_DIG_P2 = 0x90, + BME280_REGISTER_DIG_P3 = 0x92, + BME280_REGISTER_DIG_P4 = 0x94, + BME280_REGISTER_DIG_P5 = 0x96, + BME280_REGISTER_DIG_P6 = 0x98, + BME280_REGISTER_DIG_P7 = 0x9A, + BME280_REGISTER_DIG_P8 = 0x9C, + BME280_REGISTER_DIG_P9 = 0x9E, + + BME280_REGISTER_DIG_H1 = 0xA1, + BME280_REGISTER_DIG_H2 = 0xE1, + BME280_REGISTER_DIG_H3 = 0xE3, + BME280_REGISTER_DIG_H4 = 0xE4, + BME280_REGISTER_DIG_H5 = 0xE5, + BME280_REGISTER_DIG_H6 = 0xE7, + + BME280_REGISTER_CHIPID = 0xD0, + BME280_REGISTER_VERSION = 0xD1, + BME280_REGISTER_SOFTRESET = 0xE0, + + BME280_REGISTER_CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0 + + BME280_REGISTER_CONTROLHUMID = 0xF2, + BME280_REGISTER_STATUS = 0XF3, + BME280_REGISTER_CONTROL = 0xF4, + BME280_REGISTER_CONFIG = 0xF5, + BME280_REGISTER_PRESSUREDATA = 0xF7, + BME280_REGISTER_TEMPDATA = 0xFA, + BME280_REGISTER_HUMIDDATA = 0xFD + }; + +/**************************************************************************/ +/*! + @brief calibration data +*/ +/**************************************************************************/ + typedef struct + { + uint16_t dig_T1; ///< temperature compensation value + int16_t dig_T2; ///< temperature compensation value + int16_t dig_T3; ///< temperature compensation value + + uint16_t dig_P1; ///< pressure compensation value + int16_t dig_P2; ///< pressure compensation value + int16_t dig_P3; ///< pressure compensation value + int16_t dig_P4; ///< pressure compensation value + int16_t dig_P5; ///< pressure compensation value + int16_t dig_P6; ///< pressure compensation value + int16_t dig_P7; ///< pressure compensation value + int16_t dig_P8; ///< pressure compensation value + int16_t dig_P9; ///< pressure compensation value + + uint8_t dig_H1; ///< humidity compensation value + int16_t dig_H2; ///< humidity compensation value + uint8_t dig_H3; ///< humidity compensation value + int16_t dig_H4; ///< humidity compensation value + int16_t dig_H5; ///< humidity compensation value + int8_t dig_H6; ///< humidity compensation value + } bme280_calib_data; +/*=========================================================================*/ + +/* +class Adafruit_BME280_Unified : public Adafruit_Sensor +{ + public: + Adafruit_BME280_Unified(int32_t sensorID = -1); + + bool begin(uint8_t addr = BME280_ADDRESS); + void getTemperature(float *temp); + void getPressure(float *pressure); + float pressureToAltitude(float seaLevel, float atmospheric, float temp); + float seaLevelForAltitude(float altitude, float atmospheric, float temp); + void getEvent(sensors_event_t*); + void getSensor(sensor_t*); + + private: + uint8_t _i2c_addr; + int32_t _sensorID; +}; + +*/ + +/**************************************************************************/ +/*! + @brief Class that stores state and functions for interacting with BME280 IC +*/ +/**************************************************************************/ +class Adafruit_BME280 { + public: + /**************************************************************************/ + /*! + @brief sampling rates + */ + /**************************************************************************/ + enum sensor_sampling { + SAMPLING_NONE = 0b000, + SAMPLING_X1 = 0b001, + SAMPLING_X2 = 0b010, + SAMPLING_X4 = 0b011, + SAMPLING_X8 = 0b100, + SAMPLING_X16 = 0b101 + }; + + /**************************************************************************/ + /*! + @brief power modes + */ + /**************************************************************************/ + enum sensor_mode { + MODE_SLEEP = 0b00, + MODE_FORCED = 0b01, + MODE_NORMAL = 0b11 + }; + + /**************************************************************************/ + /*! + @brief filter values + */ + /**************************************************************************/ + enum sensor_filter { + FILTER_OFF = 0b000, + FILTER_X2 = 0b001, + FILTER_X4 = 0b010, + FILTER_X8 = 0b011, + FILTER_X16 = 0b100 + }; + + /**************************************************************************/ + /*! + @brief standby duration in ms + */ + /**************************************************************************/ + enum standby_duration { + STANDBY_MS_0_5 = 0b000, + STANDBY_MS_10 = 0b110, + STANDBY_MS_20 = 0b111, + STANDBY_MS_62_5 = 0b001, + STANDBY_MS_125 = 0b010, + STANDBY_MS_250 = 0b011, + STANDBY_MS_500 = 0b100, + STANDBY_MS_1000 = 0b101 + }; + + // constructors + Adafruit_BME280(void); + Adafruit_BME280(int8_t cspin); + Adafruit_BME280(int8_t cspin, int8_t mosipin, int8_t misopin, int8_t sckpin); + + bool begin(void); + bool begin(TwoWire *theWire); + bool begin(uint8_t addr); + bool begin(uint8_t addr, TwoWire *theWire); + bool init(); + + void setSampling(sensor_mode mode = MODE_NORMAL, + sensor_sampling tempSampling = SAMPLING_X16, + sensor_sampling pressSampling = SAMPLING_X16, + sensor_sampling humSampling = SAMPLING_X16, + sensor_filter filter = FILTER_OFF, + standby_duration duration = STANDBY_MS_0_5 + ); + + void takeForcedMeasurement(); + float readTemperature(void); + float readPressure(void); + float readHumidity(void); + + float readAltitude(float seaLevel); + float seaLevelForAltitude(float altitude, float pressure); + + + private: + TwoWire *_wire; + void readCoefficients(void); + bool isReadingCalibration(void); + uint8_t spixfer(uint8_t x); + + void write8(byte reg, byte value); + uint8_t read8(byte reg); + uint16_t read16(byte reg); + uint32_t read24(byte reg); + int16_t readS16(byte reg); + uint16_t read16_LE(byte reg); // little endian + int16_t readS16_LE(byte reg); // little endian + + uint8_t _i2caddr; + int32_t _sensorID; + int32_t t_fine; + + int8_t _cs, _mosi, _miso, _sck; + + bme280_calib_data _bme280_calib; + + // The config register + struct config { + // inactive duration (standby time) in normal mode + // 000 = 0.5 ms + // 001 = 62.5 ms + // 010 = 125 ms + // 011 = 250 ms + // 100 = 500 ms + // 101 = 1000 ms + // 110 = 10 ms + // 111 = 20 ms + unsigned int t_sb : 3; + + // filter settings + // 000 = filter off + // 001 = 2x filter + // 010 = 4x filter + // 011 = 8x filter + // 100 and above = 16x filter + unsigned int filter : 3; + + // unused - don't set + unsigned int none : 1; + unsigned int spi3w_en : 1; + + unsigned int get() { + return (t_sb << 5) | (filter << 2) | spi3w_en; + } + }; + config _configReg; + + + // The ctrl_meas register + struct ctrl_meas { + // temperature oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_t : 3; + + // pressure oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_p : 3; + + // device mode + // 00 = sleep + // 01 or 10 = forced + // 11 = normal + unsigned int mode : 2; + + unsigned int get() { + return (osrs_t << 5) | (osrs_p << 2) | mode; + } + }; + ctrl_meas _measReg; + + + // The ctrl_hum register + struct ctrl_hum { + // unused - don't set + unsigned int none : 5; + + // pressure oversampling + // 000 = skipped + // 001 = x1 + // 010 = x2 + // 011 = x4 + // 100 = x8 + // 101 and above = x16 + unsigned int osrs_h : 3; + + unsigned int get() { + return (osrs_h); + } + }; + ctrl_hum _humReg; +}; + +#endif diff --git a/lib/Adafruit_BME280_Library/README.md b/lib/Adafruit_BME280_Library/README.md new file mode 100644 index 0000000..8511321 --- /dev/null +++ b/lib/Adafruit_BME280_Library/README.md @@ -0,0 +1,63 @@ +# Adafruit BME280 Library [![Build Status](https://travis-ci.org/adafruit/Adafruit_BME280_Library.svg?branch=master)](https://travis-ci.org/adafruit/Adafruit_BME280_Library) + + + +This is a library for the Adafruit BME280 Humidity, Barometric Pressure + Temp sensor + +Designed specifically to work with the Adafruit BME280 Breakout + * http://www.adafruit.com/products/2652 + +These sensors use I2C or SPI to communicate, up to 4 pins are required to interface + +Use of this library also requires [Adafruit_Sensor](https://github.com/adafruit/Adafruit_Sensor) +to be installed on your local system. + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing +products from Adafruit! + +Check out the links above for our tutorials and wiring diagrams + +Written by Limor Fried/Ladyada for Adafruit Industries. +BSD license, all text above must be included in any redistribution + +To download. click the DOWNLOAD ZIP button, rename the uncompressed folder Adafruit_BME280. +Check that the Adafruit_BME280 folder contains Adafruit_BME280.cpp and Adafruit_BME280.h + +Place the Adafruit_BME280 library folder your arduinosketchfolder/libraries/ folder. +You may need to create the libraries subfolder if its your first library. Restart the IDE. + +We also have a great tutorial on Arduino library installation at: +http://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use + + +## Compatibility + +MCU | Tested Works | Doesn't Work | Not Tested | Notes +------------------ | :----------: | :----------: | :---------: | ----- +Atmega328 @ 16MHz | X | | | +Atmega328 @ 12MHz | X | | | +Atmega32u4 @ 16MHz | X | | | Use SDA/SCL on pins D2 & D3 +Atmega32u4 @ 8MHz | X | | | Use SDA/SCL on pins D2 & D3 +ESP8266 | X | | | I2C: just works, SPI: SDA/SCL default to pins 4 & 5 but any two pins can be assigned as SDA/SCL using Wire.begin(SDA,SCL) +ESP32 | X | | | I2C: just works, SPI: SDA/SCL default to pins 4 & 5 but any two pins can be assigned as SDA/SCL using Wire.begin(SDA,SCL) +Atmega2560 @ 16MHz | X | | | Use SDA/SCL on pins 20 & 21 +ATSAM3X8E | X | | | Use SDA/SCL on pins 20 & 21 +ATSAM21D | X | | | +ATtiny85 @ 16MHz | | X | | +ATtiny85 @ 8MHz | | X | | +Intel Curie @ 32MHz | | | X | +STM32F2 | | | X | + + * ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini + * ATmega328 @ 12MHz : Adafruit Pro Trinket 3V + * ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0 + * ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro + * ESP8266 : Adafruit Huzzah + * ATmega2560 @ 16MHz : Arduino Mega + * ATSAM3X8E : Arduino Due + * ATSAM21D : Arduino Zero, M0 Pro + * ATtiny85 @ 16MHz : Adafruit Trinket 5V + * ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V + + diff --git a/lib/Adafruit_BME280_Library/examples/advancedsettings/advancedsettings.ino b/lib/Adafruit_BME280_Library/examples/advancedsettings/advancedsettings.ino new file mode 100644 index 0000000..177fbbe --- /dev/null +++ b/lib/Adafruit_BME280_Library/examples/advancedsettings/advancedsettings.ino @@ -0,0 +1,158 @@ +/*************************************************************************** + This is a library for the BME280 humidity, temperature & pressure sensor + + Designed specifically to work with the Adafruit BME280 Breakout + ----> http://www.adafruit.com/products/2650 + + These sensors use I2C or SPI to communicate, 2 or 4 pins are required + to interface. The device's I2C address is either 0x76 or 0x77. + + Adafruit invests time and resources providing this open source code, + please support Adafruit andopen-source hardware by purchasing products + from Adafruit! + + Written by Limor Fried & Kevin Townsend for Adafruit Industries. + BSD license, all text above must be included in any redistribution + ***************************************************************************/ + +#include +#include +#include +#include + +#define BME_SCK 13 +#define BME_MISO 12 +#define BME_MOSI 11 +#define BME_CS 10 + +#define SEALEVELPRESSURE_HPA (1013.25) + +Adafruit_BME280 bme; // I2C +//Adafruit_BME280 bme(BME_CS); // hardware SPI +//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI + +unsigned long delayTime; + +void setup() { + Serial.begin(9600); + Serial.println(F("BME280 test")); + + if (! bme.begin(&Wire)) { + Serial.println("Could not find a valid BME280 sensor, check wiring!"); + while (1); + } + + Serial.println("-- Default Test --"); + Serial.println("normal mode, 16x oversampling for all, filter off,"); + Serial.println("0.5ms standby period"); + delayTime = 5000; + + + // For more details on the following scenarious, see chapter + // 3.5 "Recommended modes of operation" in the datasheet + +/* + // weather monitoring + Serial.println("-- Weather Station Scenario --"); + Serial.println("forced mode, 1x temperature / 1x humidity / 1x pressure oversampling,"); + Serial.println("filter off"); + bme.setSampling(Adafruit_BME280::MODE_FORCED, + Adafruit_BME280::SAMPLING_X1, // temperature + Adafruit_BME280::SAMPLING_X1, // pressure + Adafruit_BME280::SAMPLING_X1, // humidity + Adafruit_BME280::FILTER_OFF ); + + // suggested rate is 1/60Hz (1m) + delayTime = 60000; // in milliseconds +*/ + +/* + // humidity sensing + Serial.println("-- Humidity Sensing Scenario --"); + Serial.println("forced mode, 1x temperature / 1x humidity / 0x pressure oversampling"); + Serial.println("= pressure off, filter off"); + bme.setSampling(Adafruit_BME280::MODE_FORCED, + Adafruit_BME280::SAMPLING_X1, // temperature + Adafruit_BME280::SAMPLING_NONE, // pressure + Adafruit_BME280::SAMPLING_X1, // humidity + Adafruit_BME280::FILTER_OFF ); + + // suggested rate is 1Hz (1s) + delayTime = 1000; // in milliseconds +*/ + +/* + // indoor navigation + Serial.println("-- Indoor Navigation Scenario --"); + Serial.println("normal mode, 16x pressure / 2x temperature / 1x humidity oversampling,"); + Serial.println("0.5ms standby period, filter 16x"); + bme.setSampling(Adafruit_BME280::MODE_NORMAL, + Adafruit_BME280::SAMPLING_X2, // temperature + Adafruit_BME280::SAMPLING_X16, // pressure + Adafruit_BME280::SAMPLING_X1, // humidity + Adafruit_BME280::FILTER_X16, + Adafruit_BME280::STANDBY_MS_0_5 ); + + // suggested rate is 25Hz + // 1 + (2 * T_ovs) + (2 * P_ovs + 0.5) + (2 * H_ovs + 0.5) + // T_ovs = 2 + // P_ovs = 16 + // H_ovs = 1 + // = 40ms (25Hz) + // with standby time that should really be 24.16913... Hz + delayTime = 41; + */ + + /* + // gaming + Serial.println("-- Gaming Scenario --"); + Serial.println("normal mode, 4x pressure / 1x temperature / 0x humidity oversampling,"); + Serial.println("= humidity off, 0.5ms standby period, filter 16x"); + bme.setSampling(Adafruit_BME280::MODE_NORMAL, + Adafruit_BME280::SAMPLING_X1, // temperature + Adafruit_BME280::SAMPLING_X4, // pressure + Adafruit_BME280::SAMPLING_NONE, // humidity + Adafruit_BME280::FILTER_X16, + Adafruit_BME280::STANDBY_MS_0_5 ); + + // Suggested rate is 83Hz + // 1 + (2 * T_ovs) + (2 * P_ovs + 0.5) + // T_ovs = 1 + // P_ovs = 4 + // = 11.5ms + 0.5ms standby + delayTime = 12; +*/ + + Serial.println(); +} + + +void loop() { + // Only needed in forced mode! In normal mode, you can remove the next line. + bme.takeForcedMeasurement(); // has no effect in normal mode + + printValues(); + delay(delayTime); +} + + +void printValues() { + Serial.print("Temperature = "); + Serial.print(bme.readTemperature()); + Serial.println(" *C"); + + Serial.print("Pressure = "); + + Serial.print(bme.readPressure() / 100.0F); + Serial.println(" hPa"); + + Serial.print("Approx. Altitude = "); + Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA)); + Serial.println(" m"); + + Serial.print("Humidity = "); + Serial.print(bme.readHumidity()); + Serial.println(" %"); + + Serial.println(); +} \ No newline at end of file diff --git a/lib/Adafruit_BME280_Library/examples/bme280test/bme280test.ino b/lib/Adafruit_BME280_Library/examples/bme280test/bme280test.ino new file mode 100644 index 0000000..e8b5563 --- /dev/null +++ b/lib/Adafruit_BME280_Library/examples/bme280test/bme280test.ino @@ -0,0 +1,82 @@ +/*************************************************************************** + This is a library for the BME280 humidity, temperature & pressure sensor + + Designed specifically to work with the Adafruit BME280 Breakout + ----> http://www.adafruit.com/products/2650 + + These sensors use I2C or SPI to communicate, 2 or 4 pins are required + to interface. The device's I2C address is either 0x76 or 0x77. + + Adafruit invests time and resources providing this open source code, + please support Adafruit andopen-source hardware by purchasing products + from Adafruit! + + Written by Limor Fried & Kevin Townsend for Adafruit Industries. + BSD license, all text above must be included in any redistribution + ***************************************************************************/ + +#include +#include +#include +#include + +#define BME_SCK 13 +#define BME_MISO 12 +#define BME_MOSI 11 +#define BME_CS 10 + +#define SEALEVELPRESSURE_HPA (1013.25) + +Adafruit_BME280 bme; // I2C +//Adafruit_BME280 bme(BME_CS); // hardware SPI +//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI + +unsigned long delayTime; + +void setup() { + Serial.begin(9600); + Serial.println(F("BME280 test")); + + bool status; + + // default settings + // (you can also pass in a Wire library object like &Wire2) + status = bme.begin(); + if (!status) { + Serial.println("Could not find a valid BME280 sensor, check wiring!"); + while (1); + } + + Serial.println("-- Default Test --"); + delayTime = 1000; + + Serial.println(); +} + + +void loop() { + printValues(); + delay(delayTime); +} + + +void printValues() { + Serial.print("Temperature = "); + Serial.print(bme.readTemperature()); + Serial.println(" *C"); + + Serial.print("Pressure = "); + + Serial.print(bme.readPressure() / 100.0F); + Serial.println(" hPa"); + + Serial.print("Approx. Altitude = "); + Serial.print(bme.readAltitude(SEALEVELPRESSURE_HPA)); + Serial.println(" m"); + + Serial.print("Humidity = "); + Serial.print(bme.readHumidity()); + Serial.println(" %"); + + Serial.println(); +} \ No newline at end of file diff --git a/lib/Adafruit_BME280_Library/library.properties b/lib/Adafruit_BME280_Library/library.properties new file mode 100644 index 0000000..e9eb39e --- /dev/null +++ b/lib/Adafruit_BME280_Library/library.properties @@ -0,0 +1,9 @@ +name=Adafruit BME280 Library +version=1.0.8 +author=Adafruit +maintainer=Adafruit +sentence=Arduino library for BME280 sensors. +paragraph=Arduino library for BME280 humidity and pressure sensors. +category=Sensors +url=https://github.com/adafruit/Adafruit_BME280_Library +architectures=* diff --git a/lib/Adafruit_BMP280_Library/Adafruit_BMP280.cpp b/lib/Adafruit_BMP280_Library/Adafruit_BMP280.cpp new file mode 100644 index 0000000..7d96046 --- /dev/null +++ b/lib/Adafruit_BMP280_Library/Adafruit_BMP280.cpp @@ -0,0 +1,397 @@ +/*! + * @file Adafruit_BMP280.cpp + * + * This is a library for the BMP280 orientation sensor + * + * Designed specifically to work with the Adafruit BMP280 Sensor. + * + * Pick one up today in the adafruit shop! + * ------> https://www.adafruit.com/product/2651 + * + * These sensors use I2C to communicate, 2 pins are required to interface. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit andopen-source hardware by purchasing products + * from Adafruit! + * + * K.Townsend (Adafruit Industries) + * + * BSD license, all text above must be included in any redistribution + */ + +#include "Adafruit_BMP280.h" +#include "Arduino.h" +#include + +/*! + * @brief BMP280 constructor using i2c + * @param *theWire + * optional wire + */ +Adafruit_BMP280::Adafruit_BMP280(TwoWire *theWire) + : _cs(-1), _mosi(-1), _miso(-1), _sck(-1) { + _wire = theWire; +} + +/*! + * @brief BMP280 constructor using hardware SPI + * @param cspin + * cs pin number + * @param theSPI + * optional SPI object + */ +Adafruit_BMP280::Adafruit_BMP280(int8_t cspin, SPIClass *theSPI) + : _cs(cspin), _mosi(-1), _miso(-1), _sck(-1) { + *_spi = *theSPI; +} + +/*! + * @brief BMP280 constructor using bitbang SPI + * @param cspin + * The pin to use for CS/SSEL. + * @param mosipin + * The pin to use for MOSI. + * @param misopin + * The pin to use for MISO. + * @param sckpin + * The pin to use for SCK. + */ +Adafruit_BMP280::Adafruit_BMP280(int8_t cspin, int8_t mosipin, int8_t misopin, + int8_t sckpin) + : _cs(cspin), _mosi(mosipin), _miso(misopin), _sck(sckpin) {} + +/*! + * Initialises the sensor. + * @param addr + * The I2C address to use (default = 0x77) + * @param chipid + * The expected chip ID (used to validate connection). + * @return True if the init was successful, otherwise false. + */ +bool Adafruit_BMP280::begin(uint8_t addr, uint8_t chipid) { + _i2caddr = addr; + + if (_cs == -1) { + // i2c + _wire->begin(); + } else { + digitalWrite(_cs, HIGH); + pinMode(_cs, OUTPUT); + + if (_sck == -1) { + // hardware SPI + _spi->begin(); + } else { + // software SPI + pinMode(_sck, OUTPUT); + pinMode(_mosi, OUTPUT); + pinMode(_miso, INPUT); + } + } + + if (read8(BMP280_REGISTER_CHIPID) != chipid) + return false; + + readCoefficients(); + // write8(BMP280_REGISTER_CONTROL, 0x3F); /* needed? */ + setSampling(); + delay(100); + return true; +} + +/*! + * Sets the sampling config for the device. + * @param mode + * The operating mode of the sensor. + * @param tempSampling + * The sampling scheme for temp readings. + * @param pressSampling + * The sampling scheme for pressure readings. + * @param filter + * The filtering mode to apply (if any). + * @param duration + * The sampling duration. + */ +void Adafruit_BMP280::setSampling(sensor_mode mode, + sensor_sampling tempSampling, + sensor_sampling pressSampling, + sensor_filter filter, + standby_duration duration) { + _measReg.mode = mode; + _measReg.osrs_t = tempSampling; + _measReg.osrs_p = pressSampling; + + _configReg.filter = filter; + _configReg.t_sb = duration; + + write8(BMP280_REGISTER_CONFIG, _configReg.get()); + write8(BMP280_REGISTER_CONTROL, _measReg.get()); +} + +uint8_t Adafruit_BMP280::spixfer(uint8_t x) { + if (_sck == -1) + return SPI.transfer(x); + + // software spi + // Serial.println("Software SPI"); + uint8_t reply = 0; + for (int i = 7; i >= 0; i--) { + reply <<= 1; + digitalWrite(_sck, LOW); + digitalWrite(_mosi, x & (1 << i)); + digitalWrite(_sck, HIGH); + if (digitalRead(_miso)) + reply |= 1; + } + return reply; +} + +/**************************************************************************/ +/*! + @brief Writes an 8 bit value over I2C/SPI +*/ +/**************************************************************************/ +void Adafruit_BMP280::write8(byte reg, byte value) { + if (_cs == -1) { + _wire->beginTransmission((uint8_t)_i2caddr); + _wire->write((uint8_t)reg); + _wire->write((uint8_t)value); + _wire->endTransmission(); + } else { + if (_sck == -1) + _spi->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); + digitalWrite(_cs, LOW); + spixfer(reg & ~0x80); // write, bit 7 low + spixfer(value); + digitalWrite(_cs, HIGH); + if (_sck == -1) + _spi->endTransaction(); // release the SPI bus + } +} + +/*! + * @brief Reads an 8 bit value over I2C/SPI + * @param reg + * selected register + * @return value from selected register + */ +uint8_t Adafruit_BMP280::read8(byte reg) { + uint8_t value; + + if (_cs == -1) { + _wire->beginTransmission((uint8_t)_i2caddr); + _wire->write((uint8_t)reg); + _wire->endTransmission(); + _wire->requestFrom((uint8_t)_i2caddr, (byte)1); + value = _wire->read(); + + } else { + if (_sck == -1) + _spi->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); + digitalWrite(_cs, LOW); + spixfer(reg | 0x80); // read, bit 7 high + value = spixfer(0); + digitalWrite(_cs, HIGH); + if (_sck == -1) + _spi->endTransaction(); // release the SPI bus + } + return value; +} + +/*! + * @brief Reads a 16 bit value over I2C/SPI + */ +uint16_t Adafruit_BMP280::read16(byte reg) { + uint16_t value; + + if (_cs == -1) { + _wire->beginTransmission((uint8_t)_i2caddr); + _wire->write((uint8_t)reg); + _wire->endTransmission(); + _wire->requestFrom((uint8_t)_i2caddr, (byte)2); + value = (_wire->read() << 8) | _wire->read(); + + } else { + if (_sck == -1) + _spi->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); + digitalWrite(_cs, LOW); + spixfer(reg | 0x80); // read, bit 7 high + value = (spixfer(0) << 8) | spixfer(0); + digitalWrite(_cs, HIGH); + if (_sck == -1) + _spi->endTransaction(); // release the SPI bus + } + + return value; +} + +uint16_t Adafruit_BMP280::read16_LE(byte reg) { + uint16_t temp = read16(reg); + return (temp >> 8) | (temp << 8); +} + +/*! + * @brief Reads a signed 16 bit value over I2C/SPI + */ +int16_t Adafruit_BMP280::readS16(byte reg) { return (int16_t)read16(reg); } + +int16_t Adafruit_BMP280::readS16_LE(byte reg) { + return (int16_t)read16_LE(reg); +} + +/*! + * @brief Reads a 24 bit value over I2C/SPI + */ +uint32_t Adafruit_BMP280::read24(byte reg) { + uint32_t value; + + if (_cs == -1) { + _wire->beginTransmission((uint8_t)_i2caddr); + _wire->write((uint8_t)reg); + _wire->endTransmission(); + _wire->requestFrom((uint8_t)_i2caddr, (byte)3); + + value = _wire->read(); + value <<= 8; + value |= _wire->read(); + value <<= 8; + value |= _wire->read(); + + } else { + if (_sck == -1) + _spi->beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE0)); + digitalWrite(_cs, LOW); + spixfer(reg | 0x80); // read, bit 7 high + + value = spixfer(0); + value <<= 8; + value |= spixfer(0); + value <<= 8; + value |= spixfer(0); + + digitalWrite(_cs, HIGH); + if (_sck == -1) + _spi->endTransaction(); // release the SPI bus + } + + return value; +} + +/*! + * @brief Reads the factory-set coefficients + */ +void Adafruit_BMP280::readCoefficients() { + _bmp280_calib.dig_T1 = read16_LE(BMP280_REGISTER_DIG_T1); + _bmp280_calib.dig_T2 = readS16_LE(BMP280_REGISTER_DIG_T2); + _bmp280_calib.dig_T3 = readS16_LE(BMP280_REGISTER_DIG_T3); + + _bmp280_calib.dig_P1 = read16_LE(BMP280_REGISTER_DIG_P1); + _bmp280_calib.dig_P2 = readS16_LE(BMP280_REGISTER_DIG_P2); + _bmp280_calib.dig_P3 = readS16_LE(BMP280_REGISTER_DIG_P3); + _bmp280_calib.dig_P4 = readS16_LE(BMP280_REGISTER_DIG_P4); + _bmp280_calib.dig_P5 = readS16_LE(BMP280_REGISTER_DIG_P5); + _bmp280_calib.dig_P6 = readS16_LE(BMP280_REGISTER_DIG_P6); + _bmp280_calib.dig_P7 = readS16_LE(BMP280_REGISTER_DIG_P7); + _bmp280_calib.dig_P8 = readS16_LE(BMP280_REGISTER_DIG_P8); + _bmp280_calib.dig_P9 = readS16_LE(BMP280_REGISTER_DIG_P9); +} + +/*! + * Reads the temperature from the device. + * @return The temperature in degress celcius. + */ +float Adafruit_BMP280::readTemperature() { + int32_t var1, var2; + + int32_t adc_T = read24(BMP280_REGISTER_TEMPDATA); + adc_T >>= 4; + + var1 = ((((adc_T >> 3) - ((int32_t)_bmp280_calib.dig_T1 << 1))) * + ((int32_t)_bmp280_calib.dig_T2)) >> + 11; + + var2 = (((((adc_T >> 4) - ((int32_t)_bmp280_calib.dig_T1)) * + ((adc_T >> 4) - ((int32_t)_bmp280_calib.dig_T1))) >> + 12) * + ((int32_t)_bmp280_calib.dig_T3)) >> + 14; + + t_fine = var1 + var2; + + float T = (t_fine * 5 + 128) >> 8; + return T / 100; +} + +/*! + * Reads the barometric pressure from the device. + * @return Barometric pressure in hPa. + */ +float Adafruit_BMP280::readPressure() { + int64_t var1, var2, p; + + // Must be done first to get the t_fine variable set up + readTemperature(); + + int32_t adc_P = read24(BMP280_REGISTER_PRESSUREDATA); + adc_P >>= 4; + + var1 = ((int64_t)t_fine) - 128000; + var2 = var1 * var1 * (int64_t)_bmp280_calib.dig_P6; + var2 = var2 + ((var1 * (int64_t)_bmp280_calib.dig_P5) << 17); + var2 = var2 + (((int64_t)_bmp280_calib.dig_P4) << 35); + var1 = ((var1 * var1 * (int64_t)_bmp280_calib.dig_P3) >> 8) + + ((var1 * (int64_t)_bmp280_calib.dig_P2) << 12); + var1 = + (((((int64_t)1) << 47) + var1)) * ((int64_t)_bmp280_calib.dig_P1) >> 33; + + if (var1 == 0) { + return 0; // avoid exception caused by division by zero + } + p = 1048576 - adc_P; + p = (((p << 31) - var2) * 3125) / var1; + var1 = (((int64_t)_bmp280_calib.dig_P9) * (p >> 13) * (p >> 13)) >> 25; + var2 = (((int64_t)_bmp280_calib.dig_P8) * p) >> 19; + + p = ((p + var1 + var2) >> 8) + (((int64_t)_bmp280_calib.dig_P7) << 4); + return (float)p / 256; +} + +/*! + * @brief Calculates the approximate altitude using barometric pressure and the + * supplied sea level hPa as a reference. + * @param seaLevelhPa + * The current hPa at sea level. + * @return The approximate altitude above sea level in meters. + */ +float Adafruit_BMP280::readAltitude(float seaLevelhPa) { + float altitude; + + float pressure = readPressure(); // in Si units for Pascal + pressure /= 100; + + altitude = 44330 * (1.0 - pow(pressure / seaLevelhPa, 0.1903)); + + return altitude; +} + +/*! + * @brief Take a new measurement (only possible in forced mode) + * !!!todo!!! +*/ +/* +void Adafruit_BMP280::takeForcedMeasurement() +{ + // If we are in forced mode, the BME sensor goes back to sleep after each + // measurement and we need to set it to forced mode once at this point, so + // it will take the next measurement and then return to sleep again. + // In normal mode simply does new measurements periodically. + if (_measReg.mode == MODE_FORCED) { + // set to forced mode, i.e. "take next measurement" + write8(BMP280_REGISTER_CONTROL, _measReg.get()); + // wait until measurement has been completed, otherwise we would read + // the values from the last measurement + while (read8(BMP280_REGISTER_STATUS) & 0x08) + delay(1); + } +} +*/ diff --git a/lib/Adafruit_BMP280_Library/Adafruit_BMP280.h b/lib/Adafruit_BMP280_Library/Adafruit_BMP280.h new file mode 100644 index 0000000..6e541bb --- /dev/null +++ b/lib/Adafruit_BMP280_Library/Adafruit_BMP280.h @@ -0,0 +1,226 @@ +/*! + * @file Adafruit_BMP280.h + * + * This is a library for the Adafruit BMP280 Breakout. + * + * Designed specifically to work with the Adafruit BMP280 Breakout. + * + * Pick one up today in the adafruit shop! + * ------> https://www.adafruit.com/product/2651 + * + * These sensors use I2C to communicate, 2 pins are required to interface. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit andopen-source hardware by purchasing products + * from Adafruit! + * + * K.Townsend (Adafruit Industries) + * + * BSD license, all text above must be included in any redistribution + */ +#ifndef __BMP280_H__ +#define __BMP280_H__ + +#include "Arduino.h" +#include +#include + +/*! + * I2C ADDRESS/BITS/SETTINGS + */ +#define BMP280_ADDRESS (0x77) /**< The default I2C address for the sensor. */ +#define BMP280_ADDRESS_ALT \ + (0x76) /**< Alternative I2C address for the sensor. */ +#define BMP280_CHIPID (0x58) /**< Default chip ID. */ + +/*! + * Registers available on the sensor. + */ +enum { + BMP280_REGISTER_DIG_T1 = 0x88, + BMP280_REGISTER_DIG_T2 = 0x8A, + BMP280_REGISTER_DIG_T3 = 0x8C, + BMP280_REGISTER_DIG_P1 = 0x8E, + BMP280_REGISTER_DIG_P2 = 0x90, + BMP280_REGISTER_DIG_P3 = 0x92, + BMP280_REGISTER_DIG_P4 = 0x94, + BMP280_REGISTER_DIG_P5 = 0x96, + BMP280_REGISTER_DIG_P6 = 0x98, + BMP280_REGISTER_DIG_P7 = 0x9A, + BMP280_REGISTER_DIG_P8 = 0x9C, + BMP280_REGISTER_DIG_P9 = 0x9E, + BMP280_REGISTER_CHIPID = 0xD0, + BMP280_REGISTER_VERSION = 0xD1, + BMP280_REGISTER_SOFTRESET = 0xE0, + BMP280_REGISTER_CAL26 = 0xE1, /**< R calibration = 0xE1-0xF0 */ + BMP280_REGISTER_CONTROL = 0xF4, + BMP280_REGISTER_CONFIG = 0xF5, + BMP280_REGISTER_PRESSUREDATA = 0xF7, + BMP280_REGISTER_TEMPDATA = 0xFA, +}; + +/*! + * Struct to hold calibration data. + */ +typedef struct { + uint16_t dig_T1; /**< dig_T1 cal register. */ + int16_t dig_T2; /**< dig_T2 cal register. */ + int16_t dig_T3; /**< dig_T3 cal register. */ + + uint16_t dig_P1; /**< dig_P1 cal register. */ + int16_t dig_P2; /**< dig_P2 cal register. */ + int16_t dig_P3; /**< dig_P3 cal register. */ + int16_t dig_P4; /**< dig_P4 cal register. */ + int16_t dig_P5; /**< dig_P5 cal register. */ + int16_t dig_P6; /**< dig_P6 cal register. */ + int16_t dig_P7; /**< dig_P7 cal register. */ + int16_t dig_P8; /**< dig_P8 cal register. */ + int16_t dig_P9; /**< dig_P9 cal register. */ + + uint8_t dig_H1; /**< dig_H1 cal register. */ + int16_t dig_H2; /**< dig_H2 cal register. */ + uint8_t dig_H3; /**< dig_H3 cal register. */ + int16_t dig_H4; /**< dig_H4 cal register. */ + int16_t dig_H5; /**< dig_H5 cal register. */ + int8_t dig_H6; /**< dig_H6 cal register. */ +} bmp280_calib_data; + +/** + * Driver for the Adafruit BMP280 barometric pressure sensor. + */ +class Adafruit_BMP280 { +public: + /** Oversampling rate for the sensor. */ + enum sensor_sampling { + /** No over-sampling. */ + SAMPLING_NONE = 0x00, + /** 1x over-sampling. */ + SAMPLING_X1 = 0x01, + /** 2x over-sampling. */ + SAMPLING_X2 = 0x02, + /** 4x over-sampling. */ + SAMPLING_X4 = 0x03, + /** 8x over-sampling. */ + SAMPLING_X8 = 0x04, + /** 16x over-sampling. */ + SAMPLING_X16 = 0x05 + }; + + /** Operating mode for the sensor. */ + enum sensor_mode { + /** Sleep mode. */ + MODE_SLEEP = 0x00, + /** Forced mode. */ + MODE_FORCED = 0x01, + /** Normal mode. */ + MODE_NORMAL = 0x03, + /** Software reset. */ + MODE_SOFT_RESET_CODE = 0xB6 + }; + + /** Filtering level for sensor data. */ + enum sensor_filter { + /** No filtering. */ + FILTER_OFF = 0x00, + /** 2x filtering. */ + FILTER_X2 = 0x01, + /** 4x filtering. */ + FILTER_X4 = 0x02, + /** 8x filtering. */ + FILTER_X8 = 0x03, + /** 16x filtering. */ + FILTER_X16 = 0x04 + }; + + /** Standby duration in ms */ + enum standby_duration { + /** 1 ms standby. */ + STANDBY_MS_1 = 0x00, + /** 63 ms standby. */ + STANDBY_MS_63 = 0x01, + /** 125 ms standby. */ + STANDBY_MS_125 = 0x02, + /** 250 ms standby. */ + STANDBY_MS_250 = 0x03, + /** 500 ms standby. */ + STANDBY_MS_500 = 0x04, + /** 1000 ms standby. */ + STANDBY_MS_1000 = 0x05, + /** 2000 ms standby. */ + STANDBY_MS_2000 = 0x06, + /** 4000 ms standby. */ + STANDBY_MS_4000 = 0x07 + }; + + Adafruit_BMP280(TwoWire *theWire = &Wire); + Adafruit_BMP280(int8_t cspin, SPIClass *theSPI = &SPI); + Adafruit_BMP280(int8_t cspin, int8_t mosipin, int8_t misopin, int8_t sckpin); + + bool begin(uint8_t addr = BMP280_ADDRESS, uint8_t chipid = BMP280_CHIPID); + + float readTemperature(); + + float readPressure(void); + + float readAltitude(float seaLevelhPa = 1013.25); + + // void takeForcedMeasurement(); + + void setSampling(sensor_mode mode = MODE_NORMAL, + sensor_sampling tempSampling = SAMPLING_X16, + sensor_sampling pressSampling = SAMPLING_X16, + sensor_filter filter = FILTER_OFF, + standby_duration duration = STANDBY_MS_1); + + TwoWire *_wire; /**< Wire object */ + SPIClass *_spi; /**< SPI object */ + +private: + /** Encapsulates the config register */ + struct config { + /** Inactive duration (standby time) in normal mode */ + unsigned int t_sb : 3; + /** Filter settings */ + unsigned int filter : 3; + /** Unused - don't set */ + unsigned int none : 1; + /** Enables 3-wire SPI */ + unsigned int spi3w_en : 1; + /** Used to retrieve the assembled config register's byte value. */ + unsigned int get() { return (t_sb << 5) | (filter << 2) | spi3w_en; } + }; + + /** Encapsulates trhe ctrl_meas register */ + struct ctrl_meas { + /** Temperature oversampling. */ + unsigned int osrs_t : 3; + /** Pressure oversampling. */ + unsigned int osrs_p : 3; + /** Device mode */ + unsigned int mode : 2; + /** Used to retrieve the assembled ctrl_meas register's byte value. */ + unsigned int get() { return (osrs_t << 5) | (osrs_p << 2) | mode; } + }; + + void readCoefficients(void); + uint8_t spixfer(uint8_t x); + void write8(byte reg, byte value); + uint8_t read8(byte reg); + uint16_t read16(byte reg); + uint32_t read24(byte reg); + int16_t readS16(byte reg); + uint16_t read16_LE(byte reg); + int16_t readS16_LE(byte reg); + + uint8_t _i2caddr; + + + int32_t _sensorID; + int32_t t_fine; + int8_t _cs, _mosi, _miso, _sck; + bmp280_calib_data _bmp280_calib; + config _configReg; + ctrl_meas _measReg; +}; + +#endif diff --git a/lib/Adafruit_BMP280_Library/README.md b/lib/Adafruit_BMP280_Library/README.md new file mode 100644 index 0000000..f6ba8f7 --- /dev/null +++ b/lib/Adafruit_BMP280_Library/README.md @@ -0,0 +1,47 @@ +# Adafruit BMP280 Driver (Barometric Pressure Sensor) [![Build Status](https://travis-ci.org/adafruit/Adafruit_BMP280_Library.svg?branch=master)](https://travis-ci.org/adafruit/Adafruit_BMP280_Library) + +This driver is for the [Adafruit BMP280 Breakout](http://www.adafruit.com/products/2651) + + + +## About the BMP280 ## + +This precision sensor from Bosch is the best low-cost sensing solution for measuring barometric pressure and temperature. Because pressure changes with altitude you can also use it as an altimeter! + +## About this Driver ## + +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 (KTOWN) Townsend for Adafruit Industries. + + + +## Compatibility + +MCU | Tested Works | Doesn't Work | Not Tested | Notes +------------------ | :----------: | :----------: | :---------: | ----- +Atmega328 @ 16MHz | X | | | +Atmega328 @ 12MHz | X | | | +Atmega32u4 @ 16MHz | X | | | Use SDA/SCL on pins D2 & D3 +Atmega32u4 @ 8MHz | X | | | Use SDA/SCL on pins D2 & D3 +ESP8266 | X | | | SDA/SCL default to pins 4 & 5 but any two pins can be assigned as SDA/SCL using Wire.begin(SDA,SCL) +Atmega2560 @ 16MHz | X | | | Use SDA/SCL on pins 20 & 21 +ATSAM3X8E | X | | | Use SDA/SCL on pins 20 & 21 +ATSAM21D | X | | | +ATtiny85 @ 16MHz | | X | | +ATtiny85 @ 8MHz | | X | | +Intel Curie @ 32MHz | | | X | +STM32F2 | | | X | + + * ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini + * ATmega328 @ 12MHz : Adafruit Pro Trinket 3V + * ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0 + * ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro + * ESP8266 : Adafruit Huzzah + * ATmega2560 @ 16MHz : Arduino Mega + * ATSAM3X8E : Arduino Due + * ATSAM21D : Arduino Zero, M0 Pro + * ATtiny85 @ 16MHz : Adafruit Trinket 5V + * ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V + + diff --git a/lib/Adafruit_BMP280_Library/assets/board.jpg b/lib/Adafruit_BMP280_Library/assets/board.jpg new file mode 100644 index 0000000..cd0d947 Binary files /dev/null and b/lib/Adafruit_BMP280_Library/assets/board.jpg differ diff --git a/lib/Adafruit_BMP280_Library/examples/bmp280test/bmp280test.ino b/lib/Adafruit_BMP280_Library/examples/bmp280test/bmp280test.ino new file mode 100644 index 0000000..ceb4fa6 --- /dev/null +++ b/lib/Adafruit_BMP280_Library/examples/bmp280test/bmp280test.ino @@ -0,0 +1,63 @@ +/*************************************************************************** + This is a library for the BMP280 humidity, temperature & pressure sensor + + Designed specifically to work with the Adafruit BMEP280 Breakout + ----> http://www.adafruit.com/products/2651 + + These sensors use I2C or SPI to communicate, 2 or 4 pins are required + to interface. + + Adafruit invests time and resources providing this open source code, + please support Adafruit andopen-source hardware by purchasing products + from Adafruit! + + Written by Limor Fried & Kevin Townsend for Adafruit Industries. + BSD license, all text above must be included in any redistribution + ***************************************************************************/ + +#include +#include +#include + +#define BMP_SCK (13) +#define BMP_MISO (12) +#define BMP_MOSI (11) +#define BMP_CS (10) + +Adafruit_BMP280 bmp; // I2C +//Adafruit_BMP280 bmp(BMP_CS); // hardware SPI +//Adafruit_BMP280 bmp(BMP_CS, BMP_MOSI, BMP_MISO, BMP_SCK); + +void setup() { + Serial.begin(9600); + Serial.println(F("BMP280 test")); + + if (!bmp.begin()) { + Serial.println(F("Could not find a valid BMP280 sensor, check wiring!")); + while (1); + } + + /* Default settings from datasheet. */ + bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */ + Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */ + Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */ + Adafruit_BMP280::FILTER_X16, /* Filtering. */ + Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */ +} + +void loop() { + Serial.print(F("Temperature = ")); + Serial.print(bmp.readTemperature()); + Serial.println(" *C"); + + Serial.print(F("Pressure = ")); + Serial.print(bmp.readPressure()); + Serial.println(" Pa"); + + Serial.print(F("Approx altitude = ")); + Serial.print(bmp.readAltitude(1013.25)); /* Adjusted to local forecast! */ + Serial.println(" m"); + + Serial.println(); + delay(2000); +} diff --git a/lib/Adafruit_BMP280_Library/library.properties b/lib/Adafruit_BMP280_Library/library.properties new file mode 100644 index 0000000..019cdfc --- /dev/null +++ b/lib/Adafruit_BMP280_Library/library.properties @@ -0,0 +1,9 @@ +name=Adafruit BMP280 Library +version=1.0.3 +author=Adafruit +maintainer=Adafruit +sentence=Arduino library for BMP280 sensors. +paragraph=Arduino library for BMP280 pressure and altitude sensors. +category=Sensors +url=https://github.com/adafruit/Adafruit_BMP280_Library +architectures=* diff --git a/lib/Adafruit_BusIO/Adafruit_BusIO_Register.cpp b/lib/Adafruit_BusIO/Adafruit_BusIO_Register.cpp new file mode 100644 index 0000000..b31ac19 --- /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)) - 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)) - 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 0000000..45ae1e1 --- /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 0000000..e35282a --- /dev/null +++ b/lib/Adafruit_BusIO/Adafruit_I2CDevice.cpp @@ -0,0 +1,184 @@ +#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; +} + +/*! + * @brief Initializes and does basic address detection + * @return True if I2C initialized and a device with the addr found + */ +bool Adafruit_I2CDevice::begin(void) { + _wire->begin(); + _begun = true; + + return detected(); +} + + +/*! + * @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 32 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 32 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) > 32) { + // 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; i endTransmission(stop) == 0); +} + + +/*! + * @brief Read from I2C into a buffer from the I2C device. Cannot be more than 32 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 > 32) { + // 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; + } + + if (_wire->requestFrom((uint8_t)_addr, (uint8_t)len, (uint8_t)stop) != len) { + // Not enough data available to fulfill our obligation! +#ifdef DEBUG_SERIAL + DEBUG_SERIAL.println(F("\tI2CDevice did not receive enough data")); +#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(void); + 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); + + + private: + uint8_t _addr; + TwoWire *_wire; + bool _begun; + +}; + +#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 0000000..703e93b --- /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 0000000..1d599bb --- /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 0000000..121f6da --- /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(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) + #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 0000000..860e3e2 --- /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 0000000..a183080 --- /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 0000000..b150525 --- /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 0000000..909cf31 --- /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 0000000..41a3043 --- /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 0000000..555cf3b --- /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 0000000..10168c5 --- /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 0000000..6f2c063 --- /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 0000000..e24f1aa --- /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 0000000..3c29ae4 --- /dev/null +++ b/lib/Adafruit_BusIO/library.properties @@ -0,0 +1,9 @@ +name=Adafruit BusIO +version=1.0.4 +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_MAX31885/.github/ISSUE_TEMPLATE.md b/lib/Adafruit_MAX31885/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..f0e2614 --- /dev/null +++ b/lib/Adafruit_MAX31885/.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_MAX31885/.github/PULL_REQUEST_TEMPLATE.md b/lib/Adafruit_MAX31885/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..7b641eb --- /dev/null +++ b/lib/Adafruit_MAX31885/.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_MAX31885/Adafruit_MAX31855.cpp b/lib/Adafruit_MAX31885/Adafruit_MAX31855.cpp new file mode 100644 index 0000000..33aa7c9 --- /dev/null +++ b/lib/Adafruit_MAX31885/Adafruit_MAX31855.cpp @@ -0,0 +1,178 @@ +/*************************************************** + This is a library for the Adafruit Thermocouple Sensor w/MAX31855K + + Designed specifically to work with the Adafruit Thermocouple Sensor + ----> https://www.adafruit.com/products/269 + + These displays use SPI to communicate, 3 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 Limor Fried/Ladyada for Adafruit Industries. + BSD license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_MAX31855.h" +#ifdef __AVR + #include +#elif defined(ESP8266) + #include +#endif + +#include +#include + + +Adafruit_MAX31855::Adafruit_MAX31855(int8_t _sclk, int8_t _cs, int8_t _miso) { + sclk = _sclk; + cs = _cs; + miso = _miso; + + initialized = false; +} + +Adafruit_MAX31855::Adafruit_MAX31855(int8_t _cs) { + cs = _cs; + sclk = miso = -1; + + initialized = false; +} + +void Adafruit_MAX31855::begin(void) { + //define pin modes + pinMode(cs, OUTPUT); + digitalWrite(cs, HIGH); + + if (sclk == -1) { + // hardware SPI + //start and configure hardware SPI + SPI.begin(); + } else { + pinMode(sclk, OUTPUT); + pinMode(miso, INPUT); + } + initialized = true; +} + +double Adafruit_MAX31855::readInternal(void) { + uint32_t v; + + v = spiread32(); + + // ignore bottom 4 bits - they're just thermocouple data + v >>= 4; + + // pull the bottom 11 bits off + float internal = v & 0x7FF; + // check sign bit! + if (v & 0x800) { + // Convert to negative value by extending sign and casting to signed type. + int16_t tmp = 0xF800 | (v & 0x7FF); + internal = tmp; + } + internal *= 0.0625; // LSB = 0.0625 degrees + //Serial.print("\tInternal Temp: "); Serial.println(internal); + return internal; +} + +double Adafruit_MAX31855::readCelsius(void) { + + int32_t v; + + v = spiread32(); + + //Serial.print("0x"); Serial.println(v, HEX); + + /* + float internal = (v >> 4) & 0x7FF; + internal *= 0.0625; + if ((v >> 4) & 0x800) + internal *= -1; + Serial.print("\tInternal Temp: "); Serial.println(internal); + */ + + if (v & 0x7) { + // uh oh, a serious problem! + return NAN; + } + + if (v & 0x80000000) { + // Negative value, drop the lower 18 bits and explicitly extend sign bits. + v = 0xFFFFC000 | ((v >> 18) & 0x00003FFFF); + } + else { + // Positive value, just drop the lower 18 bits. + v >>= 18; + } + //Serial.println(v, HEX); + + double centigrade = v; + + // LSB = 0.25 degrees C + centigrade *= 0.25; + return centigrade; +} + +uint8_t Adafruit_MAX31855::readError() { + return spiread32() & 0x7; +} + +double Adafruit_MAX31855::readFarenheit(void) { + float f = readCelsius(); + f *= 9.0; + f /= 5.0; + f += 32; + return f; +} + +uint32_t Adafruit_MAX31855::spiread32(void) { + int i; + uint32_t d = 0; + + // backcompatibility! + if (! initialized) { + begin(); + } + + digitalWrite(cs, LOW); + delay(1); + + if(sclk == -1) { + // hardware SPI + + SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0)); + + d = SPI.transfer(0); + d <<= 8; + d |= SPI.transfer(0); + d <<= 8; + d |= SPI.transfer(0); + d <<= 8; + d |= SPI.transfer(0); + + SPI.endTransaction(); + } else { + // software SPI + + digitalWrite(sclk, LOW); + delay(1); + + for (i=31; i>=0; i--) { + digitalWrite(sclk, LOW); + delay(1); + d <<= 1; + if (digitalRead(miso)) { + d |= 1; + } + + digitalWrite(sclk, HIGH); + delay(1); + } + } + + digitalWrite(cs, HIGH); + //Serial.println(d, HEX); + return d; +} diff --git a/lib/Adafruit_MAX31885/Adafruit_MAX31855.h b/lib/Adafruit_MAX31885/Adafruit_MAX31855.h new file mode 100644 index 0000000..4bcc5eb --- /dev/null +++ b/lib/Adafruit_MAX31885/Adafruit_MAX31855.h @@ -0,0 +1,44 @@ +/*************************************************** + This is a library for the Adafruit Thermocouple Sensor w/MAX31855K + + Designed specifically to work with the Adafruit Thermocouple Sensor + ----> https://www.adafruit.com/products/269 + + These displays use SPI to communicate, 3 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 Limor Fried/Ladyada for Adafruit Industries. + BSD license, all text above must be included in any redistribution + ****************************************************/ + +#ifndef ADAFRUIT_MAX31855_H +#define ADAFRUIT_MAX31855_H + +#if (ARDUINO >= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +class Adafruit_MAX31855 { + public: + Adafruit_MAX31855(int8_t _sclk, int8_t _cs, int8_t _miso); + Adafruit_MAX31855(int8_t _cs); + + void begin(void); + double readInternal(void); + double readCelsius(void); + double readFarenheit(void); + uint8_t readError(); + + private: + boolean initialized; + + int8_t sclk, miso, cs; + uint32_t spiread32(void); +}; + +#endif diff --git a/lib/Adafruit_MAX31885/README.md b/lib/Adafruit_MAX31885/README.md new file mode 100644 index 0000000..6a8bdaa --- /dev/null +++ b/lib/Adafruit_MAX31885/README.md @@ -0,0 +1,32 @@ +# Adafruit-MAX31855-library + + +## Compatibility + +MCU | Tested Works | Doesn't Work | Not Tested | Notes +------------------ | :----------: | :----------: | :---------: | ----- +Atmega328 @ 16MHz | X | | | +Atmega328 @ 12MHz | X | | | For LCD example had to move pin 7. +Atmega32u4 @ 16MHz | X | | | +Atmega32u4 @ 8MHz | X | | | +ESP8266 | X | | | +Atmega2560 @ 16MHz | X | | | +ATSAM3X8E | X | | | +ATSAM21D | X | | | +ATtiny85 @ 16MHz | | X | | +ATtiny85 @ 8MHz | | X | | +Intel Curie @ 32MHz | | | X | +STM32F2 | | | X | + + * ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini + * ATmega328 @ 12MHz : Adafruit Pro Trinket 3V + * ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0 + * ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro + * ESP8266 : Adafruit Huzzah + * ATmega2560 @ 16MHz : Arduino Mega + * ATSAM3X8E : Arduino Due + * ATSAM21D : Arduino Zero, M0 Pro + * ATtiny85 @ 16MHz : Adafruit Trinket 5V + * ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V + + diff --git a/lib/Adafruit_MAX31885/README.txt b/lib/Adafruit_MAX31885/README.txt new file mode 100644 index 0000000..cb5c9a1 --- /dev/null +++ b/lib/Adafruit_MAX31885/README.txt @@ -0,0 +1,19 @@ +This is the Adafruit MAX31885 Arduino Library + +Tested and works great with the Adafruit Thermocouple Breakout w/MAX31885K + ------> http://www.adafruit.com/products/269 + +These modules use SPI to communicate, 3 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 Limor Fried/Ladyada for Adafruit Industries. +BSD license, check license.txt for more information +All text above must be included in any redistribution + +To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder Adafruit_MAX31885. Check that the Adafruit_MAX31885 folder contains Adafruit_MAX31885.cpp and Adafruit_MAX31885.h + +Place the Adafruit_MAX31885 library folder your /libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. \ No newline at end of file diff --git a/lib/Adafruit_MAX31885/examples/lcdthermocouple/lcdthermocouple.ino b/lib/Adafruit_MAX31885/examples/lcdthermocouple/lcdthermocouple.ino new file mode 100644 index 0000000..2412818 --- /dev/null +++ b/lib/Adafruit_MAX31885/examples/lcdthermocouple/lcdthermocouple.ino @@ -0,0 +1,77 @@ +/*************************************************** + This is an example for the Adafruit Thermocouple Sensor w/MAX31855K + + Designed specifically to work with the Adafruit Thermocouple Sensor + ----> https://www.adafruit.com/products/269 + + These displays use SPI to communicate, 3 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 Limor Fried/Ladyada for Adafruit Industries. + BSD license, all text above must be included in any redistribution + ****************************************************/ +#include +#include +#include "Adafruit_MAX31855.h" +#include + +// Example creating a thermocouple instance with software SPI on any three +// digital IO pins. +#define MAXDO 3 +#define MAXCS 4 +#define MAXCLK 5 + +// Initialize the Thermocouple +Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO); + +// initialize the library with the numbers of the interface pins +LiquidCrystal lcd(7, 8, 9, 10, 11, 12); + +#if defined(ARDUINO_ARCH_SAMD) +// for Zero, output on USB Serial console, remove line below if using programming port to program the Zero! + #define Serial SerialUSB +#endif + +void setup() { + #ifndef ESP8266 + while (!Serial); // will pause Zero, Leonardo, etc until serial console opens + #endif + Serial.begin(9600); + // set up the LCD's number of columns and rows: + lcd.begin(16, 2); + + lcd.clear(); + lcd.print("MAX31855 test"); + // wait for MAX chip to stabilize + delay(500); +} + +void loop() { + // basic readout test, just print the current temp + lcd.clear(); + lcd.setCursor(0, 0); + lcd.print("Int. Temp = "); + lcd.println(thermocouple.readInternal()); + Serial.print("Int. Temp = "); + Serial.println(thermocouple.readInternal()); + + double c = thermocouple.readCelsius(); + lcd.setCursor(0, 1); + if (isnan(c)) + { + lcd.print("T/C Problem"); + } + else + { + lcd.print("C = "); + lcd.print(c); + lcd.print(" "); + Serial.print("Thermocouple Temp = *"); + Serial.println(c); + } + + delay(1000); +} diff --git a/lib/Adafruit_MAX31885/examples/serialthermocouple/serialthermocouple.ino b/lib/Adafruit_MAX31885/examples/serialthermocouple/serialthermocouple.ino new file mode 100644 index 0000000..0e348f7 --- /dev/null +++ b/lib/Adafruit_MAX31885/examples/serialthermocouple/serialthermocouple.ino @@ -0,0 +1,63 @@ +/*************************************************** + This is an example for the Adafruit Thermocouple Sensor w/MAX31855K + + Designed specifically to work with the Adafruit Thermocouple Sensor + ----> https://www.adafruit.com/products/269 + + These displays use SPI to communicate, 3 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 Limor Fried/Ladyada for Adafruit Industries. + BSD license, all text above must be included in any redistribution + ****************************************************/ + +#include +#include "Adafruit_MAX31855.h" + +// Default connection is using software SPI, but comment and uncomment one of +// the two examples below to switch between software SPI and hardware SPI: + +// Example creating a thermocouple instance with software SPI on any three +// digital IO pins. +#define MAXDO 3 +#define MAXCS 4 +#define MAXCLK 5 + +// initialize the Thermocouple +Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO); + +// Example creating a thermocouple instance with hardware SPI +// on a given CS pin. +//#define MAXCS 10 +//Adafruit_MAX31855 thermocouple(MAXCS); + +void setup() { + Serial.begin(9600); + + while (!Serial) delay(1); // wait for Serial on Leonardo/Zero, etc + + Serial.println("MAX31855 test"); + // wait for MAX chip to stabilize + delay(500); +} + +void loop() { + // basic readout test, just print the current temp + Serial.print("Internal Temp = "); + Serial.println(thermocouple.readInternal()); + + double c = thermocouple.readCelsius(); + if (isnan(c)) { + Serial.println("Something wrong with thermocouple!"); + } else { + Serial.print("C = "); + Serial.println(c); + } + //Serial.print("F = "); + //Serial.println(thermocouple.readFarenheit()); + + delay(1000); +} \ No newline at end of file diff --git a/lib/Adafruit_MAX31885/keywords.txt b/lib/Adafruit_MAX31885/keywords.txt new file mode 100644 index 0000000..66e429e --- /dev/null +++ b/lib/Adafruit_MAX31885/keywords.txt @@ -0,0 +1,21 @@ +####################################### +# Syntax Coloring Map for NewSoftSerial +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +max6675 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +readCelsius KEYWORD2 +readFarenheit KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/lib/Adafruit_MAX31885/library.properties b/lib/Adafruit_MAX31885/library.properties new file mode 100644 index 0000000..5b6892d --- /dev/null +++ b/lib/Adafruit_MAX31885/library.properties @@ -0,0 +1,9 @@ +name=Adafruit MAX31855 library +version=1.0.3 +author=Adafruit +maintainer=Adafruit +sentence=Library for the Adafruit Thermocouple breakout with MAX31855K +paragraph=Library for the Adafruit Thermocouple breakout with MAX31855K +category=Sensors +url=https://github.com/adafruit/Adafruit-MAX31855-library +architectures=* diff --git a/lib/Adafruit_MAX31885/license.txt b/lib/Adafruit_MAX31885/license.txt new file mode 100644 index 0000000..f6a0f22 --- /dev/null +++ b/lib/Adafruit_MAX31885/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/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp b/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp new file mode 100644 index 0000000..61f2ad4 --- /dev/null +++ b/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp @@ -0,0 +1,2589 @@ +/*! + * @file Adafruit_NeoPixel.cpp + * + * @mainpage Arduino Library for driving Adafruit NeoPixel addressable LEDs, + * FLORA RGB Smart Pixels and compatible devicess -- WS2811, WS2812, WS2812B, + * SK6812, etc. + * + * @section intro_sec Introduction + * + * This is the documentation for Adafruit's NeoPixel library for the + * Arduino platform, allowing a broad range of microcontroller boards + * (most AVR boards, many ARM devices, ESP8266 and ESP32, among others) + * to control Adafruit NeoPixels, FLORA RGB Smart Pixels and compatible + * devices -- WS2811, WS2812, WS2812B, SK6812, etc. + * + * 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 + * + * Written by Phil "Paint Your Dragon" Burgess for Adafruit Industries, + * with contributions by PJRC, Michael Miller and other members of the + * open source community. + * + * @section license License + * + * This file is part of the Adafruit_NeoPixel library. + * + * Adafruit_NeoPixel is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Adafruit_NeoPixel 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with NeoPixel. If not, see + * . + * + */ + +#include "Adafruit_NeoPixel.h" + +#if defined(TARGET_LPC1768) + #include +#endif + +#if defined(NRF52) || defined(NRF52_SERIES) +#include "nrf.h" + +// Interrupt is only disabled if there is no PWM device available +// Note: Adafruit Bluefruit nrf52 does not use this option +//#define NRF52_DISABLE_INT +#endif + +/*! + @brief NeoPixel constructor when length, pin and pixel type are known + at compile-time. + @param n Number of NeoPixels in strand. + @param p Arduino pin number which will drive the NeoPixel data in. + @param t Pixel type -- add together NEO_* constants defined in + Adafruit_NeoPixel.h, for example NEO_GRB+NEO_KHZ800 for + NeoPixels expecting an 800 KHz (vs 400 KHz) data stream + with color bytes expressed in green, red, blue order per + pixel. + @return Adafruit_NeoPixel object. Call the begin() function before use. +*/ +Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, uint16_t p, neoPixelType t) : + begun(false), brightness(0), pixels(NULL), endTime(0) { + updateType(t); + updateLength(n); + setPin(p); +} + +/*! + @brief "Empty" NeoPixel constructor when length, pin and/or pixel type + are not known at compile-time, and must be initialized later with + updateType(), updateLength() and setPin(). + @return Adafruit_NeoPixel object. Call the begin() function before use. + @note This function is deprecated, here only for old projects that + may still be calling it. New projects should instead use the + 'new' keyword with the first constructor syntax (length, pin, + type). +*/ +Adafruit_NeoPixel::Adafruit_NeoPixel() : +#if defined(NEO_KHZ400) + is800KHz(true), +#endif + begun(false), numLEDs(0), numBytes(0), pin(-1), brightness(0), pixels(NULL), + rOffset(1), gOffset(0), bOffset(2), wOffset(1), endTime(0) { +} + +/*! + @brief Deallocate Adafruit_NeoPixel object, set data pin back to INPUT. +*/ +Adafruit_NeoPixel::~Adafruit_NeoPixel() { + free(pixels); + if(pin >= 0) pinMode(pin, INPUT); +} + +/*! + @brief Configure NeoPixel pin for output. +*/ +void Adafruit_NeoPixel::begin(void) { + if(pin >= 0) { + pinMode(pin, OUTPUT); + digitalWrite(pin, LOW); + } + begun = true; +} + +/*! + @brief Change the length of a previously-declared Adafruit_NeoPixel + strip object. Old data is deallocated and new data is cleared. + Pin number and pixel format are unchanged. + @param n New length of strip, in pixels. + @note This function is deprecated, here only for old projects that + may still be calling it. New projects should instead use the + 'new' keyword with the first constructor syntax (length, pin, + type). +*/ +void Adafruit_NeoPixel::updateLength(uint16_t n) { + free(pixels); // Free existing data (if any) + + // Allocate new data -- note: ALL PIXELS ARE CLEARED + numBytes = n * ((wOffset == rOffset) ? 3 : 4); + if((pixels = (uint8_t *)malloc(numBytes))) { + memset(pixels, 0, numBytes); + numLEDs = n; + } else { + numLEDs = numBytes = 0; + } +} + +/*! + @brief Change the pixel format of a previously-declared + Adafruit_NeoPixel strip object. If format changes from one of + the RGB variants to an RGBW variant (or RGBW to RGB), the old + data will be deallocated and new data is cleared. Otherwise, + the old data will remain in RAM and is not reordered to the + new format, so it's advisable to follow up with clear(). + @param t Pixel type -- add together NEO_* constants defined in + Adafruit_NeoPixel.h, for example NEO_GRB+NEO_KHZ800 for + NeoPixels expecting an 800 KHz (vs 400 KHz) data stream + with color bytes expressed in green, red, blue order per + pixel. + @note This function is deprecated, here only for old projects that + may still be calling it. New projects should instead use the + 'new' keyword with the first constructor syntax + (length, pin, type). +*/ +void Adafruit_NeoPixel::updateType(neoPixelType t) { + bool oldThreeBytesPerPixel = (wOffset == rOffset); // false if RGBW + + wOffset = (t >> 6) & 0b11; // See notes in header file + rOffset = (t >> 4) & 0b11; // regarding R/G/B/W offsets + gOffset = (t >> 2) & 0b11; + bOffset = t & 0b11; +#if defined(NEO_KHZ400) + is800KHz = (t < 256); // 400 KHz flag is 1<<8 +#endif + + // If bytes-per-pixel has changed (and pixel data was previously + // allocated), re-allocate to new size. Will clear any data. + if(pixels) { + bool newThreeBytesPerPixel = (wOffset == rOffset); + if(newThreeBytesPerPixel != oldThreeBytesPerPixel) updateLength(numLEDs); + } +} + +#if defined(ESP8266) +// ESP8266 show() is external to enforce ICACHE_RAM_ATTR execution +extern "C" void ICACHE_RAM_ATTR espShow( + uint16_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t type); +#elif defined(ESP32) +extern "C" void espShow( + uint16_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t type); +#endif // ESP8266 + +/*! + @brief Transmit pixel data in RAM to NeoPixels. + @note On most architectures, interrupts are temporarily disabled in + order to achieve the correct NeoPixel signal timing. This means + that the Arduino millis() and micros() functions, which require + interrupts, will lose small intervals of time whenever this + function is called (about 30 microseconds per RGB pixel, 40 for + RGBW pixels). There's no easy fix for this, but a few + specialized alternative or companion libraries exist that use + very device-specific peripherals to work around it. +*/ +void Adafruit_NeoPixel::show(void) { + + if(!pixels) return; + + // Data latch = 300+ microsecond pause in the output stream. Rather than + // put a delay at the end of the function, the ending time is noted and + // the function will simply hold off (if needed) on issuing the + // subsequent round of data until the latch time has elapsed. This + // allows the mainline code to start generating the next frame of data + // rather than stalling for the latch. + while(!canShow()); + // endTime is a private member (rather than global var) so that multiple + // instances on different pins can be quickly issued in succession (each + // instance doesn't delay the next). + + // In order to make this code runtime-configurable to work with any pin, + // SBI/CBI instructions are eschewed in favor of full PORT writes via the + // OUT or ST instructions. It relies on two facts: that peripheral + // functions (such as PWM) take precedence on output pins, so our PORT- + // wide writes won't interfere, and that interrupts are globally disabled + // while data is being issued to the LEDs, so no other code will be + // accessing the PORT. The code takes an initial 'snapshot' of the PORT + // state, computes 'pin high' and 'pin low' values, and writes these back + // to the PORT register as needed. + + // NRF52 may use PWM + DMA (if available), may not need to disable interrupt +#if !( defined(NRF52) || defined(NRF52_SERIES) ) + noInterrupts(); // Need 100% focus on instruction timing +#endif + +#if defined(__AVR__) +// AVR MCUs -- ATmega & ATtiny (no XMEGA) --------------------------------- + + volatile uint16_t + i = numBytes; // Loop counter + volatile uint8_t + *ptr = pixels, // Pointer to next byte + b = *ptr++, // Current byte value + hi, // PORT w/output bit set high + lo; // PORT w/output bit set low + + // Hand-tuned assembly code issues data to the LED drivers at a specific + // rate. There's separate code for different CPU speeds (8, 12, 16 MHz) + // for both the WS2811 (400 KHz) and WS2812 (800 KHz) drivers. The + // datastream timing for the LED drivers allows a little wiggle room each + // way (listed in the datasheets), so the conditions for compiling each + // case are set up for a range of frequencies rather than just the exact + // 8, 12 or 16 MHz values, permitting use with some close-but-not-spot-on + // devices (e.g. 16.5 MHz DigiSpark). The ranges were arrived at based + // on the datasheet figures and have not been extensively tested outside + // the canonical 8/12/16 MHz speeds; there's no guarantee these will work + // close to the extremes (or possibly they could be pushed further). + // Keep in mind only one CPU speed case actually gets compiled; the + // resulting program isn't as massive as it might look from source here. + +// 8 MHz(ish) AVR --------------------------------------------------------- +#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) + +#if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled + if(is800KHz) { +#endif + + volatile uint8_t n1, n2 = 0; // First, next bits out + + // Squeezing an 800 KHz stream out of an 8 MHz chip requires code + // specific to each PORT register. + + // 10 instruction clocks per bit: HHxxxxxLLL + // OUT instructions: ^ ^ ^ (T=0,2,7) + + // PORTD OUTPUT ---------------------------------------------------- + +#if defined(PORTD) + #if defined(PORTB) || defined(PORTC) || defined(PORTF) + if(port == &PORTD) { + #endif // defined(PORTB/C/F) + + hi = PORTD | pinMask; + lo = PORTD & ~pinMask; + n1 = lo; + if(b & 0x80) n1 = hi; + + // Dirty trick: RJMPs proceeding to the next instruction are used + // to delay two clock cycles in one instruction word (rather than + // using two NOPs). This was necessary in order to squeeze the + // loop down to exactly 64 words -- the maximum possible for a + // relative branch. + + asm volatile( + "headD:" "\n\t" // Clk Pseudocode + // Bit 7: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 6" "\n\t" // 1-2 if(b & 0x40) + "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 6: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 5" "\n\t" // 1-2 if(b & 0x20) + "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 5: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 4" "\n\t" // 1-2 if(b & 0x10) + "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 4: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 3" "\n\t" // 1-2 if(b & 0x08) + "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 3: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 2" "\n\t" // 1-2 if(b & 0x04) + "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 2: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 1" "\n\t" // 1-2 if(b & 0x02) + "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 1: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 0" "\n\t" // 1-2 if(b & 0x01) + "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "sbiw %[count], 1" "\n\t" // 2 i-- (don't act on Z flag yet) + // Bit 0: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) + "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "brne headD" "\n" // 2 while(i) (Z flag set above) + : [byte] "+r" (b), + [n1] "+r" (n1), + [n2] "+r" (n2), + [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTD)), + [ptr] "e" (ptr), + [hi] "r" (hi), + [lo] "r" (lo)); + + #if defined(PORTB) || defined(PORTC) || defined(PORTF) + } else // other PORT(s) + #endif // defined(PORTB/C/F) +#endif // defined(PORTD) + + // PORTB OUTPUT ---------------------------------------------------- + +#if defined(PORTB) + #if defined(PORTD) || defined(PORTC) || defined(PORTF) + if(port == &PORTB) { + #endif // defined(PORTD/C/F) + + // Same as above, just switched to PORTB and stripped of comments. + hi = PORTB | pinMask; + lo = PORTB & ~pinMask; + n1 = lo; + if(b & 0x80) n1 = hi; + + asm volatile( + "headB:" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 6" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 5" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 4" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 3" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 2" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 1" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 0" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "sbiw %[count], 1" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "ld %[byte] , %a[ptr]+" "\n\t" + "sbrc %[byte] , 7" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "brne headB" "\n" + : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), + [lo] "r" (lo)); + + #if defined(PORTD) || defined(PORTC) || defined(PORTF) + } + #endif + #if defined(PORTC) || defined(PORTF) + else + #endif // defined(PORTC/F) +#endif // defined(PORTB) + + // PORTC OUTPUT ---------------------------------------------------- + +#if defined(PORTC) + #if defined(PORTD) || defined(PORTB) || defined(PORTF) + if(port == &PORTC) { + #endif // defined(PORTD/B/F) + + // Same as above, just switched to PORTC and stripped of comments. + hi = PORTC | pinMask; + lo = PORTC & ~pinMask; + n1 = lo; + if(b & 0x80) n1 = hi; + + asm volatile( + "headC:" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 6" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 5" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 4" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 3" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 2" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 1" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 0" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "sbiw %[count], 1" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "ld %[byte] , %a[ptr]+" "\n\t" + "sbrc %[byte] , 7" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "brne headC" "\n" + : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTC)), [ptr] "e" (ptr), [hi] "r" (hi), + [lo] "r" (lo)); + + #if defined(PORTD) || defined(PORTB) || defined(PORTF) + } + #endif // defined(PORTD/B/F) + #if defined(PORTF) + else + #endif +#endif // defined(PORTC) + + // PORTF OUTPUT ---------------------------------------------------- + +#if defined(PORTF) + #if defined(PORTD) || defined(PORTB) || defined(PORTC) + if(port == &PORTF) { + #endif // defined(PORTD/B/C) + + hi = PORTF | pinMask; + lo = PORTF & ~pinMask; + n1 = lo; + if(b & 0x80) n1 = hi; + + asm volatile( + "headF:" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 6" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 5" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 4" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 3" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 2" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 1" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 0" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "sbiw %[count], 1" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "ld %[byte] , %a[ptr]+" "\n\t" + "sbrc %[byte] , 7" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "brne headF" "\n" + : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTF)), [ptr] "e" (ptr), [hi] "r" (hi), + [lo] "r" (lo)); + + #if defined(PORTD) || defined(PORTB) || defined(PORTC) + } + #endif // defined(PORTD/B/C) +#endif // defined(PORTF) + +#if defined(NEO_KHZ400) + } else { // end 800 KHz, do 400 KHz + + // Timing is more relaxed; unrolling the inner loop for each bit is + // not necessary. Still using the peculiar RJMPs as 2X NOPs, not out + // of need but just to trim the code size down a little. + // This 400-KHz-datastream-on-8-MHz-CPU code is not quite identical + // to the 800-on-16 code later -- the hi/lo timing between WS2811 and + // WS2812 is not simply a 2:1 scale! + + // 20 inst. clocks per bit: HHHHxxxxxxLLLLLLLLLL + // ST instructions: ^ ^ ^ (T=0,4,10) + + volatile uint8_t next, bit; + + hi = *port | pinMask; + lo = *port & ~pinMask; + next = lo; + bit = 8; + + asm volatile( + "head20:" "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) + "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) + "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 6) + "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7) + "dec %[bit]" "\n\t" // 1 bit-- (T = 8) + "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12) + "rjmp .+0" "\n\t" // 2 nop nop (T = 14) + "rjmp .+0" "\n\t" // 2 nop nop (T = 16) + "rjmp .+0" "\n\t" // 2 nop nop (T = 18) + "rjmp head20" "\n\t" // 2 -> head20 (next bit out) + "nextbyte20:" "\n\t" // (T = 10) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12) + "nop" "\n\t" // 1 nop (T = 13) + "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 14) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 16) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) + "brne head20" "\n" // 2 if(i != 0) -> (next byte) + : [port] "+e" (port), + [byte] "+r" (b), + [bit] "+r" (bit), + [next] "+r" (next), + [count] "+w" (i) + : [hi] "r" (hi), + [lo] "r" (lo), + [ptr] "e" (ptr)); + } +#endif // NEO_KHZ400 + +// 12 MHz(ish) AVR -------------------------------------------------------- +#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) + +#if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled + if(is800KHz) { +#endif + + // In the 12 MHz case, an optimized 800 KHz datastream (no dead time + // between bytes) requires a PORT-specific loop similar to the 8 MHz + // code (but a little more relaxed in this case). + + // 15 instruction clocks per bit: HHHHxxxxxxLLLLL + // OUT instructions: ^ ^ ^ (T=0,4,10) + + volatile uint8_t next; + + // PORTD OUTPUT ---------------------------------------------------- + +#if defined(PORTD) + #if defined(PORTB) || defined(PORTC) || defined(PORTF) + if(port == &PORTD) { + #endif // defined(PORTB/C/F) + + hi = PORTD | pinMask; + lo = PORTD & ~pinMask; + next = lo; + if(b & 0x80) next = hi; + + // Don't "optimize" the OUT calls into the bitTime subroutine; + // we're exploiting the RCALL and RET as 3- and 4-cycle NOPs! + asm volatile( + "headD:" "\n\t" // (T = 0) + "out %[port], %[hi]" "\n\t" // (T = 1) + "rcall bitTimeD" "\n\t" // Bit 7 (T = 15) + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 6 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 5 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 4 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 3 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 2 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 1 + // Bit 0: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi (T = 1) + "rjmp .+0" "\n\t" // 2 nop nop (T = 3) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 5) + "out %[port] , %[next]" "\n\t" // 1 PORT = next (T = 6) + "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7) + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) (T = 8) + "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 9) + "nop" "\n\t" // 1 (T = 10) + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo (T = 11) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 13) + "brne headD" "\n\t" // 2 if(i != 0) -> (next byte) + "rjmp doneD" "\n\t" + "bitTimeD:" "\n\t" // nop nop nop (T = 4) + "out %[port], %[next]" "\n\t" // 1 PORT = next (T = 5) + "mov %[next], %[lo]" "\n\t" // 1 next = lo (T = 6) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 7) + "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 0x80) (T = 8) + "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 9) + "nop" "\n\t" // 1 (T = 10) + "out %[port], %[lo]" "\n\t" // 1 PORT = lo (T = 11) + "ret" "\n\t" // 4 nop nop nop nop (T = 15) + "doneD:" "\n" + : [byte] "+r" (b), + [next] "+r" (next), + [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTD)), + [ptr] "e" (ptr), + [hi] "r" (hi), + [lo] "r" (lo)); + + #if defined(PORTB) || defined(PORTC) || defined(PORTF) + } else // other PORT(s) + #endif // defined(PORTB/C/F) +#endif // defined(PORTD) + + // PORTB OUTPUT ---------------------------------------------------- + +#if defined(PORTB) + #if defined(PORTD) || defined(PORTC) || defined(PORTF) + if(port == &PORTB) { + #endif // defined(PORTD/C/F) + + hi = PORTB | pinMask; + lo = PORTB & ~pinMask; + next = lo; + if(b & 0x80) next = hi; + + // Same as above, just set for PORTB & stripped of comments + asm volatile( + "headB:" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port] , %[hi]" "\n\t" + "rjmp .+0" "\n\t" + "ld %[byte] , %a[ptr]+" "\n\t" + "out %[port] , %[next]" "\n\t" + "mov %[next] , %[lo]" "\n\t" + "sbrc %[byte] , 7" "\n\t" + "mov %[next] , %[hi]" "\n\t" + "nop" "\n\t" + "out %[port] , %[lo]" "\n\t" + "sbiw %[count], 1" "\n\t" + "brne headB" "\n\t" + "rjmp doneB" "\n\t" + "bitTimeB:" "\n\t" + "out %[port], %[next]" "\n\t" + "mov %[next], %[lo]" "\n\t" + "rol %[byte]" "\n\t" + "sbrc %[byte], 7" "\n\t" + "mov %[next], %[hi]" "\n\t" + "nop" "\n\t" + "out %[port], %[lo]" "\n\t" + "ret" "\n\t" + "doneB:" "\n" + : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), + [lo] "r" (lo)); + + #if defined(PORTD) || defined(PORTC) || defined(PORTF) + } + #endif + #if defined(PORTC) || defined(PORTF) + else + #endif // defined(PORTC/F) +#endif // defined(PORTB) + + // PORTC OUTPUT ---------------------------------------------------- + +#if defined(PORTC) + #if defined(PORTD) || defined(PORTB) || defined(PORTF) + if(port == &PORTC) { + #endif // defined(PORTD/B/F) + + hi = PORTC | pinMask; + lo = PORTC & ~pinMask; + next = lo; + if(b & 0x80) next = hi; + + // Same as above, just set for PORTC & stripped of comments + asm volatile( + "headC:" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeC" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeC" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeC" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeC" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeC" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeC" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeC" "\n\t" + "out %[port] , %[hi]" "\n\t" + "rjmp .+0" "\n\t" + "ld %[byte] , %a[ptr]+" "\n\t" + "out %[port] , %[next]" "\n\t" + "mov %[next] , %[lo]" "\n\t" + "sbrc %[byte] , 7" "\n\t" + "mov %[next] , %[hi]" "\n\t" + "nop" "\n\t" + "out %[port] , %[lo]" "\n\t" + "sbiw %[count], 1" "\n\t" + "brne headC" "\n\t" + "rjmp doneC" "\n\t" + "bitTimeC:" "\n\t" + "out %[port], %[next]" "\n\t" + "mov %[next], %[lo]" "\n\t" + "rol %[byte]" "\n\t" + "sbrc %[byte], 7" "\n\t" + "mov %[next], %[hi]" "\n\t" + "nop" "\n\t" + "out %[port], %[lo]" "\n\t" + "ret" "\n\t" + "doneC:" "\n" + : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTC)), [ptr] "e" (ptr), [hi] "r" (hi), + [lo] "r" (lo)); + + #if defined(PORTD) || defined(PORTB) || defined(PORTF) + } + #endif // defined(PORTD/B/F) + #if defined(PORTF) + else + #endif +#endif // defined(PORTC) + + // PORTF OUTPUT ---------------------------------------------------- + +#if defined(PORTF) + #if defined(PORTD) || defined(PORTB) || defined(PORTC) + if(port == &PORTF) { + #endif // defined(PORTD/B/C) + + hi = PORTF | pinMask; + lo = PORTF & ~pinMask; + next = lo; + if(b & 0x80) next = hi; + + // Same as above, just set for PORTF & stripped of comments + asm volatile( + "headF:" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeC" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeC" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeC" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeC" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeC" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeC" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeC" "\n\t" + "out %[port] , %[hi]" "\n\t" + "rjmp .+0" "\n\t" + "ld %[byte] , %a[ptr]+" "\n\t" + "out %[port] , %[next]" "\n\t" + "mov %[next] , %[lo]" "\n\t" + "sbrc %[byte] , 7" "\n\t" + "mov %[next] , %[hi]" "\n\t" + "nop" "\n\t" + "out %[port] , %[lo]" "\n\t" + "sbiw %[count], 1" "\n\t" + "brne headF" "\n\t" + "rjmp doneC" "\n\t" + "bitTimeC:" "\n\t" + "out %[port], %[next]" "\n\t" + "mov %[next], %[lo]" "\n\t" + "rol %[byte]" "\n\t" + "sbrc %[byte], 7" "\n\t" + "mov %[next], %[hi]" "\n\t" + "nop" "\n\t" + "out %[port], %[lo]" "\n\t" + "ret" "\n\t" + "doneC:" "\n" + : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTF)), [ptr] "e" (ptr), [hi] "r" (hi), + [lo] "r" (lo)); + + #if defined(PORTD) || defined(PORTB) || defined(PORTC) + } + #endif // defined(PORTD/B/C) +#endif // defined(PORTF) + +#if defined(NEO_KHZ400) + } else { // 400 KHz + + // 30 instruction clocks per bit: HHHHHHxxxxxxxxxLLLLLLLLLLLLLLL + // ST instructions: ^ ^ ^ (T=0,6,15) + + volatile uint8_t next, bit; + + hi = *port | pinMask; + lo = *port & ~pinMask; + next = lo; + bit = 8; + + asm volatile( + "head30:" "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) + "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) + "rjmp .+0" "\n\t" // 2 nop nop (T = 6) + "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 8) + "rjmp .+0" "\n\t" // 2 nop nop (T = 10) + "rjmp .+0" "\n\t" // 2 nop nop (T = 12) + "rjmp .+0" "\n\t" // 2 nop nop (T = 14) + "nop" "\n\t" // 1 nop (T = 15) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 17) + "rjmp .+0" "\n\t" // 2 nop nop (T = 19) + "dec %[bit]" "\n\t" // 1 bit-- (T = 20) + "breq nextbyte30" "\n\t" // 1-2 if(bit == 0) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 22) + "rjmp .+0" "\n\t" // 2 nop nop (T = 24) + "rjmp .+0" "\n\t" // 2 nop nop (T = 26) + "rjmp .+0" "\n\t" // 2 nop nop (T = 28) + "rjmp head30" "\n\t" // 2 -> head30 (next bit out) + "nextbyte30:" "\n\t" // (T = 22) + "nop" "\n\t" // 1 nop (T = 23) + "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 24) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 26) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 28) + "brne head30" "\n" // 1-2 if(i != 0) -> (next byte) + : [port] "+e" (port), + [byte] "+r" (b), + [bit] "+r" (bit), + [next] "+r" (next), + [count] "+w" (i) + : [hi] "r" (hi), + [lo] "r" (lo), + [ptr] "e" (ptr)); + } +#endif // NEO_KHZ400 + +// 16 MHz(ish) AVR -------------------------------------------------------- +#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) + +#if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled + if(is800KHz) { +#endif + + // WS2811 and WS2812 have different hi/lo duty cycles; this is + // similar but NOT an exact copy of the prior 400-on-8 code. + + // 20 inst. clocks per bit: HHHHHxxxxxxxxLLLLLLL + // ST instructions: ^ ^ ^ (T=0,5,13) + + volatile uint8_t next, bit; + + hi = *port | pinMask; + lo = *port & ~pinMask; + next = lo; + bit = 8; + + asm volatile( + "head20:" "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128) + "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) + "dec %[bit]" "\n\t" // 1 bit-- (T = 5) + "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7) + "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8) + "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) + "rjmp .+0" "\n\t" // 2 nop nop (T = 12) + "nop" "\n\t" // 1 nop (T = 13) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) + "nop" "\n\t" // 1 nop (T = 16) + "rjmp .+0" "\n\t" // 2 nop nop (T = 18) + "rjmp head20" "\n\t" // 2 -> head20 (next bit out) + "nextbyte20:" "\n\t" // (T = 10) + "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) + "nop" "\n\t" // 1 nop (T = 16) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) + "brne head20" "\n" // 2 if(i != 0) -> (next byte) + : [port] "+e" (port), + [byte] "+r" (b), + [bit] "+r" (bit), + [next] "+r" (next), + [count] "+w" (i) + : [ptr] "e" (ptr), + [hi] "r" (hi), + [lo] "r" (lo)); + +#if defined(NEO_KHZ400) + } else { // 400 KHz + + // The 400 KHz clock on 16 MHz MCU is the most 'relaxed' version. + + // 40 inst. clocks per bit: HHHHHHHHxxxxxxxxxxxxLLLLLLLLLLLLLLLLLLLL + // ST instructions: ^ ^ ^ (T=0,8,20) + + volatile uint8_t next, bit; + + hi = *port | pinMask; + lo = *port & ~pinMask; + next = lo; + bit = 8; + + asm volatile( + "head40:" "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) + "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 4) + "rjmp .+0" "\n\t" // 2 nop nop (T = 6) + "rjmp .+0" "\n\t" // 2 nop nop (T = 8) + "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 10) + "rjmp .+0" "\n\t" // 2 nop nop (T = 12) + "rjmp .+0" "\n\t" // 2 nop nop (T = 14) + "rjmp .+0" "\n\t" // 2 nop nop (T = 16) + "rjmp .+0" "\n\t" // 2 nop nop (T = 18) + "rjmp .+0" "\n\t" // 2 nop nop (T = 20) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 22) + "nop" "\n\t" // 1 nop (T = 23) + "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 24) + "dec %[bit]" "\n\t" // 1 bit-- (T = 25) + "breq nextbyte40" "\n\t" // 1-2 if(bit == 0) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 27) + "nop" "\n\t" // 1 nop (T = 28) + "rjmp .+0" "\n\t" // 2 nop nop (T = 30) + "rjmp .+0" "\n\t" // 2 nop nop (T = 32) + "rjmp .+0" "\n\t" // 2 nop nop (T = 34) + "rjmp .+0" "\n\t" // 2 nop nop (T = 36) + "rjmp .+0" "\n\t" // 2 nop nop (T = 38) + "rjmp head40" "\n\t" // 2 -> head40 (next bit out) + "nextbyte40:" "\n\t" // (T = 27) + "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 28) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 30) + "rjmp .+0" "\n\t" // 2 nop nop (T = 32) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 34) + "rjmp .+0" "\n\t" // 2 nop nop (T = 36) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 38) + "brne head40" "\n" // 1-2 if(i != 0) -> (next byte) + : [port] "+e" (port), + [byte] "+r" (b), + [bit] "+r" (bit), + [next] "+r" (next), + [count] "+w" (i) + : [ptr] "e" (ptr), + [hi] "r" (hi), + [lo] "r" (lo)); + } +#endif // NEO_KHZ400 + +#else + #error "CPU SPEED NOT SUPPORTED" +#endif // end F_CPU ifdefs on __AVR__ + +// END AVR ---------------------------------------------------------------- + + +#elif defined(__arm__) + +// ARM MCUs -- Teensy 3.0, 3.1, LC, Arduino Due --------------------------- + +#if defined(TEENSYDUINO) && defined(KINETISK) // Teensy 3.0, 3.1, 3.2, 3.5, 3.6 +#define CYCLES_800_T0H (F_CPU / 4000000) +#define CYCLES_800_T1H (F_CPU / 1250000) +#define CYCLES_800 (F_CPU / 800000) +#define CYCLES_400_T0H (F_CPU / 2000000) +#define CYCLES_400_T1H (F_CPU / 833333) +#define CYCLES_400 (F_CPU / 400000) + + uint8_t *p = pixels, + *end = p + numBytes, pix, mask; + volatile uint8_t *set = portSetRegister(pin), + *clr = portClearRegister(pin); + uint32_t cyc; + + ARM_DEMCR |= ARM_DEMCR_TRCENA; + ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; + +#if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled + if(is800KHz) { +#endif + cyc = ARM_DWT_CYCCNT + CYCLES_800; + while(p < end) { + pix = *p++; + for(mask = 0x80; mask; mask >>= 1) { + while(ARM_DWT_CYCCNT - cyc < CYCLES_800); + cyc = ARM_DWT_CYCCNT; + *set = 1; + if(pix & mask) { + while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T1H); + } else { + while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T0H); + } + *clr = 1; + } + } + while(ARM_DWT_CYCCNT - cyc < CYCLES_800); +#if defined(NEO_KHZ400) + } else { // 400 kHz bitstream + cyc = ARM_DWT_CYCCNT + CYCLES_400; + while(p < end) { + pix = *p++; + for(mask = 0x80; mask; mask >>= 1) { + while(ARM_DWT_CYCCNT - cyc < CYCLES_400); + cyc = ARM_DWT_CYCCNT; + *set = 1; + if(pix & mask) { + while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T1H); + } else { + while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T0H); + } + *clr = 1; + } + } + while(ARM_DWT_CYCCNT - cyc < CYCLES_400); + } +#endif // NEO_KHZ400 + +#elif defined(TEENSYDUINO) && (defined(__IMXRT1052__) || defined(__IMXRT1062__)) +#define CYCLES_800_T0H (F_CPU_ACTUAL / 4000000) +#define CYCLES_800_T1H (F_CPU_ACTUAL / 1250000) +#define CYCLES_800 (F_CPU_ACTUAL / 800000) +#define CYCLES_400_T0H (F_CPU_ACTUAL / 2000000) +#define CYCLES_400_T1H (F_CPU_ACTUAL / 833333) +#define CYCLES_400 (F_CPU_ACTUAL / 400000) + + uint8_t *p = pixels, + *end = p + numBytes, pix, mask; + volatile uint32_t *set = portSetRegister(pin), + *clr = portClearRegister(pin); + uint32_t cyc, + msk = digitalPinToBitMask(pin); + + ARM_DEMCR |= ARM_DEMCR_TRCENA; + ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; + +#if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled + if(is800KHz) { +#endif + cyc = ARM_DWT_CYCCNT + CYCLES_800; + while(p < end) { + pix = *p++; + for(mask = 0x80; mask; mask >>= 1) { + while(ARM_DWT_CYCCNT - cyc < CYCLES_800); + cyc = ARM_DWT_CYCCNT; + *set = msk; + if(pix & mask) { + while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T1H); + } else { + while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T0H); + } + *clr = msk; + } + } + while(ARM_DWT_CYCCNT - cyc < CYCLES_800); +#if defined(NEO_KHZ400) + } else { // 400 kHz bitstream + cyc = ARM_DWT_CYCCNT + CYCLES_400; + while(p < end) { + pix = *p++; + for(mask = 0x80; mask; mask >>= 1) { + while(ARM_DWT_CYCCNT - cyc < CYCLES_400); + cyc = ARM_DWT_CYCCNT; + *set = msk; + if(pix & mask) { + while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T1H); + } else { + while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T0H); + } + *clr = msk; + } + } + while(ARM_DWT_CYCCNT - cyc < CYCLES_400); + } +#endif // NEO_KHZ400 + +#elif defined(TEENSYDUINO) && defined(__MKL26Z64__) // Teensy-LC + +#if F_CPU == 48000000 + uint8_t *p = pixels, + pix, count, dly, + bitmask = digitalPinToBitMask(pin); + volatile uint8_t *reg = portSetRegister(pin); + uint32_t num = numBytes; + asm volatile( + "L%=_begin:" "\n\t" + "ldrb %[pix], [%[p], #0]" "\n\t" + "lsl %[pix], #24" "\n\t" + "movs %[count], #7" "\n\t" + "L%=_loop:" "\n\t" + "lsl %[pix], #1" "\n\t" + "bcs L%=_loop_one" "\n\t" + "L%=_loop_zero:" "\n\t" + "strb %[bitmask], [%[reg], #0]" "\n\t" + "movs %[dly], #4" "\n\t" + "L%=_loop_delay_T0H:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_loop_delay_T0H" "\n\t" + "strb %[bitmask], [%[reg], #4]" "\n\t" + "movs %[dly], #13" "\n\t" + "L%=_loop_delay_T0L:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_loop_delay_T0L" "\n\t" + "b L%=_next" "\n\t" + "L%=_loop_one:" "\n\t" + "strb %[bitmask], [%[reg], #0]" "\n\t" + "movs %[dly], #13" "\n\t" + "L%=_loop_delay_T1H:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_loop_delay_T1H" "\n\t" + "strb %[bitmask], [%[reg], #4]" "\n\t" + "movs %[dly], #4" "\n\t" + "L%=_loop_delay_T1L:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_loop_delay_T1L" "\n\t" + "nop" "\n\t" + "L%=_next:" "\n\t" + "sub %[count], #1" "\n\t" + "bne L%=_loop" "\n\t" + "lsl %[pix], #1" "\n\t" + "bcs L%=_last_one" "\n\t" + "L%=_last_zero:" "\n\t" + "strb %[bitmask], [%[reg], #0]" "\n\t" + "movs %[dly], #4" "\n\t" + "L%=_last_delay_T0H:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_last_delay_T0H" "\n\t" + "strb %[bitmask], [%[reg], #4]" "\n\t" + "movs %[dly], #10" "\n\t" + "L%=_last_delay_T0L:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_last_delay_T0L" "\n\t" + "b L%=_repeat" "\n\t" + "L%=_last_one:" "\n\t" + "strb %[bitmask], [%[reg], #0]" "\n\t" + "movs %[dly], #13" "\n\t" + "L%=_last_delay_T1H:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_last_delay_T1H" "\n\t" + "strb %[bitmask], [%[reg], #4]" "\n\t" + "movs %[dly], #1" "\n\t" + "L%=_last_delay_T1L:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_last_delay_T1L" "\n\t" + "nop" "\n\t" + "L%=_repeat:" "\n\t" + "add %[p], #1" "\n\t" + "sub %[num], #1" "\n\t" + "bne L%=_begin" "\n\t" + "L%=_done:" "\n\t" + : [p] "+r" (p), + [pix] "=&r" (pix), + [count] "=&r" (count), + [dly] "=&r" (dly), + [num] "+r" (num) + : [bitmask] "r" (bitmask), + [reg] "r" (reg) + ); +#else +#error "Sorry, only 48 MHz is supported, please set Tools > CPU Speed to 48 MHz" +#endif // F_CPU == 48000000 + +// Begin of support for nRF52 based boards ------------------------- + +#elif defined(NRF52) || defined(NRF52_SERIES) +// [[[Begin of the Neopixel NRF52 EasyDMA implementation +// by the Hackerspace San Salvador]]] +// This technique uses the PWM peripheral on the NRF52. The PWM uses the +// EasyDMA feature included on the chip. This technique loads the duty +// cycle configuration for each cycle when the PWM is enabled. For this +// to work we need to store a 16 bit configuration for each bit of the +// RGB(W) values in the pixel buffer. +// Comparator values for the PWM were hand picked and are guaranteed to +// be 100% organic to preserve freshness and high accuracy. Current +// parameters are: +// * PWM Clock: 16Mhz +// * Minimum step time: 62.5ns +// * Time for zero in high (T0H): 0.31ms +// * Time for one in high (T1H): 0.75ms +// * Cycle time: 1.25us +// * Frequency: 800Khz +// For 400Khz we just double the calculated times. +// ---------- BEGIN Constants for the EasyDMA implementation ----------- +// The PWM starts the duty cycle in LOW. To start with HIGH we +// need to set the 15th bit on each register. + +// WS2812 (rev A) timing is 0.35 and 0.7us +//#define MAGIC_T0H 5UL | (0x8000) // 0.3125us +//#define MAGIC_T1H 12UL | (0x8000) // 0.75us + +// WS2812B (rev B) timing is 0.4 and 0.8 us +#define MAGIC_T0H 6UL | (0x8000) // 0.375us +#define MAGIC_T1H 13UL | (0x8000) // 0.8125us + +// WS2811 (400 khz) timing is 0.5 and 1.2 +#define MAGIC_T0H_400KHz 8UL | (0x8000) // 0.5us +#define MAGIC_T1H_400KHz 19UL | (0x8000) // 1.1875us + +// For 400Khz, we double value of CTOPVAL +#define CTOPVAL 20UL // 1.25us +#define CTOPVAL_400KHz 40UL // 2.5us + +// ---------- END Constants for the EasyDMA implementation ------------- +// +// If there is no device available an alternative cycle-counter +// implementation is tried. +// The nRF52 runs with a fixed clock of 64Mhz. The alternative +// implementation is the same as the one used for the Teensy 3.0/1/2 but +// with the Nordic SDK HAL & registers syntax. +// The number of cycles was hand picked and is guaranteed to be 100% +// organic to preserve freshness and high accuracy. +// ---------- BEGIN Constants for cycle counter implementation --------- +#define CYCLES_800_T0H 18 // ~0.36 uS +#define CYCLES_800_T1H 41 // ~0.76 uS +#define CYCLES_800 71 // ~1.25 uS + +#define CYCLES_400_T0H 26 // ~0.50 uS +#define CYCLES_400_T1H 70 // ~1.26 uS +#define CYCLES_400 156 // ~2.50 uS +// ---------- END of Constants for cycle counter implementation -------- + + // To support both the SoftDevice + Neopixels we use the EasyDMA + // feature from the NRF25. However this technique implies to + // generate a pattern and store it on the memory. The actual + // memory used in bytes corresponds to the following formula: + // totalMem = numBytes*8*2+(2*2) + // The two additional bytes at the end are needed to reset the + // sequence. + // + // If there is not enough memory, we will fall back to cycle counter + // using DWT + uint32_t pattern_size = numBytes*8*sizeof(uint16_t)+2*sizeof(uint16_t); + uint16_t* pixels_pattern = NULL; + + NRF_PWM_Type* pwm = NULL; + + // Try to find a free PWM device, which is not enabled + // and has no connected pins + NRF_PWM_Type* PWM[] = { + NRF_PWM0, NRF_PWM1, NRF_PWM2 +#if defined(NRF_PWM3) + ,NRF_PWM3 +#endif + }; + + for(unsigned int device = 0; device < (sizeof(PWM)/sizeof(PWM[0])); device++) { + if( (PWM[device]->ENABLE == 0) && + (PWM[device]->PSEL.OUT[0] & PWM_PSEL_OUT_CONNECT_Msk) && + (PWM[device]->PSEL.OUT[1] & PWM_PSEL_OUT_CONNECT_Msk) && + (PWM[device]->PSEL.OUT[2] & PWM_PSEL_OUT_CONNECT_Msk) && + (PWM[device]->PSEL.OUT[3] & PWM_PSEL_OUT_CONNECT_Msk) + ) { + pwm = PWM[device]; + break; + } + } + + // only malloc if there is PWM device available + if ( pwm != NULL ) { + #if defined(ARDUINO_NRF52_ADAFRUIT) // use thread-safe malloc + pixels_pattern = (uint16_t *) rtos_malloc(pattern_size); + #else + pixels_pattern = (uint16_t *) malloc(pattern_size); + #endif + } + + // Use the identified device to choose the implementation + // If a PWM device is available use DMA + if( (pixels_pattern != NULL) && (pwm != NULL) ) { + uint16_t pos = 0; // bit position + + for(uint16_t n=0; n0; mask >>= 1) { + #if defined(NEO_KHZ400) + if( !is800KHz ) { + pixels_pattern[pos] = (pix & mask) ? MAGIC_T1H_400KHz : MAGIC_T0H_400KHz; + }else + #endif + { + pixels_pattern[pos] = (pix & mask) ? MAGIC_T1H : MAGIC_T0H; + } + + pos++; + } + } + + // Zero padding to indicate the end of que sequence + pixels_pattern[pos++] = 0 | (0x8000); // Seq end + pixels_pattern[pos++] = 0 | (0x8000); // Seq end + + // Set the wave mode to count UP + pwm->MODE = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos); + + // Set the PWM to use the 16MHz clock + pwm->PRESCALER = (PWM_PRESCALER_PRESCALER_DIV_1 << PWM_PRESCALER_PRESCALER_Pos); + + // Setting of the maximum count + // but keeping it on 16Mhz allows for more granularity just + // in case someone wants to do more fine-tuning of the timing. +#if defined(NEO_KHZ400) + if( !is800KHz ) { + pwm->COUNTERTOP = (CTOPVAL_400KHz << PWM_COUNTERTOP_COUNTERTOP_Pos); + }else +#endif + { + pwm->COUNTERTOP = (CTOPVAL << PWM_COUNTERTOP_COUNTERTOP_Pos); + } + + // Disable loops, we want the sequence to repeat only once + pwm->LOOP = (PWM_LOOP_CNT_Disabled << PWM_LOOP_CNT_Pos); + + // On the "Common" setting the PWM uses the same pattern for the + // for supported sequences. The pattern is stored on half-word + // of 16bits + pwm->DECODER = (PWM_DECODER_LOAD_Common << PWM_DECODER_LOAD_Pos) | + (PWM_DECODER_MODE_RefreshCount << PWM_DECODER_MODE_Pos); + + // Pointer to the memory storing the patter + pwm->SEQ[0].PTR = (uint32_t)(pixels_pattern) << PWM_SEQ_PTR_PTR_Pos; + + // Calculation of the number of steps loaded from memory. + pwm->SEQ[0].CNT = (pattern_size/sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos; + + // The following settings are ignored with the current config. + pwm->SEQ[0].REFRESH = 0; + pwm->SEQ[0].ENDDELAY = 0; + + // The Neopixel implementation is a blocking algorithm. DMA + // allows for non-blocking operation. To "simulate" a blocking + // operation we enable the interruption for the end of sequence + // and block the execution thread until the event flag is set by + // the peripheral. +// pwm->INTEN |= (PWM_INTEN_SEQEND0_Enabled<PSEL.OUT[0] = g_APinDescription[pin].name; + #else + pwm->PSEL.OUT[0] = g_ADigitalPinMap[pin]; + #endif + + // Enable the PWM + pwm->ENABLE = 1; + + // After all of this and many hours of reading the documentation + // we are ready to start the sequence... + pwm->EVENTS_SEQEND[0] = 0; + pwm->TASKS_SEQSTART[0] = 1; + + // But we have to wait for the flag to be set. + while(!pwm->EVENTS_SEQEND[0]) + { + #if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_NRF52840) + yield(); + #endif + } + + // Before leave we clear the flag for the event. + pwm->EVENTS_SEQEND[0] = 0; + + // We need to disable the device and disconnect + // all the outputs before leave or the device will not + // be selected on the next call. + // TODO: Check if disabling the device causes performance issues. + pwm->ENABLE = 0; + + pwm->PSEL.OUT[0] = 0xFFFFFFFFUL; + + #if defined(ARDUINO_NRF52_ADAFRUIT) // use thread-safe free + rtos_free(pixels_pattern); + #else + free(pixels_pattern); + #endif + }// End of DMA implementation + // --------------------------------------------------------------------- + else{ +#ifndef ARDUINO_ARCH_NRF52840 + // Fall back to DWT + #if defined(ARDUINO_NRF52_ADAFRUIT) + // Bluefruit Feather 52 uses freeRTOS + // Critical Section is used since it does not block SoftDevice execution + taskENTER_CRITICAL(); + #elif defined(NRF52_DISABLE_INT) + // If you are using the Bluetooth SoftDevice we advise you to not disable + // the interrupts. Disabling the interrupts even for short periods of time + // causes the SoftDevice to stop working. + // Disable the interrupts only in cases where you need high performance for + // the LEDs and if you are not using the EasyDMA feature. + __disable_irq(); + #endif + + NRF_GPIO_Type* nrf_port = (NRF_GPIO_Type*) digitalPinToPort(pin); + uint32_t pinMask = digitalPinToBitMask(pin); + + uint32_t CYCLES_X00 = CYCLES_800; + uint32_t CYCLES_X00_T1H = CYCLES_800_T1H; + uint32_t CYCLES_X00_T0H = CYCLES_800_T0H; + +#if defined(NEO_KHZ400) + if( !is800KHz ) + { + CYCLES_X00 = CYCLES_400; + CYCLES_X00_T1H = CYCLES_400_T1H; + CYCLES_X00_T0H = CYCLES_400_T0H; + } +#endif + + // Enable DWT in debug core + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + + // Tries to re-send the frame if is interrupted by the SoftDevice. + while(1) { + uint8_t *p = pixels; + + uint32_t cycStart = DWT->CYCCNT; + uint32_t cyc = 0; + + for(uint16_t n=0; n>= 1) { + while(DWT->CYCCNT - cyc < CYCLES_X00); + cyc = DWT->CYCCNT; + + nrf_port->OUTSET |= pinMask; + + if(pix & mask) { + while(DWT->CYCCNT - cyc < CYCLES_X00_T1H); + } else { + while(DWT->CYCCNT - cyc < CYCLES_X00_T0H); + } + + nrf_port->OUTCLR |= pinMask; + } + } + while(DWT->CYCCNT - cyc < CYCLES_X00); + + + // If total time longer than 25%, resend the whole data. + // Since we are likely to be interrupted by SoftDevice + if ( (DWT->CYCCNT - cycStart) < ( 8*numBytes*((CYCLES_X00*5)/4) ) ) { + break; + } + + // re-send need 300us delay + delayMicroseconds(300); + } + + // Enable interrupts again + #if defined(ARDUINO_NRF52_ADAFRUIT) + taskEXIT_CRITICAL(); + #elif defined(NRF52_DISABLE_INT) + __enable_irq(); + #endif +#endif + } +// END of NRF52 implementation + +#elif defined (__SAMD21E17A__) || defined(__SAMD21G18A__) || defined(__SAMD21E18A__) || defined(__SAMD21J18A__) // Arduino Zero, Gemma/Trinket M0, SODAQ Autonomo and others + // Tried this with a timer/counter, couldn't quite get adequate + // resolution. So yay, you get a load of goofball NOPs... + + uint8_t *ptr, *end, p, bitMask, portNum; + uint32_t pinMask; + + portNum = g_APinDescription[pin].ulPort; + pinMask = 1ul << g_APinDescription[pin].ulPin; + ptr = pixels; + end = ptr + numBytes; + p = *ptr++; + bitMask = 0x80; + + volatile uint32_t *set = &(PORT->Group[portNum].OUTSET.reg), + *clr = &(PORT->Group[portNum].OUTCLR.reg); + +#if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled + if(is800KHz) { +#endif + for(;;) { + *set = pinMask; + asm("nop; nop; nop; nop; nop; nop; nop; nop;"); + if(p & bitMask) { + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop;"); + *clr = pinMask; + } else { + *clr = pinMask; + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop;"); + } + if(bitMask >>= 1) { + asm("nop; nop; nop; nop; nop; nop; nop; nop; nop;"); + } else { + if(ptr >= end) break; + p = *ptr++; + bitMask = 0x80; + } + } +#if defined(NEO_KHZ400) + } else { // 400 KHz bitstream + for(;;) { + *set = pinMask; + asm("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;"); + if(p & bitMask) { + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop;"); + *clr = pinMask; + } else { + *clr = pinMask; + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop;"); + } + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;"); + if(bitMask >>= 1) { + asm("nop; nop; nop; nop; nop; nop; nop;"); + } else { + if(ptr >= end) break; + p = *ptr++; + bitMask = 0x80; + } + } + } +#endif + +#elif defined (__SAMD51__) // M4 + + uint8_t *ptr, *end, p, bitMask, portNum, bit; + uint32_t pinMask; + + portNum = g_APinDescription[pin].ulPort; + pinMask = 1ul << g_APinDescription[pin].ulPin; + ptr = pixels; + end = ptr + numBytes; + p = *ptr++; + bitMask = 0x80; + + volatile uint32_t *set = &(PORT->Group[portNum].OUTSET.reg), + *clr = &(PORT->Group[portNum].OUTCLR.reg); + + // SAMD51 overclock-compatible timing is only a mild abomination. + // It uses SysTick for a consistent clock reference regardless of + // optimization / cache settings. That's the good news. The bad news, + // since SysTick->VAL is a volatile type it's slow to access...and then, + // with the SysTick interval that Arduino sets up (1 ms), this would + // require a subtract and MOD operation for gauging elapsed time, and + // all taken in combination that lacks adequate temporal resolution + // for NeoPixel timing. So a kind of horrible thing is done here... + // since interrupts are turned off anyway and it's generally accepted + // by now that we're gonna lose track of time in the NeoPixel lib, + // the SysTick timer is reconfigured for a period matching the NeoPixel + // bit timing (either 800 or 400 KHz) and we watch SysTick->VAL very + // closely (just a threshold, no subtract or MOD or anything) and that + // seems to work just well enough. When finished, the SysTick + // peripheral is set back to its original state. + + uint32_t t0, t1, top, ticks, + saveLoad = SysTick->LOAD, saveVal = SysTick->VAL; + +#if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled + if(is800KHz) { +#endif + top = (uint32_t)(F_CPU * 0.00000125); // Bit hi + lo = 1.25 uS + t0 = top - (uint32_t)(F_CPU * 0.00000040); // 0 = 0.4 uS hi + t1 = top - (uint32_t)(F_CPU * 0.00000080); // 1 = 0.8 uS hi +#if defined(NEO_KHZ400) + } else { // 400 KHz bitstream + top = (uint32_t)(F_CPU * 0.00000250); // Bit hi + lo = 2.5 uS + t0 = top - (uint32_t)(F_CPU * 0.00000050); // 0 = 0.5 uS hi + t1 = top - (uint32_t)(F_CPU * 0.00000120); // 1 = 1.2 uS hi + } +#endif + + SysTick->LOAD = top; // Config SysTick for NeoPixel bit freq + SysTick->VAL = top; // Set to start value (counts down) + (void)SysTick->VAL; // Dummy read helps sync up 1st bit + + for(;;) { + *set = pinMask; // Set output high + ticks = (p & bitMask) ? t1 : t0; // SysTick threshold, + while(SysTick->VAL > ticks); // wait for it + *clr = pinMask; // Set output low + if(!(bitMask >>= 1)) { // Next bit for this byte...done? + if(ptr >= end) break; // If last byte sent, exit loop + p = *ptr++; // Fetch next byte + bitMask = 0x80; // Reset bitmask + } + while(SysTick->VAL <= ticks); // Wait for rollover to 'top' + } + + SysTick->LOAD = saveLoad; // Restore SysTick rollover to 1 ms + SysTick->VAL = saveVal; // Restore SysTick value + +#elif defined (ARDUINO_STM32_FEATHER) // FEATHER WICED (120MHz) + + // Tried this with a timer/counter, couldn't quite get adequate + // resolution. So yay, you get a load of goofball NOPs... + + uint8_t *ptr, *end, p, bitMask; + uint32_t pinMask; + + pinMask = BIT(PIN_MAP[pin].gpio_bit); + ptr = pixels; + end = ptr + numBytes; + p = *ptr++; + bitMask = 0x80; + + volatile uint16_t *set = &(PIN_MAP[pin].gpio_device->regs->BSRRL); + volatile uint16_t *clr = &(PIN_MAP[pin].gpio_device->regs->BSRRH); + +#if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled + if(is800KHz) { +#endif + for(;;) { + if(p & bitMask) { // ONE + // High 800ns + *set = pinMask; + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop;"); + // Low 450ns + *clr = pinMask; + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop;"); + } else { // ZERO + // High 400ns + *set = pinMask; + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop;"); + // Low 850ns + *clr = pinMask; + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop;"); + } + if(bitMask >>= 1) { + // Move on to the next pixel + asm("nop;"); + } else { + if(ptr >= end) break; + p = *ptr++; + bitMask = 0x80; + } + } +#if defined(NEO_KHZ400) + } else { // 400 KHz bitstream + // ToDo! + } +#endif + +#elif defined(TARGET_LPC1768) + uint8_t *ptr, *end, p, bitMask; + ptr = pixels; + end = ptr + numBytes; + p = *ptr++; + bitMask = 0x80; + +#if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled + if(is800KHz) { +#endif + for(;;) { + if(p & bitMask) { + // data ONE high + // min: 550 typ: 700 max: 5,500 + gpio_set(pin); + time::delay_ns(550); + // min: 450 typ: 600 max: 5,000 + gpio_clear(pin); + time::delay_ns(450); + } else { + // data ZERO high + // min: 200 typ: 350 max: 500 + gpio_set(pin); + time::delay_ns(200); + // data low + // min: 450 typ: 600 max: 5,000 + gpio_clear(pin); + time::delay_ns(450); + } + if(bitMask >>= 1) { + // Move on to the next pixel + asm("nop;"); + } else { + if(ptr >= end) break; + p = *ptr++; + bitMask = 0x80; + } + } +#if defined(NEO_KHZ400) + } else { // 400 KHz bitstream + // ToDo! + } +#endif +#elif defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_ARDUINO_CORE_STM32) + uint8_t *p = pixels, *end = p + numBytes, + pix = *p++, mask = 0x80; + uint32_t cyc; + uint32_t saveLoad = SysTick->LOAD, saveVal = SysTick->VAL; +#if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled + if(is800KHz) { +#endif + uint32_t top = (F_CPU / 800000); // 1.25µs + uint32_t t0 = top - (F_CPU / 2500000); // 0.4µs + uint32_t t1 = top - (F_CPU / 1250000); // 0.8µs + SysTick->LOAD = top - 1; // Config SysTick for NeoPixel bit freq + SysTick->VAL = 0; // Set to start value + for(;;) { + LL_GPIO_SetOutputPin(gpioPort, gpioPin); + cyc = (pix & mask) ? t1 : t0; + while(SysTick->VAL > cyc); + LL_GPIO_ResetOutputPin(gpioPort, gpioPin); + if(!(mask >>= 1)) { + if(p >= end) break; + pix = *p++; + mask = 0x80; + } + while(SysTick->VAL <= cyc); + } +#if defined(NEO_KHZ400) + } else { // 400 kHz bitstream + uint32_t top = (F_CPU / 400000); // 2.5µs + uint32_t t0 = top - (F_CPU / 2000000); // 0.5µs + uint32_t t1 = top - (F_CPU / 833333); // 1.2µs + SysTick->LOAD = top - 1; // Config SysTick for NeoPixel bit freq + SysTick->VAL = 0; // Set to start value + for(;;) { + LL_GPIO_SetOutputPin(gpioPort, gpioPin); + cyc = (pix & mask) ? t1 : t0; + while(SysTick->VAL > cyc); + LL_GPIO_ResetOutputPin(gpioPort, gpioPin); + if(!(mask >>= 1)) { + if(p >= end) break; + pix = *p++; + mask = 0x80; + } + while(SysTick->VAL <= cyc); + } + } +#endif // NEO_KHZ400 + SysTick->LOAD = saveLoad; // Restore SysTick rollover to 1 ms + SysTick->VAL = saveVal; // Restore SysTick value +#elif defined (NRF51) + uint8_t *p = pixels, + pix, count, mask; + int32_t num = numBytes; + unsigned int bitmask = ( 1 << g_ADigitalPinMap[pin] ); +// https://github.com/sandeepmistry/arduino-nRF5/blob/dc53980c8bac27898fca90d8ecb268e11111edc1/variants/BBCmicrobit/variant.cpp + + volatile unsigned int *reg = (unsigned int *) (0x50000000UL + 0x508); + +// https://github.com/sandeepmistry/arduino-nRF5/blob/dc53980c8bac27898fca90d8ecb268e11111edc1/cores/nRF5/SDK/components/device/nrf51.h +// http://www.iot-programmer.com/index.php/books/27-micro-bit-iot-in-c/chapters-micro-bit-iot-in-c/47-micro-bit-iot-in-c-fast-memory-mapped-gpio?showall=1 +// https://github.com/Microsoft/pxt-neopixel/blob/master/sendbuffer.asm + + asm volatile( + // "cpsid i" ; disable irq + + // b .start + "b L%=_start" "\n\t" + // .nextbit: ; C0 + "L%=_nextbit:" "\n\t" //; C0 + // str r1, [r3, #0] ; pin := hi C2 + "strb %[bitmask], [%[reg], #0]" "\n\t" //; pin := hi C2 + // tst r6, r0 ; C3 + "tst %[mask], %[pix]" "\n\t"// ; C3 + // bne .islate ; C4 + "bne L%=_islate" "\n\t" //; C4 + // str r1, [r2, #0] ; pin := lo C6 + "strb %[bitmask], [%[reg], #4]" "\n\t" //; pin := lo C6 + // .islate: + "L%=_islate:" "\n\t" + // lsrs r6, r6, #1 ; r6 >>= 1 C7 + "lsr %[mask], %[mask], #1" "\n\t" //; r6 >>= 1 C7 + // bne .justbit ; C8 + "bne L%=_justbit" "\n\t" //; C8 + + // ; not just a bit - need new byte + // adds r4, #1 ; r4++ C9 + "add %[p], #1" "\n\t" //; r4++ C9 + // subs r5, #1 ; r5-- C10 + "sub %[num], #1" "\n\t" //; r5-- C10 + // bcc .stop ; if (r5<0) goto .stop C11 + "bcc L%=_stop" "\n\t" //; if (r5<0) goto .stop C11 + // .start: + "L%=_start:" + // movs r6, #0x80 ; reset mask C12 + "movs %[mask], #0x80" "\n\t" //; reset mask C12 + // nop ; C13 + "nop" "\n\t" //; C13 + + // .common: ; C13 + "L%=_common:" "\n\t" //; C13 + // str r1, [r2, #0] ; pin := lo C15 + "strb %[bitmask], [%[reg], #4]" "\n\t" //; pin := lo C15 + // ; always re-load byte - it just fits with the cycles better this way + // ldrb r0, [r4, #0] ; r0 := *r4 C17 + "ldrb %[pix], [%[p], #0]" "\n\t" //; r0 := *r4 C17 + // b .nextbit ; C20 + "b L%=_nextbit" "\n\t" //; C20 + + // .justbit: ; C10 + "L%=_justbit:" "\n\t" //; C10 + // ; no nops, branch taken is already 3 cycles + // b .common ; C13 + "b L%=_common" "\n\t" //; C13 + + // .stop: + "L%=_stop:" "\n\t" + // str r1, [r2, #0] ; pin := lo + "strb %[bitmask], [%[reg], #4]" "\n\t" //; pin := lo + // cpsie i ; enable irq + + : [p] "+r" (p), + [pix] "=&r" (pix), + [count] "=&r" (count), + [mask] "=&r" (mask), + [num] "+r" (num) + : [bitmask] "r" (bitmask), + [reg] "r" (reg) + ); + +#elif defined(__SAM3X8E__) // Arduino Due + + #define SCALE VARIANT_MCK / 2UL / 1000000UL + #define INST (2UL * F_CPU / VARIANT_MCK) + #define TIME_800_0 ((int)(0.40 * SCALE + 0.5) - (5 * INST)) + #define TIME_800_1 ((int)(0.80 * SCALE + 0.5) - (5 * INST)) + #define PERIOD_800 ((int)(1.25 * SCALE + 0.5) - (5 * INST)) + #define TIME_400_0 ((int)(0.50 * SCALE + 0.5) - (5 * INST)) + #define TIME_400_1 ((int)(1.20 * SCALE + 0.5) - (5 * INST)) + #define PERIOD_400 ((int)(2.50 * SCALE + 0.5) - (5 * INST)) + + int pinMask, time0, time1, period, t; + Pio *port; + volatile WoReg *portSet, *portClear, *timeValue, *timeReset; + uint8_t *p, *end, pix, mask; + + pmc_set_writeprotect(false); + pmc_enable_periph_clk((uint32_t)TC3_IRQn); + TC_Configure(TC1, 0, + TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK1); + TC_Start(TC1, 0); + + pinMask = g_APinDescription[pin].ulPin; // Don't 'optimize' these into + port = g_APinDescription[pin].pPort; // declarations above. Want to + portSet = &(port->PIO_SODR); // burn a few cycles after + portClear = &(port->PIO_CODR); // starting timer to minimize + timeValue = &(TC1->TC_CHANNEL[0].TC_CV); // the initial 'while'. + timeReset = &(TC1->TC_CHANNEL[0].TC_CCR); + p = pixels; + end = p + numBytes; + pix = *p++; + mask = 0x80; + +#if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled + if(is800KHz) { +#endif + time0 = TIME_800_0; + time1 = TIME_800_1; + period = PERIOD_800; +#if defined(NEO_KHZ400) + } else { // 400 KHz bitstream + time0 = TIME_400_0; + time1 = TIME_400_1; + period = PERIOD_400; + } +#endif + + for(t = time0;; t = time0) { + if(pix & mask) t = time1; + while(*timeValue < (unsigned)period); + *portSet = pinMask; + *timeReset = TC_CCR_CLKEN | TC_CCR_SWTRG; + while(*timeValue < (unsigned)t); + *portClear = pinMask; + if(!(mask >>= 1)) { // This 'inside-out' loop logic utilizes + if(p >= end) break; // idle time to minimize inter-byte delays. + pix = *p++; + mask = 0x80; + } + } + while(*timeValue < (unsigned)period); // Wait for last bit + TC_Stop(TC1, 0); + +#endif // end Due + +// END ARM ---------------------------------------------------------------- + + +#elif defined(ESP8266) || defined(ESP32) + +// ESP8266 ---------------------------------------------------------------- + + // ESP8266 show() is external to enforce ICACHE_RAM_ATTR execution + espShow(pin, pixels, numBytes, is800KHz); + +#elif defined(__ARDUINO_ARC__) + +// Arduino 101 ----------------------------------------------------------- + +#define NOPx7 { __builtin_arc_nop(); \ + __builtin_arc_nop(); __builtin_arc_nop(); \ + __builtin_arc_nop(); __builtin_arc_nop(); \ + __builtin_arc_nop(); __builtin_arc_nop(); } + + PinDescription *pindesc = &g_APinDescription[pin]; + register uint32_t loop = 8 * numBytes; // one loop to handle all bytes and all bits + register uint8_t *p = pixels; + register uint32_t currByte = (uint32_t) (*p); + register uint32_t currBit = 0x80 & currByte; + register uint32_t bitCounter = 0; + register uint32_t first = 1; + + // The loop is unusual. Very first iteration puts all the way LOW to the wire - + // constant LOW does not affect NEOPIXEL, so there is no visible effect displayed. + // During that very first iteration CPU caches instructions in the loop. + // Because of the caching process, "CPU slows down". NEOPIXEL pulse is very time sensitive + // that's why we let the CPU cache first and we start regular pulse from 2nd iteration + if (pindesc->ulGPIOType == SS_GPIO) { + register uint32_t reg = pindesc->ulGPIOBase + SS_GPIO_SWPORTA_DR; + uint32_t reg_val = __builtin_arc_lr((volatile uint32_t)reg); + register uint32_t reg_bit_high = reg_val | (1 << pindesc->ulGPIOId); + register uint32_t reg_bit_low = reg_val & ~(1 << pindesc->ulGPIOId); + + loop += 1; // include first, special iteration + while(loop--) { + if(!first) { + currByte <<= 1; + bitCounter++; + } + + // 1 is >550ns high and >450ns low; 0 is 200..500ns high and >450ns low + __builtin_arc_sr(first ? reg_bit_low : reg_bit_high, (volatile uint32_t)reg); + if(currBit) { // ~400ns HIGH (740ns overall) + NOPx7 + NOPx7 + } + // ~340ns HIGH + NOPx7 + __builtin_arc_nop(); + + // 820ns LOW; per spec, max allowed low here is 5000ns */ + __builtin_arc_sr(reg_bit_low, (volatile uint32_t)reg); + NOPx7 + NOPx7 + + if(bitCounter >= 8) { + bitCounter = 0; + currByte = (uint32_t) (*++p); + } + + currBit = 0x80 & currByte; + first = 0; + } + } else if(pindesc->ulGPIOType == SOC_GPIO) { + register uint32_t reg = pindesc->ulGPIOBase + SOC_GPIO_SWPORTA_DR; + uint32_t reg_val = MMIO_REG_VAL(reg); + register uint32_t reg_bit_high = reg_val | (1 << pindesc->ulGPIOId); + register uint32_t reg_bit_low = reg_val & ~(1 << pindesc->ulGPIOId); + + loop += 1; // include first, special iteration + while(loop--) { + if(!first) { + currByte <<= 1; + bitCounter++; + } + MMIO_REG_VAL(reg) = first ? reg_bit_low : reg_bit_high; + if(currBit) { // ~430ns HIGH (740ns overall) + NOPx7 + NOPx7 + __builtin_arc_nop(); + } + // ~310ns HIGH + NOPx7 + + // 850ns LOW; per spec, max allowed low here is 5000ns */ + MMIO_REG_VAL(reg) = reg_bit_low; + NOPx7 + NOPx7 + + if(bitCounter >= 8) { + bitCounter = 0; + currByte = (uint32_t) (*++p); + } + + currBit = 0x80 & currByte; + first = 0; + } + } + +#else +#error Architecture not supported +#endif + + +// END ARCHITECTURE SELECT ------------------------------------------------ + +#if !( defined(NRF52) || defined(NRF52_SERIES) ) + interrupts(); +#endif + + endTime = micros(); // Save EOD time for latch on next call +} + +/*! + @brief Set/change the NeoPixel output pin number. Previous pin, + if any, is set to INPUT and the new pin is set to OUTPUT. + @param p Arduino pin number (-1 = no pin). +*/ +void Adafruit_NeoPixel::setPin(uint16_t p) { + if(begun && (pin >= 0)) pinMode(pin, INPUT); + pin = p; + if(begun) { + pinMode(p, OUTPUT); + digitalWrite(p, LOW); + } +#if defined(__AVR__) + port = portOutputRegister(digitalPinToPort(p)); + pinMask = digitalPinToBitMask(p); +#endif +#if defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_ARDUINO_CORE_STM32) + gpioPort = digitalPinToPort(p); + gpioPin = STM_LL_GPIO_PIN(digitalPinToPinName(p)); +#endif +} + +/*! + @brief Set a pixel's color using separate red, green and blue + components. If using RGBW pixels, white will be set to 0. + @param n Pixel index, starting from 0. + @param r Red brightness, 0 = minimum (off), 255 = maximum. + @param g Green brightness, 0 = minimum (off), 255 = maximum. + @param b Blue brightness, 0 = minimum (off), 255 = maximum. +*/ +void Adafruit_NeoPixel::setPixelColor( + uint16_t n, uint8_t r, uint8_t g, uint8_t b) { + + if(n < numLEDs) { + if(brightness) { // See notes in setBrightness() + r = (r * brightness) >> 8; + g = (g * brightness) >> 8; + b = (b * brightness) >> 8; + } + uint8_t *p; + if(wOffset == rOffset) { // Is an RGB-type strip + p = &pixels[n * 3]; // 3 bytes per pixel + } else { // Is a WRGB-type strip + p = &pixels[n * 4]; // 4 bytes per pixel + p[wOffset] = 0; // But only R,G,B passed -- set W to 0 + } + p[rOffset] = r; // R,G,B always stored + p[gOffset] = g; + p[bOffset] = b; + } +} + +/*! + @brief Set a pixel's color using separate red, green, blue and white + components (for RGBW NeoPixels only). + @param n Pixel index, starting from 0. + @param r Red brightness, 0 = minimum (off), 255 = maximum. + @param g Green brightness, 0 = minimum (off), 255 = maximum. + @param b Blue brightness, 0 = minimum (off), 255 = maximum. + @param w White brightness, 0 = minimum (off), 255 = maximum, ignored + if using RGB pixels. +*/ +void Adafruit_NeoPixel::setPixelColor( + uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w) { + + if(n < numLEDs) { + if(brightness) { // See notes in setBrightness() + r = (r * brightness) >> 8; + g = (g * brightness) >> 8; + b = (b * brightness) >> 8; + w = (w * brightness) >> 8; + } + uint8_t *p; + if(wOffset == rOffset) { // Is an RGB-type strip + p = &pixels[n * 3]; // 3 bytes per pixel (ignore W) + } else { // Is a WRGB-type strip + p = &pixels[n * 4]; // 4 bytes per pixel + p[wOffset] = w; // Store W + } + p[rOffset] = r; // Store R,G,B + p[gOffset] = g; + p[bOffset] = b; + } +} + +/*! + @brief Set a pixel's color using a 32-bit 'packed' RGB or RGBW value. + @param n Pixel index, starting from 0. + @param c 32-bit color value. Most significant byte is white (for RGBW + pixels) or ignored (for RGB pixels), next is red, then green, + and least significant byte is blue. +*/ +void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint32_t c) { + if(n < numLEDs) { + uint8_t *p, + r = (uint8_t)(c >> 16), + g = (uint8_t)(c >> 8), + b = (uint8_t)c; + if(brightness) { // See notes in setBrightness() + r = (r * brightness) >> 8; + g = (g * brightness) >> 8; + b = (b * brightness) >> 8; + } + if(wOffset == rOffset) { + p = &pixels[n * 3]; + } else { + p = &pixels[n * 4]; + uint8_t w = (uint8_t)(c >> 24); + p[wOffset] = brightness ? ((w * brightness) >> 8) : w; + } + p[rOffset] = r; + p[gOffset] = g; + p[bOffset] = b; + } +} + +/*! + @brief Fill all or part of the NeoPixel strip with a color. + @param c 32-bit color value. Most significant byte is white (for + RGBW pixels) or ignored (for RGB pixels), next is red, + then green, and least significant byte is blue. If all + arguments are unspecified, this will be 0 (off). + @param first Index of first pixel to fill, starting from 0. Must be + in-bounds, no clipping is performed. 0 if unspecified. + @param count Number of pixels to fill, as a positive value. Passing + 0 or leaving unspecified will fill to end of strip. +*/ +void Adafruit_NeoPixel::fill(uint32_t c, uint16_t first, uint16_t count) { + uint16_t i, end; + + if(first >= numLEDs) { + return; // If first LED is past end of strip, nothing to do + } + + // Calculate the index ONE AFTER the last pixel to fill + if(count == 0) { + // Fill to end of strip + end = numLEDs; + } else { + // Ensure that the loop won't go past the last pixel + end = first + count; + if(end > numLEDs) end = numLEDs; + } + + for(i = first; i < end; i++) { + this->setPixelColor(i, c); + } +} + +/*! + @brief Convert hue, saturation and value into a packed 32-bit RGB color + that can be passed to setPixelColor() or other RGB-compatible + functions. + @param hue An unsigned 16-bit value, 0 to 65535, representing one full + loop of the color wheel, which allows 16-bit hues to "roll + over" while still doing the expected thing (and allowing + more precision than the wheel() function that was common to + prior NeoPixel examples). + @param sat Saturation, 8-bit value, 0 (min or pure grayscale) to 255 + (max or pure hue). Default of 255 if unspecified. + @param val Value (brightness), 8-bit value, 0 (min / black / off) to + 255 (max or full brightness). Default of 255 if unspecified. + @return Packed 32-bit RGB with the most significant byte set to 0 -- the + white element of WRGB pixels is NOT utilized. Result is linearly + but not perceptually correct, so you may want to pass the result + through the gamma32() function (or your own gamma-correction + operation) else colors may appear washed out. This is not done + automatically by this function because coders may desire a more + refined gamma-correction function than the simplified + one-size-fits-all operation of gamma32(). Diffusing the LEDs also + really seems to help when using low-saturation colors. +*/ +uint32_t Adafruit_NeoPixel::ColorHSV(uint16_t hue, uint8_t sat, uint8_t val) { + + uint8_t r, g, b; + + // Remap 0-65535 to 0-1529. Pure red is CENTERED on the 64K rollover; + // 0 is not the start of pure red, but the midpoint...a few values above + // zero and a few below 65536 all yield pure red (similarly, 32768 is the + // midpoint, not start, of pure cyan). The 8-bit RGB hexcone (256 values + // each for red, green, blue) really only allows for 1530 distinct hues + // (not 1536, more on that below), but the full unsigned 16-bit type was + // chosen for hue so that one's code can easily handle a contiguous color + // wheel by allowing hue to roll over in either direction. + hue = (hue * 1530L + 32768) / 65536; + // Because red is centered on the rollover point (the +32768 above, + // essentially a fixed-point +0.5), the above actually yields 0 to 1530, + // where 0 and 1530 would yield the same thing. Rather than apply a + // costly modulo operator, 1530 is handled as a special case below. + + // So you'd think that the color "hexcone" (the thing that ramps from + // pure red, to pure yellow, to pure green and so forth back to red, + // yielding six slices), and with each color component having 256 + // possible values (0-255), might have 1536 possible items (6*256), + // but in reality there's 1530. This is because the last element in + // each 256-element slice is equal to the first element of the next + // slice, and keeping those in there this would create small + // discontinuities in the color wheel. So the last element of each + // slice is dropped...we regard only elements 0-254, with item 255 + // being picked up as element 0 of the next slice. Like this: + // Red to not-quite-pure-yellow is: 255, 0, 0 to 255, 254, 0 + // Pure yellow to not-quite-pure-green is: 255, 255, 0 to 1, 255, 0 + // Pure green to not-quite-pure-cyan is: 0, 255, 0 to 0, 255, 254 + // and so forth. Hence, 1530 distinct hues (0 to 1529), and hence why + // the constants below are not the multiples of 256 you might expect. + + // Convert hue to R,G,B (nested ifs faster than divide+mod+switch): + if(hue < 510) { // Red to Green-1 + b = 0; + if(hue < 255) { // Red to Yellow-1 + r = 255; + g = hue; // g = 0 to 254 + } else { // Yellow to Green-1 + r = 510 - hue; // r = 255 to 1 + g = 255; + } + } else if(hue < 1020) { // Green to Blue-1 + r = 0; + if(hue < 765) { // Green to Cyan-1 + g = 255; + b = hue - 510; // b = 0 to 254 + } else { // Cyan to Blue-1 + g = 1020 - hue; // g = 255 to 1 + b = 255; + } + } else if(hue < 1530) { // Blue to Red-1 + g = 0; + if(hue < 1275) { // Blue to Magenta-1 + r = hue - 1020; // r = 0 to 254 + b = 255; + } else { // Magenta to Red-1 + r = 255; + b = 1530 - hue; // b = 255 to 1 + } + } else { // Last 0.5 Red (quicker than % operator) + r = 255; + g = b = 0; + } + + // Apply saturation and value to R,G,B, pack into 32-bit result: + uint32_t v1 = 1 + val; // 1 to 256; allows >>8 instead of /255 + uint16_t s1 = 1 + sat; // 1 to 256; same reason + uint8_t s2 = 255 - sat; // 255 to 0 + return ((((((r * s1) >> 8) + s2) * v1) & 0xff00) << 8) | + (((((g * s1) >> 8) + s2) * v1) & 0xff00) | + ( ((((b * s1) >> 8) + s2) * v1) >> 8); +} + +/*! + @brief Query the color of a previously-set pixel. + @param n Index of pixel to read (0 = first). + @return 'Packed' 32-bit RGB or WRGB value. Most significant byte is white + (for RGBW pixels) or 0 (for RGB pixels), next is red, then green, + and least significant byte is blue. + @note If the strip brightness has been changed from the default value + of 255, the color read from a pixel may not exactly match what + was previously written with one of the setPixelColor() functions. + This gets more pronounced at lower brightness levels. +*/ +uint32_t Adafruit_NeoPixel::getPixelColor(uint16_t n) const { + if(n >= numLEDs) return 0; // Out of bounds, return no color. + + uint8_t *p; + + if(wOffset == rOffset) { // Is RGB-type device + p = &pixels[n * 3]; + if(brightness) { + // Stored color was decimated by setBrightness(). Returned value + // attempts to scale back to an approximation of the original 24-bit + // value used when setting the pixel color, but there will always be + // some error -- those bits are simply gone. Issue is most + // pronounced at low brightness levels. + return (((uint32_t)(p[rOffset] << 8) / brightness) << 16) | + (((uint32_t)(p[gOffset] << 8) / brightness) << 8) | + ( (uint32_t)(p[bOffset] << 8) / brightness ); + } else { + // No brightness adjustment has been made -- return 'raw' color + return ((uint32_t)p[rOffset] << 16) | + ((uint32_t)p[gOffset] << 8) | + (uint32_t)p[bOffset]; + } + } else { // Is RGBW-type device + p = &pixels[n * 4]; + if(brightness) { // Return scaled color + return (((uint32_t)(p[wOffset] << 8) / brightness) << 24) | + (((uint32_t)(p[rOffset] << 8) / brightness) << 16) | + (((uint32_t)(p[gOffset] << 8) / brightness) << 8) | + ( (uint32_t)(p[bOffset] << 8) / brightness ); + } else { // Return raw color + return ((uint32_t)p[wOffset] << 24) | + ((uint32_t)p[rOffset] << 16) | + ((uint32_t)p[gOffset] << 8) | + (uint32_t)p[bOffset]; + } + } +} + + +/*! + @brief Adjust output brightness. Does not immediately affect what's + currently displayed on the LEDs. The next call to show() will + refresh the LEDs at this level. + @param b Brightness setting, 0=minimum (off), 255=brightest. + @note This was intended for one-time use in one's setup() function, + not as an animation effect in itself. Because of the way this + library "pre-multiplies" LED colors in RAM, changing the + brightness is often a "lossy" operation -- what you write to + pixels isn't necessary the same as what you'll read back. + Repeated brightness changes using this function exacerbate the + problem. Smart programs therefore treat the strip as a + write-only resource, maintaining their own state to render each + frame of an animation, not relying on read-modify-write. +*/ +void Adafruit_NeoPixel::setBrightness(uint8_t b) { + // Stored brightness value is different than what's passed. + // This simplifies the actual scaling math later, allowing a fast + // 8x8-bit multiply and taking the MSB. 'brightness' is a uint8_t, + // adding 1 here may (intentionally) roll over...so 0 = max brightness + // (color values are interpreted literally; no scaling), 1 = min + // brightness (off), 255 = just below max brightness. + uint8_t newBrightness = b + 1; + if(newBrightness != brightness) { // Compare against prior value + // Brightness has changed -- re-scale existing data in RAM, + // This process is potentially "lossy," especially when increasing + // brightness. The tight timing in the WS2811/WS2812 code means there + // aren't enough free cycles to perform this scaling on the fly as data + // is issued. So we make a pass through the existing color data in RAM + // and scale it (subsequent graphics commands also work at this + // brightness level). If there's a significant step up in brightness, + // the limited number of steps (quantization) in the old data will be + // quite visible in the re-scaled version. For a non-destructive + // change, you'll need to re-render the full strip data. C'est la vie. + uint8_t c, + *ptr = pixels, + oldBrightness = brightness - 1; // De-wrap old brightness value + uint16_t scale; + if(oldBrightness == 0) scale = 0; // Avoid /0 + else if(b == 255) scale = 65535 / oldBrightness; + else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness; + for(uint16_t i=0; i> 8; + } + brightness = newBrightness; + } +} + +/*! + @brief Retrieve the last-set brightness value for the strip. + @return Brightness value: 0 = minimum (off), 255 = maximum. +*/ +uint8_t Adafruit_NeoPixel::getBrightness(void) const { + return brightness - 1; +} + +/*! + @brief Fill the whole NeoPixel strip with 0 / black / off. +*/ +void Adafruit_NeoPixel::clear(void) { + memset(pixels, 0, numBytes); +} + +// A 32-bit variant of gamma8() that applies the same function +// to all components of a packed RGB or WRGB value. +uint32_t Adafruit_NeoPixel::gamma32(uint32_t x) { + uint8_t *y = (uint8_t *)&x; + // All four bytes of a 32-bit value are filtered even if RGB (not WRGB), + // to avoid a bunch of shifting and masking that would be necessary for + // properly handling different endianisms (and each byte is a fairly + // trivial operation, so it might not even be wasting cycles vs a check + // and branch for the RGB case). In theory this might cause trouble *if* + // someone's storing information in the unused most significant byte + // of an RGB value, but this seems exceedingly rare and if it's + // encountered in reality they can mask values going in or coming out. + for(uint8_t i=0; i<4; i++) y[i] = gamma8(y[i]); + return x; // Packed 32-bit return +} diff --git a/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.h b/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.h new file mode 100644 index 0000000..955be39 --- /dev/null +++ b/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.h @@ -0,0 +1,366 @@ +/*! + * @file Adafruit_NeoPixel.h + * + * This is part of Adafruit's NeoPixel library for the Arduino platform, + * allowing a broad range of microcontroller boards (most AVR boards, + * many ARM devices, ESP8266 and ESP32, among others) to control Adafruit + * NeoPixels, FLORA RGB Smart Pixels and compatible devices -- WS2811, + * WS2812, WS2812B, SK6812, etc. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing products + * from Adafruit! + * + * Written by Phil "Paint Your Dragon" Burgess for Adafruit Industries, + * with contributions by PJRC, Michael Miller and other members of the + * open source community. + * + * This file is part of the Adafruit_NeoPixel library. + * + * Adafruit_NeoPixel is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * Adafruit_NeoPixel 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with NeoPixel. If not, see + * . + * + */ + +#ifndef ADAFRUIT_NEOPIXEL_H +#define ADAFRUIT_NEOPIXEL_H + +#ifdef ARDUINO + #if (ARDUINO >= 100) + #include + #else + #include + #include + #endif +#endif + +#ifdef TARGET_LPC1768 + #include +#endif + +// The order of primary colors in the NeoPixel data stream can vary among +// device types, manufacturers and even different revisions of the same +// item. The third parameter to the Adafruit_NeoPixel constructor encodes +// the per-pixel byte offsets of the red, green and blue primaries (plus +// white, if present) in the data stream -- the following #defines provide +// an easier-to-use named version for each permutation. e.g. NEO_GRB +// indicates a NeoPixel-compatible device expecting three bytes per pixel, +// with the first byte transmitted containing the green value, second +// containing red and third containing blue. The in-memory representation +// of a chain of NeoPixels is the same as the data-stream order; no +// re-ordering of bytes is required when issuing data to the chain. +// Most of these values won't exist in real-world devices, but it's done +// this way so we're ready for it (also, if using the WS2811 driver IC, +// one might have their pixels set up in any weird permutation). + +// Bits 5,4 of this value are the offset (0-3) from the first byte of a +// pixel to the location of the red color byte. Bits 3,2 are the green +// offset and 1,0 are the blue offset. If it is an RGBW-type device +// (supporting a white primary in addition to R,G,B), bits 7,6 are the +// offset to the white byte...otherwise, bits 7,6 are set to the same value +// as 5,4 (red) to indicate an RGB (not RGBW) device. +// i.e. binary representation: +// 0bWWRRGGBB for RGBW devices +// 0bRRRRGGBB for RGB + +// RGB NeoPixel permutations; white and red offsets are always same +// Offset: W R G B +#define NEO_RGB ((0<<6) | (0<<4) | (1<<2) | (2)) ///< Transmit as R,G,B +#define NEO_RBG ((0<<6) | (0<<4) | (2<<2) | (1)) ///< Transmit as R,B,G +#define NEO_GRB ((1<<6) | (1<<4) | (0<<2) | (2)) ///< Transmit as G,R,B +#define NEO_GBR ((2<<6) | (2<<4) | (0<<2) | (1)) ///< Transmit as G,B,R +#define NEO_BRG ((1<<6) | (1<<4) | (2<<2) | (0)) ///< Transmit as B,R,G +#define NEO_BGR ((2<<6) | (2<<4) | (1<<2) | (0)) ///< Transmit as B,G,R + +// RGBW NeoPixel permutations; all 4 offsets are distinct +// Offset: W R G B +#define NEO_WRGB ((0<<6) | (1<<4) | (2<<2) | (3)) ///< Transmit as W,R,G,B +#define NEO_WRBG ((0<<6) | (1<<4) | (3<<2) | (2)) ///< Transmit as W,R,B,G +#define NEO_WGRB ((0<<6) | (2<<4) | (1<<2) | (3)) ///< Transmit as W,G,R,B +#define NEO_WGBR ((0<<6) | (3<<4) | (1<<2) | (2)) ///< Transmit as W,G,B,R +#define NEO_WBRG ((0<<6) | (2<<4) | (3<<2) | (1)) ///< Transmit as W,B,R,G +#define NEO_WBGR ((0<<6) | (3<<4) | (2<<2) | (1)) ///< Transmit as W,B,G,R + +#define NEO_RWGB ((1<<6) | (0<<4) | (2<<2) | (3)) ///< Transmit as R,W,G,B +#define NEO_RWBG ((1<<6) | (0<<4) | (3<<2) | (2)) ///< Transmit as R,W,B,G +#define NEO_RGWB ((2<<6) | (0<<4) | (1<<2) | (3)) ///< Transmit as R,G,W,B +#define NEO_RGBW ((3<<6) | (0<<4) | (1<<2) | (2)) ///< Transmit as R,G,B,W +#define NEO_RBWG ((2<<6) | (0<<4) | (3<<2) | (1)) ///< Transmit as R,B,W,G +#define NEO_RBGW ((3<<6) | (0<<4) | (2<<2) | (1)) ///< Transmit as R,B,G,W + +#define NEO_GWRB ((1<<6) | (2<<4) | (0<<2) | (3)) ///< Transmit as G,W,R,B +#define NEO_GWBR ((1<<6) | (3<<4) | (0<<2) | (2)) ///< Transmit as G,W,B,R +#define NEO_GRWB ((2<<6) | (1<<4) | (0<<2) | (3)) ///< Transmit as G,R,W,B +#define NEO_GRBW ((3<<6) | (1<<4) | (0<<2) | (2)) ///< Transmit as G,R,B,W +#define NEO_GBWR ((2<<6) | (3<<4) | (0<<2) | (1)) ///< Transmit as G,B,W,R +#define NEO_GBRW ((3<<6) | (2<<4) | (0<<2) | (1)) ///< Transmit as G,B,R,W + +#define NEO_BWRG ((1<<6) | (2<<4) | (3<<2) | (0)) ///< Transmit as B,W,R,G +#define NEO_BWGR ((1<<6) | (3<<4) | (2<<2) | (0)) ///< Transmit as B,W,G,R +#define NEO_BRWG ((2<<6) | (1<<4) | (3<<2) | (0)) ///< Transmit as B,R,W,G +#define NEO_BRGW ((3<<6) | (1<<4) | (2<<2) | (0)) ///< Transmit as B,R,G,W +#define NEO_BGWR ((2<<6) | (3<<4) | (1<<2) | (0)) ///< Transmit as B,G,W,R +#define NEO_BGRW ((3<<6) | (2<<4) | (1<<2) | (0)) ///< Transmit as B,G,R,W + +// Add NEO_KHZ400 to the color order value to indicate a 400 KHz device. +// All but the earliest v1 NeoPixels expect an 800 KHz data stream, this is +// the default if unspecified. Because flash space is very limited on ATtiny +// devices (e.g. Trinket, Gemma), v1 NeoPixels aren't handled by default on +// those chips, though it can be enabled by removing the ifndef/endif below, +// but code will be bigger. Conversely, can disable the NEO_KHZ400 line on +// other MCUs to remove v1 support and save a little space. + +#define NEO_KHZ800 0x0000 ///< 800 KHz data transmission +#ifndef __AVR_ATtiny85__ +#define NEO_KHZ400 0x0100 ///< 400 KHz data transmission +#endif + +// If 400 KHz support is enabled, the third parameter to the constructor +// requires a 16-bit value (in order to select 400 vs 800 KHz speed). +// If only 800 KHz is enabled (as is default on ATtiny), an 8-bit value +// is sufficient to encode pixel color order, saving some space. + +#ifdef NEO_KHZ400 +typedef uint16_t neoPixelType; ///< 3rd arg to Adafruit_NeoPixel constructor +#else +typedef uint8_t neoPixelType; ///< 3rd arg to Adafruit_NeoPixel constructor +#endif + +// These two tables are declared outside the Adafruit_NeoPixel class +// because some boards may require oldschool compilers that don't +// handle the C++11 constexpr keyword. + +/* A PROGMEM (flash mem) table containing 8-bit unsigned sine wave (0-255). + Copy & paste this snippet into a Python REPL to regenerate: +import math +for x in range(256): + print("{:3},".format(int((math.sin(x/128.0*math.pi)+1.0)*127.5+0.5))), + if x&15 == 15: print +*/ +static const uint8_t PROGMEM _NeoPixelSineTable[256] = { + 128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173, + 176,179,182,185,188,190,193,196,198,201,203,206,208,211,213,215, + 218,220,222,224,226,228,230,232,234,235,237,238,240,241,243,244, + 245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255, + 255,255,255,255,254,254,254,253,253,252,251,250,250,249,248,246, + 245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,220, + 218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179, + 176,173,170,167,165,162,158,155,152,149,146,143,140,137,134,131, + 128,124,121,118,115,112,109,106,103,100, 97, 93, 90, 88, 85, 82, + 79, 76, 73, 70, 67, 65, 62, 59, 57, 54, 52, 49, 47, 44, 42, 40, + 37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 15, 14, 12, 11, + 10, 9, 7, 6, 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9, + 10, 11, 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, + 37, 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76, + 79, 82, 85, 88, 90, 93, 97,100,103,106,109,112,115,118,121,124}; + +/* Similar to above, but for an 8-bit gamma-correction table. + Copy & paste this snippet into a Python REPL to regenerate: +import math +gamma=2.6 +for x in range(256): + print("{:3},".format(int(math.pow((x)/255.0,gamma)*255.0+0.5))), + if x&15 == 15: print +*/ +static const uint8_t PROGMEM _NeoPixelGammaTable[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, + 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, + 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, + 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, + 20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 27, 28, 29, 29, + 30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 38, 38, 39, 40, 41, 42, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72, 73, 75, + 76, 77, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 92, 93, 94, 96, + 97, 99,100,102,103,105,106,108,109,111,112,114,115,117,119,120, + 122,124,125,127,129,130,132,134,136,137,139,141,143,145,146,148, + 150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180, + 182,184,186,188,191,193,195,197,199,202,204,206,209,211,213,215, + 218,220,223,225,227,230,232,235,237,240,242,245,247,250,252,255}; + +/*! + @brief Class that stores state and functions for interacting with + Adafruit NeoPixels and compatible devices. +*/ +class Adafruit_NeoPixel { + + public: + + // Constructor: number of LEDs, pin number, LED type + Adafruit_NeoPixel(uint16_t n, uint16_t pin=6, + neoPixelType type=NEO_GRB + NEO_KHZ800); + Adafruit_NeoPixel(void); + ~Adafruit_NeoPixel(); + + void begin(void); + void show(void); + void setPin(uint16_t p); + void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b); + void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, + uint8_t w); + void setPixelColor(uint16_t n, uint32_t c); + void fill(uint32_t c=0, uint16_t first=0, uint16_t count=0); + void setBrightness(uint8_t); + void clear(void); + void updateLength(uint16_t n); + void updateType(neoPixelType t); + /*! + @brief Check whether a call to show() will start sending data + immediately or will 'block' for a required interval. NeoPixels + require a short quiet time (about 300 microseconds) after the + last bit is received before the data 'latches' and new data can + start being received. Usually one's sketch is implicitly using + this time to generate a new frame of animation...but if it + finishes very quickly, this function could be used to see if + there's some idle time available for some low-priority + concurrent task. + @return 1 or true if show() will start sending immediately, 0 or false + if show() would block (meaning some idle time is available). + */ + bool canShow(void) { + if (endTime > micros()) { + endTime = micros(); + } + return (micros() - endTime) >= 300L; + } + /*! + @brief Get a pointer directly to the NeoPixel data buffer in RAM. + Pixel data is stored in a device-native format (a la the NEO_* + constants) and is not translated here. Applications that access + this buffer will need to be aware of the specific data format + and handle colors appropriately. + @return Pointer to NeoPixel buffer (uint8_t* array). + @note This is for high-performance applications where calling + setPixelColor() on every single pixel would be too slow (e.g. + POV or light-painting projects). There is no bounds checking + on the array, creating tremendous potential for mayhem if one + writes past the ends of the buffer. Great power, great + responsibility and all that. + */ + uint8_t *getPixels(void) const { return pixels; }; + uint8_t getBrightness(void) const; + /*! + @brief Retrieve the pin number used for NeoPixel data output. + @return Arduino pin number (-1 if not set). + */ + int16_t getPin(void) const { return pin; }; + /*! + @brief Return the number of pixels in an Adafruit_NeoPixel strip object. + @return Pixel count (0 if not set). + */ + uint16_t numPixels(void) const { return numLEDs; } + uint32_t getPixelColor(uint16_t n) const; + /*! + @brief An 8-bit integer sine wave function, not directly compatible + with standard trigonometric units like radians or degrees. + @param x Input angle, 0-255; 256 would loop back to zero, completing + the circle (equivalent to 360 degrees or 2 pi radians). + One can therefore use an unsigned 8-bit variable and simply + add or subtract, allowing it to overflow/underflow and it + still does the expected contiguous thing. + @return Sine result, 0 to 255, or -128 to +127 if type-converted to + a signed int8_t, but you'll most likely want unsigned as this + output is often used for pixel brightness in animation effects. + */ + static uint8_t sine8(uint8_t x) { + return pgm_read_byte(&_NeoPixelSineTable[x]); // 0-255 in, 0-255 out + } + /*! + @brief An 8-bit gamma-correction function for basic pixel brightness + adjustment. Makes color transitions appear more perceptially + correct. + @param x Input brightness, 0 (minimum or off/black) to 255 (maximum). + @return Gamma-adjusted brightness, can then be passed to one of the + setPixelColor() functions. This uses a fixed gamma correction + exponent of 2.6, which seems reasonably okay for average + NeoPixels in average tasks. If you need finer control you'll + need to provide your own gamma-correction function instead. + */ + static uint8_t gamma8(uint8_t x) { + return pgm_read_byte(&_NeoPixelGammaTable[x]); // 0-255 in, 0-255 out + } + /*! + @brief Convert separate red, green and blue values into a single + "packed" 32-bit RGB color. + @param r Red brightness, 0 to 255. + @param g Green brightness, 0 to 255. + @param b Blue brightness, 0 to 255. + @return 32-bit packed RGB value, which can then be assigned to a + variable for later use or passed to the setPixelColor() + function. Packed RGB format is predictable, regardless of + LED strand color order. + */ + static uint32_t Color(uint8_t r, uint8_t g, uint8_t b) { + return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; + } + /*! + @brief Convert separate red, green, blue and white values into a + single "packed" 32-bit WRGB color. + @param r Red brightness, 0 to 255. + @param g Green brightness, 0 to 255. + @param b Blue brightness, 0 to 255. + @param w White brightness, 0 to 255. + @return 32-bit packed WRGB value, which can then be assigned to a + variable for later use or passed to the setPixelColor() + function. Packed WRGB format is predictable, regardless of + LED strand color order. + */ + static uint32_t Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { + return ((uint32_t)w << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; + } + static uint32_t ColorHSV(uint16_t hue, uint8_t sat=255, uint8_t val=255); + /*! + @brief A gamma-correction function for 32-bit packed RGB or WRGB + colors. Makes color transitions appear more perceptially + correct. + @param x 32-bit packed RGB or WRGB color. + @return Gamma-adjusted packed color, can then be passed in one of the + setPixelColor() functions. Like gamma8(), this uses a fixed + gamma correction exponent of 2.6, which seems reasonably okay + for average NeoPixels in average tasks. If you need finer + control you'll need to provide your own gamma-correction + function instead. + */ + static uint32_t gamma32(uint32_t x); + + protected: + +#ifdef NEO_KHZ400 // If 400 KHz NeoPixel support enabled... + bool is800KHz; ///< true if 800 KHz pixels +#endif + bool begun; ///< true if begin() previously called + uint16_t numLEDs; ///< Number of RGB LEDs in strip + uint16_t numBytes; ///< Size of 'pixels' buffer below + int16_t pin; ///< Output pin number (-1 if not yet set) + uint8_t brightness; ///< Strip brightness 0-255 (stored as +1) + uint8_t *pixels; ///< Holds LED color values (3 or 4 bytes each) + uint8_t rOffset; ///< Red index within each 3- or 4-byte pixel + uint8_t gOffset; ///< Index of green byte + uint8_t bOffset; ///< Index of blue byte + uint8_t wOffset; ///< Index of white (==rOffset if no white) + uint32_t endTime; ///< Latch timing reference +#ifdef __AVR__ + volatile uint8_t *port; ///< Output PORT register + uint8_t pinMask; ///< Output PORT bitmask +#endif +#if defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_ARDUINO_CORE_STM32) + GPIO_TypeDef *gpioPort; ///< Output GPIO PORT + uint32_t gpioPin; ///< Output GPIO PIN +#endif +}; + +#endif // ADAFRUIT_NEOPIXEL_H diff --git a/lib/Adafruit_NeoPixel/CONTRIBUTING.md b/lib/Adafruit_NeoPixel/CONTRIBUTING.md new file mode 100644 index 0000000..aa75389 --- /dev/null +++ b/lib/Adafruit_NeoPixel/CONTRIBUTING.md @@ -0,0 +1,13 @@ +# Contribution Guidelines + +This library is the culmination of the expertise of many members of the open source community who have dedicated their time and hard work. The best way to ask for help or propose a new idea is to [create a new issue](https://github.com/adafruit/Adafruit_NeoPixel/issues/new) while creating a Pull Request with your code changes allows you to share your own innovations with the rest of the community. + +The following are some guidelines to observe when creating issues or PRs: + +- Be friendly; it is important that we can all enjoy a safe space as we are all working on the same project and it is okay for people to have different ideas + +- [Use code blocks](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code); it helps us help you when we can read your code! On that note also refrain from pasting more than 30 lines of code in a post, instead [create a gist](https://gist.github.com/) if you need to share large snippets + +- Use reasonable titles; refrain from using overly long or capitalized titles as they are usually annoying and do little to encourage others to help :smile: + +- Be detailed; refrain from mentioning code problems without sharing your source code and always give information regarding your board and version of the library diff --git a/lib/Adafruit_NeoPixel/COPYING b/lib/Adafruit_NeoPixel/COPYING new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/lib/Adafruit_NeoPixel/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/lib/Adafruit_NeoPixel/README.md b/lib/Adafruit_NeoPixel/README.md new file mode 100644 index 0000000..8c15050 --- /dev/null +++ b/lib/Adafruit_NeoPixel/README.md @@ -0,0 +1,153 @@ +# Adafruit NeoPixel Library [![Build Status](https://github.com/adafruit/Adafruit_NeoPixel/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_NeoPixel/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit_NeoPixel/html/index.html) + +Arduino library for controlling single-wire-based LED pixels and strip such as the [Adafruit 60 LED/meter Digital LED strip][strip], the [Adafruit FLORA RGB Smart Pixel][flora], the [Adafruit Breadboard-friendly RGB Smart Pixel][pixel], the [Adafruit NeoPixel Stick][stick], and the [Adafruit NeoPixel Shield][shield]. + +After downloading, rename folder to 'Adafruit_NeoPixel' and install in Arduino Libraries folder. Restart Arduino IDE, then open File->Sketchbook->Library->Adafruit_NeoPixel->strandtest sketch. + +Compatibility notes: Port A is not supported on any AVR processors at this time + +[flora]: http://adafruit.com/products/1060 +[strip]: http://adafruit.com/products/1138 +[pixel]: http://adafruit.com/products/1312 +[stick]: http://adafruit.com/products/1426 +[shield]: http://adafruit.com/products/1430 + +--- + +## Installation + +### First Method + +![image](https://user-images.githubusercontent.com/36513474/68967967-3e37f480-0803-11ea-91d9-601848c306ee.png) + +1. In the Arduino IDE, navigate to Sketch > Include Library > Manage Libraries +1. Then the Library Manager will open and you will find a list of libraries that are already installed or ready for installation. +1. Then search for Neopixel strip using the search bar. +1. Click on the text area and then select the specific version and install it. + +### Second Method + +1. Navigate to the [Releases page](https://github.com/adafruit/Adafruit_NeoPixel/releases). +1. Download the latest release. +1. Extract the zip file +1. In the Arduino IDE, navigate to Sketch > Include Library > Add .ZIP Library + +## Features + +- ### Simple to use + + Controlling NeoPixels “from scratch” is quite a challenge, so we provide a library letting you focus on the fun and interesting bits. + +- ### Give back + + The library is free; you don’t have to pay for anything. Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! + +- ### Supported Chipsets + + We have included code for the following chips - sometimes these break for exciting reasons that we can't control in which case please open an issue! + + - AVR ATmega and ATtiny (any 8-bit) - 8 MHz, 12 MHz and 16 MHz + - Teensy 3.x and LC + - Arduino Due + - Arduino 101 + - ATSAMD21 (Arduino Zero/M0 and other SAMD21 boards) @ 48 MHz + - ATSAMD51 @ 120 MHz + - Adafruit STM32 Feather @ 120 MHz + - ESP8266 any speed + - ESP32 any speed + - Nordic nRF52 (Adafruit Feather nRF52), nRF51 (micro:bit) + + Check forks for other architectures not listed here! + +- ### GNU Lesser General Public License + + Adafruit_NeoPixel is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +## Functions + +- begin() +- updateLength() +- updateType() +- show() +- delay_ns() +- setPin() +- setPixelColor() +- fill() +- ColorHSV() +- getPixelColor() +- setBrightness() +- getBrightness() +- clear() +- gamma32() + +## Examples + +There are many examples implemented in this library. One of the examples is below. You can find other examples [here](https://github.com/adafruit/Adafruit_NeoPixel/tree/master/examples) + +### Simple + +```Cpp +#include +#ifdef __AVR__ + #include +#endif +#define PIN 6 +#define NUMPIXELS 16 + +Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); +#define DELAYVAL 500 + +void setup() { +#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000) + clock_prescale_set(clock_div_1); +#endif + + pixels.begin(); +} + +void loop() { + pixels.clear(); + + for(int i=0; i +#ifdef ESP8266 +#include +#endif + +static uint32_t _getCycleCount(void) __attribute__((always_inline)); +static inline uint32_t _getCycleCount(void) { + uint32_t ccount; + __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); + return ccount; +} + +#ifdef ESP8266 +void ICACHE_RAM_ATTR espShow( + uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) { +#else +void espShow( + uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) { +#endif + +#define CYCLES_800_T0H (F_CPU / 2500000) // 0.4us +#define CYCLES_800_T1H (F_CPU / 1250000) // 0.8us +#define CYCLES_800 (F_CPU / 800000) // 1.25us per bit +#define CYCLES_400_T0H (F_CPU / 2000000) // 0.5uS +#define CYCLES_400_T1H (F_CPU / 833333) // 1.2us +#define CYCLES_400 (F_CPU / 400000) // 2.5us per bit + + uint8_t *p, *end, pix, mask; + uint32_t t, time0, time1, period, c, startTime; + +#ifdef ESP8266 + uint32_t pinMask; + pinMask = _BV(pin); +#endif + + p = pixels; + end = p + numBytes; + pix = *p++; + mask = 0x80; + startTime = 0; + +#ifdef NEO_KHZ400 + if(is800KHz) { +#endif + time0 = CYCLES_800_T0H; + time1 = CYCLES_800_T1H; + period = CYCLES_800; +#ifdef NEO_KHZ400 + } else { // 400 KHz bitstream + time0 = CYCLES_400_T0H; + time1 = CYCLES_400_T1H; + period = CYCLES_400; + } +#endif + + for(t = time0;; t = time0) { + if(pix & mask) t = time1; // Bit high duration + while(((c = _getCycleCount()) - startTime) < period); // Wait for bit start +#ifdef ESP8266 + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinMask); // Set high +#else + gpio_set_level(pin, HIGH); +#endif + startTime = c; // Save start time + while(((c = _getCycleCount()) - startTime) < t); // Wait high duration +#ifdef ESP8266 + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinMask); // Set low +#else + gpio_set_level(pin, LOW); +#endif + if(!(mask >>= 1)) { // Next bit/byte + if(p >= end) break; + pix = *p++; + mask = 0x80; + } + } + while((_getCycleCount() - startTime) < period); // Wait for last bit +} + +#endif // ESP8266 diff --git a/lib/Adafruit_NeoPixel/examples/RGBWstrandtest/RGBWstrandtest.ino b/lib/Adafruit_NeoPixel/examples/RGBWstrandtest/RGBWstrandtest.ino new file mode 100644 index 0000000..4af26d6 --- /dev/null +++ b/lib/Adafruit_NeoPixel/examples/RGBWstrandtest/RGBWstrandtest.ino @@ -0,0 +1,177 @@ +// NeoPixel test program showing use of the WHITE channel for RGBW +// pixels only (won't look correct on regular RGB NeoPixel strips). + +#include +#ifdef __AVR__ + #include // Required for 16 MHz Adafruit Trinket +#endif + +// Which pin on the Arduino is connected to the NeoPixels? +// On a Trinket or Gemma we suggest changing this to 1: +#define LED_PIN 6 + +// How many NeoPixels are attached to the Arduino? +#define LED_COUNT 60 + +// NeoPixel brightness, 0 (min) to 255 (max) +#define BRIGHTNESS 50 + +// Declare our NeoPixel strip object: +Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRBW + NEO_KHZ800); +// Argument 1 = Number of pixels in NeoPixel strip +// Argument 2 = Arduino pin number (most are valid) +// Argument 3 = Pixel type flags, add together as needed: +// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) +// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) +// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) +// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) +// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products) + +void setup() { + // These lines are specifically to support the Adafruit Trinket 5V 16 MHz. + // Any other board, you can remove this part (but no harm leaving it): +#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000) + clock_prescale_set(clock_div_1); +#endif + // END of Trinket-specific code. + + strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) + strip.show(); // Turn OFF all pixels ASAP + strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255) +} + +void loop() { + // Fill along the length of the strip in various colors... + colorWipe(strip.Color(255, 0, 0) , 50); // Red + colorWipe(strip.Color( 0, 255, 0) , 50); // Green + colorWipe(strip.Color( 0, 0, 255) , 50); // Blue + colorWipe(strip.Color( 0, 0, 0, 255), 50); // True white (not RGB white) + + whiteOverRainbow(75, 5); + + pulseWhite(5); + + rainbowFade2White(3, 3, 1); +} + +// Fill strip pixels one after another with a color. Strip is NOT cleared +// first; anything there will be covered pixel by pixel. Pass in color +// (as a single 'packed' 32-bit value, which you can get by calling +// strip.Color(red, green, blue) as shown in the loop() function above), +// and a delay time (in milliseconds) between pixels. +void colorWipe(uint32_t color, int wait) { + for(int i=0; i= strip.numPixels()) whiteLength = strip.numPixels() - 1; + + int head = whiteLength - 1; + int tail = 0; + int loops = 3; + int loopNum = 0; + uint32_t lastTime = millis(); + uint32_t firstPixelHue = 0; + + for(;;) { // Repeat forever (or until a 'break' or 'return') + for(int i=0; i= tail) && (i <= head)) || // If between head & tail... + ((tail > head) && ((i >= tail) || (i <= head)))) { + strip.setPixelColor(i, strip.Color(0, 0, 0, 255)); // Set white + } else { // else set rainbow + int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels()); + strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue))); + } + } + + strip.show(); // Update strip with new contents + // There's no delay here, it just runs full-tilt until the timer and + // counter combination below runs out. + + firstPixelHue += 40; // Advance just a little along the color wheel + + if((millis() - lastTime) > whiteSpeed) { // Time to update head/tail? + if(++head >= strip.numPixels()) { // Advance head, wrap around + head = 0; + if(++loopNum >= loops) return; + } + if(++tail >= strip.numPixels()) { // Advance tail, wrap around + tail = 0; + } + lastTime = millis(); // Save time of last movement + } + } +} + +void pulseWhite(uint8_t wait) { + for(int j=0; j<256; j++) { // Ramp up from 0 to 255 + // Fill entire strip with white at gamma-corrected brightness level 'j': + strip.fill(strip.Color(0, 0, 0, strip.gamma8(j))); + strip.show(); + delay(wait); + } + + for(int j=255; j>=0; j--) { // Ramp down from 255 to 0 + strip.fill(strip.Color(0, 0, 0, strip.gamma8(j))); + strip.show(); + delay(wait); + } +} + +void rainbowFade2White(int wait, int rainbowLoops, int whiteLoops) { + int fadeVal=0, fadeMax=100; + + // Hue of first pixel runs 'rainbowLoops' complete loops through the color + // wheel. Color wheel has a range of 65536 but it's OK if we roll over, so + // just count from 0 to rainbowLoops*65536, using steps of 256 so we + // advance around the wheel at a decent clip. + for(uint32_t firstPixelHue = 0; firstPixelHue < rainbowLoops*65536; + firstPixelHue += 256) { + + for(int i=0; i= ((rainbowLoops-1) * 65536)) { // Last loop, + if(fadeVal > 0) fadeVal--; // fade out + } else { + fadeVal = fadeMax; // Interim loop, make sure fade is at max + } + } + + for(int k=0; k=0; j--) { // Ramp down 255 to 0 + strip.fill(strip.Color(0, 0, 0, strip.gamma8(j))); + strip.show(); + } + } + + delay(500); // Pause 1/2 second +} diff --git a/lib/Adafruit_NeoPixel/examples/StrandtestArduinoBLE/StrandtestArduinoBLE.ino b/lib/Adafruit_NeoPixel/examples/StrandtestArduinoBLE/StrandtestArduinoBLE.ino new file mode 100644 index 0000000..80e02d2 --- /dev/null +++ b/lib/Adafruit_NeoPixel/examples/StrandtestArduinoBLE/StrandtestArduinoBLE.ino @@ -0,0 +1,231 @@ +/**************************************************************************** + * This example is based on StrandtestBLE example and adapts it to use + * the new ArduinoBLE library. + * + * https://github.com/arduino-libraries/ArduinoBLE + * + * Supported boards: + * Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT, + Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board. + * + * You can use a generic BLE central app, like LightBlue (iOS and Android) or + * nRF Connect (Android), to interact with the services and characteristics + * created in this sketch. + * + * This example code is in the public domain. + * + */ +#include + +#define PIN 15 // Pin where NeoPixels are connected + +// Declare our NeoPixel strip object: +Adafruit_NeoPixel strip(64, PIN, NEO_GRB + NEO_KHZ800); +// Argument 1 = Number of pixels in NeoPixel strip +// Argument 2 = Arduino pin number (most are valid) +// Argument 3 = Pixel type flags, add together as needed: +// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) +// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) +// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) +// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) +// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products) + +// NEOPIXEL BEST PRACTICES for most reliable operation: +// - Add 1000 uF CAPACITOR between NeoPixel strip's + and - connections. +// - MINIMIZE WIRING LENGTH between microcontroller board and first pixel. +// - NeoPixel strip's DATA-IN should pass through a 300-500 OHM RESISTOR. +// - AVOID connecting NeoPixels on a LIVE CIRCUIT. If you must, ALWAYS +// connect GROUND (-) first, then +, then data. +// - When using a 3.3V microcontroller with a 5V-powered NeoPixel strip, +// a LOGIC-LEVEL CONVERTER on the data line is STRONGLY RECOMMENDED. +// (Skipping these may work OK on your workbench but can fail in the field) + +uint8_t rgb_values[3]; + +#include + +BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // BLE LED Service + +// BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central +BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite); + +void setup() +{ + Serial.begin(115200); + Serial.println("Hello World!"); + + // custom services and characteristics can be added as well + // begin initialization + if (!BLE.begin()) + { + Serial.println("starting BLE failed!"); + + while (1) + ; + } + + Serial.print("Peripheral address: "); + Serial.println(BLE.address()); + + // set advertised local name and service UUID: + BLE.setLocalName("LED"); + BLE.setAdvertisedService(ledService); + + // add the characteristic to the service + ledService.addCharacteristic(switchCharacteristic); + + // add service + BLE.addService(ledService); + + // set the initial value for the characeristic: + switchCharacteristic.writeValue(0); + + // start advertising + BLE.advertise(); + + strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) + strip.show(); // Turn OFF all pixels ASAP + + pinMode(PIN, OUTPUT); + digitalWrite(PIN, LOW); + +} + +void loop() +{ + BLEDevice central = BLE.central(); + + // if a central is connected to peripheral: + if (central) + { + Serial.print("Connected to central: "); + // print the central's MAC address: + Serial.println(central.address()); + + // while the central is still connected to peripheral: + while (central.connected()) + { + // if the remote device wrote to the characteristic, + // use the value to control the LED: + if (switchCharacteristic.written()) + { + switch (switchCharacteristic.value()) + { + case 'a': + colorWipe(strip.Color(255, 0, 0), 20); // Red + break; + case 'b': + colorWipe(strip.Color(0, 255, 0), 20); // Green + break; + case 'c': + colorWipe(strip.Color(0, 0, 255), 20); // Blue + break; + case 'd': + theaterChase(strip.Color(255, 0, 0), 20); // Red + break; + case 'e': + theaterChase(strip.Color(0, 255, 0), 20); // Green + break; + case 'f': + theaterChase(strip.Color(255, 0, 255), 20); // Cyan + break; + case 'g': + rainbow(10); + break; + case 'h': + theaterChaseRainbow(20); + break; + } + } + } + } +} + +// Fill strip pixels one after another with a color. Strip is NOT cleared +// first; anything there will be covered pixel by pixel. Pass in color +// (as a single 'packed' 32-bit value, which you can get by calling +// strip.Color(red, green, blue) as shown in the loop() function above), +// and a delay time (in milliseconds) between pixels. +void colorWipe(uint32_t color, int wait) +{ + for (int i = 0; i < strip.numPixels(); i++) + { // For each pixel in strip... + strip.setPixelColor(i, color); // Set pixel's color (in RAM) + strip.show(); // Update strip to match + delay(wait); // Pause for a moment + } +} + +// Theater-marquee-style chasing lights. Pass in a color (32-bit value, +// a la strip.Color(r,g,b) as mentioned above), and a delay time (in ms) +// between frames. +void theaterChase(uint32_t color, int wait) +{ + for (int a = 0; a < 10; a++) + { // Repeat 10 times... + for (int b = 0; b < 3; b++) + { // 'b' counts from 0 to 2... + strip.clear(); // Set all pixels in RAM to 0 (off) + // 'c' counts up from 'b' to end of strip in steps of 3... + for (int c = b; c < strip.numPixels(); c += 3) + { + strip.setPixelColor(c, color); // Set pixel 'c' to value 'color' + } + strip.show(); // Update strip with new contents + delay(wait); // Pause for a moment + } + } +} + +// Rainbow cycle along whole strip. Pass delay time (in ms) between frames. +void rainbow(int wait) +{ + // Hue of first pixel runs 5 complete loops through the color wheel. + // Color wheel has a range of 65536 but it's OK if we roll over, so + // just count from 0 to 5*65536. Adding 256 to firstPixelHue each time + // means we'll make 5*65536/256 = 1280 passes through this outer loop: + for (long firstPixelHue = 0; firstPixelHue < 5 * 65536; firstPixelHue += 256) + { + for (int i = 0; i < strip.numPixels(); i++) + { // For each pixel in strip... + // Offset pixel hue by an amount to make one full revolution of the + // color wheel (range of 65536) along the length of the strip + // (strip.numPixels() steps): + int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels()); + // strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or + // optionally add saturation and value (brightness) (each 0 to 255). + // Here we're using just the single-argument hue variant. The result + // is passed through strip.gamma32() to provide 'truer' colors + // before assigning to each pixel: + strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue))); + } + strip.show(); // Update strip with new contents + delay(wait); // Pause for a moment + } +} + +// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames. +void theaterChaseRainbow(int wait) +{ + int firstPixelHue = 0; // First pixel starts at red (hue 0) + for (int a = 0; a < 30; a++) + { // Repeat 30 times... + for (int b = 0; b < 3; b++) + { // 'b' counts from 0 to 2... + strip.clear(); // Set all pixels in RAM to 0 (off) + // 'c' counts up from 'b' to end of strip in increments of 3... + for (int c = b; c < strip.numPixels(); c += 3) + { + // hue of pixel 'c' is offset by an amount to make one full + // revolution of the color wheel (range 65536) along the length + // of the strip (strip.numPixels() steps): + int hue = firstPixelHue + c * 65536L / strip.numPixels(); + uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB + strip.setPixelColor(c, color); // Set pixel 'c' to value 'color' + } + strip.show(); // Update strip with new contents + delay(wait); // Pause for a moment + firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames + } + } +} diff --git a/lib/Adafruit_NeoPixel/examples/StrandtestArduinoBLECallback/StrandtestArduinoBLECallback.ino b/lib/Adafruit_NeoPixel/examples/StrandtestArduinoBLECallback/StrandtestArduinoBLECallback.ino new file mode 100644 index 0000000..b986943 --- /dev/null +++ b/lib/Adafruit_NeoPixel/examples/StrandtestArduinoBLECallback/StrandtestArduinoBLECallback.ino @@ -0,0 +1,239 @@ +/**************************************************************************** + * This example is based on StrandtestArduinoBLE example to make use of + * callbacks features of the ArduinoBLE library. + * + * https://github.com/arduino-libraries/ArduinoBLE + * + * Supported boards: + * Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT, + Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board. + * + * You can use a generic BLE central app, like LightBlue (iOS and Android) or + * nRF Connect (Android), to interact with the services and characteristics + * created in this sketch. + * + * This example code is in the public domain. + * + */ +#include + +#define PIN 15 // Pin where NeoPixels are connected + +// Declare our NeoPixel strip object: +Adafruit_NeoPixel strip(64, PIN, NEO_GRB + NEO_KHZ800); +// Argument 1 = Number of pixels in NeoPixel strip +// Argument 2 = Arduino pin number (most are valid) +// Argument 3 = Pixel type flags, add together as needed: +// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) +// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) +// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) +// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) +// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products) + +// NEOPIXEL BEST PRACTICES for most reliable operation: +// - Add 1000 uF CAPACITOR between NeoPixel strip's + and - connections. +// - MINIMIZE WIRING LENGTH between microcontroller board and first pixel. +// - NeoPixel strip's DATA-IN should pass through a 300-500 OHM RESISTOR. +// - AVOID connecting NeoPixels on a LIVE CIRCUIT. If you must, ALWAYS +// connect GROUND (-) first, then +, then data. +// - When using a 3.3V microcontroller with a 5V-powered NeoPixel strip, +// a LOGIC-LEVEL CONVERTER on the data line is STRONGLY RECOMMENDED. +// (Skipping these may work OK on your workbench but can fail in the field) + +uint8_t rgb_values[3]; + +#include + +BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // BLE LED Service + +// BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central +BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite); + +void setup() +{ + Serial.begin(115200); + Serial.println("Hello World!"); + + // custom services and characteristics can be added as well + // begin initialization + if (!BLE.begin()) + { + Serial.println("starting BLE failed!"); + + while (1) + ; + } + + Serial.print("Peripheral address: "); + Serial.println(BLE.address()); + + // set advertised local name and service UUID: + BLE.setLocalName("LEDCallback"); + BLE.setAdvertisedService(ledService); + + // add the characteristic to the service + ledService.addCharacteristic(switchCharacteristic); + + // add service + BLE.addService(ledService); + // assign event handlers for connected, disconnected to peripheral + BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler); + BLE.setEventHandler(BLEDisconnected, blePeripheralDisconnectHandler); + + // assign event handlers for characteristic + switchCharacteristic.setEventHandler(BLEWritten, switchCharacteristicWritten); + // set the initial value for the characeristic: + switchCharacteristic.writeValue(0); + + // start advertising + BLE.advertise(); + + strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) + strip.show(); // Turn OFF all pixels ASAP + + pinMode(PIN, OUTPUT); + digitalWrite(PIN, LOW); +} + +void loop() +{ + // poll for BLE events + BLE.poll(); +} + +void blePeripheralConnectHandler(BLEDevice central) +{ + // central connected event handler + Serial.print("Connected event, central: "); + Serial.println(central.address()); +} + +void blePeripheralDisconnectHandler(BLEDevice central) +{ + // central disconnected event handler + Serial.print("Disconnected event, central: "); + Serial.println(central.address()); +} + +void switchCharacteristicWritten(BLEDevice central, BLECharacteristic characteristic) +{ + // central wrote new value to characteristic, update LED + Serial.print("Characteristic event, written: "); + + switch (switchCharacteristic.value()) + { + case 'a': + colorWipe(strip.Color(255, 0, 0), 20); // Red + break; + case 'b': + colorWipe(strip.Color(0, 255, 0), 20); // Green + break; + case 'c': + colorWipe(strip.Color(0, 0, 255), 20); // Blue + break; + case 'd': + theaterChase(strip.Color(255, 0, 0), 20); // Red + break; + case 'e': + theaterChase(strip.Color(0, 255, 0), 20); // Green + break; + case 'f': + theaterChase(strip.Color(255, 0, 255), 20); // Cyan + break; + case 'g': + rainbow(10); + break; + case 'h': + theaterChaseRainbow(20); + break; + } +} + +// Fill strip pixels one after another with a color. Strip is NOT cleared +// first; anything there will be covered pixel by pixel. Pass in color +// (as a single 'packed' 32-bit value, which you can get by calling +// strip.Color(red, green, blue) as shown in the loop() function above), +// and a delay time (in milliseconds) between pixels. +void colorWipe(uint32_t color, int wait) +{ + for (int i = 0; i < strip.numPixels(); i++) + { // For each pixel in strip... + strip.setPixelColor(i, color); // Set pixel's color (in RAM) + strip.show(); // Update strip to match + delay(wait); // Pause for a moment + } +} + +// Theater-marquee-style chasing lights. Pass in a color (32-bit value, +// a la strip.Color(r,g,b) as mentioned above), and a delay time (in ms) +// between frames. +void theaterChase(uint32_t color, int wait) +{ + for (int a = 0; a < 10; a++) + { // Repeat 10 times... + for (int b = 0; b < 3; b++) + { // 'b' counts from 0 to 2... + strip.clear(); // Set all pixels in RAM to 0 (off) + // 'c' counts up from 'b' to end of strip in steps of 3... + for (int c = b; c < strip.numPixels(); c += 3) + { + strip.setPixelColor(c, color); // Set pixel 'c' to value 'color' + } + strip.show(); // Update strip with new contents + delay(wait); // Pause for a moment + } + } +} + +// Rainbow cycle along whole strip. Pass delay time (in ms) between frames. +void rainbow(int wait) +{ + // Hue of first pixel runs 5 complete loops through the color wheel. + // Color wheel has a range of 65536 but it's OK if we roll over, so + // just count from 0 to 5*65536. Adding 256 to firstPixelHue each time + // means we'll make 5*65536/256 = 1280 passes through this outer loop: + for (long firstPixelHue = 0; firstPixelHue < 5 * 65536; firstPixelHue += 256) + { + for (int i = 0; i < strip.numPixels(); i++) + { // For each pixel in strip... + // Offset pixel hue by an amount to make one full revolution of the + // color wheel (range of 65536) along the length of the strip + // (strip.numPixels() steps): + int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels()); + // strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or + // optionally add saturation and value (brightness) (each 0 to 255). + // Here we're using just the single-argument hue variant. The result + // is passed through strip.gamma32() to provide 'truer' colors + // before assigning to each pixel: + strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue))); + } + strip.show(); // Update strip with new contents + delay(wait); // Pause for a moment + } +} + +// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames. +void theaterChaseRainbow(int wait) +{ + int firstPixelHue = 0; // First pixel starts at red (hue 0) + for (int a = 0; a < 30; a++) + { // Repeat 30 times... + for (int b = 0; b < 3; b++) + { // 'b' counts from 0 to 2... + strip.clear(); // Set all pixels in RAM to 0 (off) + // 'c' counts up from 'b' to end of strip in increments of 3... + for (int c = b; c < strip.numPixels(); c += 3) + { + // hue of pixel 'c' is offset by an amount to make one full + // revolution of the color wheel (range 65536) along the length + // of the strip (strip.numPixels() steps): + int hue = firstPixelHue + c * 65536L / strip.numPixels(); + uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB + strip.setPixelColor(c, color); // Set pixel 'c' to value 'color' + } + strip.show(); // Update strip with new contents + delay(wait); // Pause for a moment + firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames + } + } +} diff --git a/lib/Adafruit_NeoPixel/examples/StrandtestBLE/BLESerial.cpp b/lib/Adafruit_NeoPixel/examples/StrandtestBLE/BLESerial.cpp new file mode 100644 index 0000000..d1693de --- /dev/null +++ b/lib/Adafruit_NeoPixel/examples/StrandtestBLE/BLESerial.cpp @@ -0,0 +1,133 @@ +#include "BLESerial.h" + +// #define BLE_SERIAL_DEBUG + +BLESerial* BLESerial::_instance = NULL; + +BLESerial::BLESerial(unsigned char req, unsigned char rdy, unsigned char rst) : + BLEPeripheral(req, rdy, rst) +{ + this->_txCount = 0; + this->_rxHead = this->_rxTail = 0; + this->_flushed = 0; + BLESerial::_instance = this; + + addAttribute(this->_uartService); + addAttribute(this->_uartNameDescriptor); + setAdvertisedServiceUuid(this->_uartService.uuid()); + addAttribute(this->_rxCharacteristic); + addAttribute(this->_rxNameDescriptor); + this->_rxCharacteristic.setEventHandler(BLEWritten, BLESerial::_received); + addAttribute(this->_txCharacteristic); + addAttribute(this->_txNameDescriptor); +} + +void BLESerial::begin(...) { + BLEPeripheral::begin(); + #ifdef BLE_SERIAL_DEBUG + Serial.println(F("BLESerial::begin()")); + #endif +} + +void BLESerial::poll() { + if (millis() < this->_flushed + 100) { + BLEPeripheral::poll(); + } else { + flush(); + } +} + +void BLESerial::end() { + this->_rxCharacteristic.setEventHandler(BLEWritten, NULL); + this->_rxHead = this->_rxTail = 0; + flush(); + BLEPeripheral::disconnect(); +} + +int BLESerial::available(void) { + BLEPeripheral::poll(); + int retval = (this->_rxHead - this->_rxTail + sizeof(this->_rxBuffer)) % sizeof(this->_rxBuffer); + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLESerial::available() = ")); + Serial.println(retval); + #endif + return retval; +} + +int BLESerial::peek(void) { + BLEPeripheral::poll(); + if (this->_rxTail == this->_rxHead) return -1; + uint8_t byte = this->_rxBuffer[this->_rxTail]; + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLESerial::peek() = ")); + Serial.print((char) byte); + Serial.print(F(" 0x")); + Serial.println(byte, HEX); + #endif + return byte; +} + +int BLESerial::read(void) { + BLEPeripheral::poll(); + if (this->_rxTail == this->_rxHead) return -1; + this->_rxTail = (this->_rxTail + 1) % sizeof(this->_rxBuffer); + uint8_t byte = this->_rxBuffer[this->_rxTail]; + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLESerial::read() = ")); + Serial.print((char) byte); + Serial.print(F(" 0x")); + Serial.println(byte, HEX); + #endif + return byte; +} + +void BLESerial::flush(void) { + if (this->_txCount == 0) return; + this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount); + this->_flushed = millis(); + this->_txCount = 0; + BLEPeripheral::poll(); + #ifdef BLE_SERIAL_DEBUG + Serial.println(F("BLESerial::flush()")); + #endif +} + +size_t BLESerial::write(uint8_t byte) { + BLEPeripheral::poll(); + if (this->_txCharacteristic.subscribed() == false) return 0; + this->_txBuffer[this->_txCount++] = byte; + if (this->_txCount == sizeof(this->_txBuffer)) flush(); + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLESerial::write(")); + Serial.print((char) byte); + Serial.print(F(" 0x")); + Serial.print(byte, HEX); + Serial.println(F(") = 1")); + #endif + return 1; +} + +BLESerial::operator bool() { + bool retval = BLEPeripheral::connected(); + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLESerial::operator bool() = ")); + Serial.println(retval); + #endif + return retval; +} + +void BLESerial::_received(const uint8_t* data, size_t size) { + for (int i = 0; i < size; i++) { + this->_rxHead = (this->_rxHead + 1) % sizeof(this->_rxBuffer); + this->_rxBuffer[this->_rxHead] = data[i]; + } + #ifdef BLE_SERIAL_DEBUG + Serial.print(F("BLESerial::received(")); + for (int i = 0; i < size; i++) Serial.print((char) data[i]); + Serial.println(F(")")); + #endif +} + +void BLESerial::_received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic) { + BLESerial::_instance->_received(rxCharacteristic.value(), rxCharacteristic.valueLength()); +} diff --git a/lib/Adafruit_NeoPixel/examples/StrandtestBLE/BLESerial.h b/lib/Adafruit_NeoPixel/examples/StrandtestBLE/BLESerial.h new file mode 100644 index 0000000..01904c7 --- /dev/null +++ b/lib/Adafruit_NeoPixel/examples/StrandtestBLE/BLESerial.h @@ -0,0 +1,46 @@ +#ifndef _BLE_SERIAL_H_ +#define _BLE_SERIAL_H_ + +#include +#include + +class BLESerial : public BLEPeripheral, public Stream +{ + public: + BLESerial(unsigned char req, unsigned char rdy, unsigned char rst); + + void begin(...); + void poll(); + void end(); + + virtual int available(void); + virtual int peek(void); + virtual int read(void); + virtual void flush(void); + virtual size_t write(uint8_t byte); + using Print::write; + virtual operator bool(); + + private: + unsigned long _flushed; + static BLESerial* _instance; + + size_t _rxHead; + size_t _rxTail; + size_t _rxCount() const; + uint8_t _rxBuffer[BLE_ATTRIBUTE_MAX_VALUE_LENGTH]; + size_t _txCount; + uint8_t _txBuffer[BLE_ATTRIBUTE_MAX_VALUE_LENGTH]; + + BLEService _uartService = BLEService("6E400001-B5A3-F393-E0A9-E50E24DCCA9E"); + BLEDescriptor _uartNameDescriptor = BLEDescriptor("2901", "UART"); + BLECharacteristic _rxCharacteristic = BLECharacteristic("6E400002-B5A3-F393-E0A9-E50E24DCCA9E", BLEWriteWithoutResponse, BLE_ATTRIBUTE_MAX_VALUE_LENGTH); + BLEDescriptor _rxNameDescriptor = BLEDescriptor("2901", "RX - Receive Data (Write)"); + BLECharacteristic _txCharacteristic = BLECharacteristic("6E400003-B5A3-F393-E0A9-E50E24DCCA9E", BLENotify, BLE_ATTRIBUTE_MAX_VALUE_LENGTH); + BLEDescriptor _txNameDescriptor = BLEDescriptor("2901", "TX - Transfer Data (Notify)"); + + void _received(const uint8_t* data, size_t size); + static void _received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic); +}; + +#endif diff --git a/lib/Adafruit_NeoPixel/examples/StrandtestBLE/StrandtestBLE.ino b/lib/Adafruit_NeoPixel/examples/StrandtestBLE/StrandtestBLE.ino new file mode 100644 index 0000000..593b35b --- /dev/null +++ b/lib/Adafruit_NeoPixel/examples/StrandtestBLE/StrandtestBLE.ino @@ -0,0 +1,192 @@ +/**************************************************************************** + * This example was developed by the Hackerspace San Salvador to demonstrate + * the simultaneous use of the NeoPixel library and the Bluetooth SoftDevice. + * To compile this example you'll need to add support for the NRF52 based + * following the instructions at: + * https://github.com/sandeepmistry/arduino-nRF5 + * Or adding the following URL to the board manager URLs on Arduino preferences: + * https://sandeepmistry.github.io/arduino-nRF5/package_nRF5_boards_index.json + * Then you can install the BLEPeripheral library avaiable at: + * https://github.com/sandeepmistry/arduino-BLEPeripheral + * To test it, compile this example and use the UART module from the nRF + * Toolbox App for Android. Edit the interface and send the characters + * 'a' to 'i' to switch the animation. + * There is a delay because this example blocks the thread of execution but + * the change will be shown after the current animation ends. (This might + * take a couple of seconds) + * For more info write us at: info _at- teubi.co + */ +#include +#include +#include "BLESerial.h" +#include + +#define PIN 15 // Pin where NeoPixels are connected + +// Declare our NeoPixel strip object: +Adafruit_NeoPixel strip(64, PIN, NEO_GRB + NEO_KHZ800); +// Argument 1 = Number of pixels in NeoPixel strip +// Argument 2 = Arduino pin number (most are valid) +// Argument 3 = Pixel type flags, add together as needed: +// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) +// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) +// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) +// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) +// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products) + +// NEOPIXEL BEST PRACTICES for most reliable operation: +// - Add 1000 uF CAPACITOR between NeoPixel strip's + and - connections. +// - MINIMIZE WIRING LENGTH between microcontroller board and first pixel. +// - NeoPixel strip's DATA-IN should pass through a 300-500 OHM RESISTOR. +// - AVOID connecting NeoPixels on a LIVE CIRCUIT. If you must, ALWAYS +// connect GROUND (-) first, then +, then data. +// - When using a 3.3V microcontroller with a 5V-powered NeoPixel strip, +// a LOGIC-LEVEL CONVERTER on the data line is STRONGLY RECOMMENDED. +// (Skipping these may work OK on your workbench but can fail in the field) + +// define pins (varies per shield/board) +#define BLE_REQ 10 +#define BLE_RDY 2 +#define BLE_RST 9 + +// create ble serial instance, see pinouts above +BLESerial BLESerial(BLE_REQ, BLE_RDY, BLE_RST); + +uint8_t current_state = 0; +uint8_t rgb_values[3]; + +void setup() { + Serial.begin(115200); + Serial.println("Hello World!"); + // custom services and characteristics can be added as well + BLESerial.setLocalName("UART_HS"); + BLESerial.begin(); + + strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) + strip.show(); // Turn OFF all pixels ASAP + + //pinMode(PIN, OUTPUT); + //digitalWrite(PIN, LOW); + + current_state = 'a'; +} + +void loop() { + while(BLESerial.available()) { + uint8_t character = BLESerial.read(); + switch(character) { + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + current_state = character; + break; + }; + } + switch(current_state) { + case 'a': + colorWipe(strip.Color(255, 0, 0), 20); // Red + break; + case 'b': + colorWipe(strip.Color( 0, 255, 0), 20); // Green + break; + case 'c': + colorWipe(strip.Color( 0, 0, 255), 20); // Blue + break; + case 'd': + theaterChase(strip.Color(255, 0, 0), 20); // Red + break; + case 'e': + theaterChase(strip.Color( 0, 255, 0), 20); // Green + break; + case 'f': + theaterChase(strip.Color(255, 0, 255), 20); // Cyan + break; + case 'g': + rainbow(10); + break; + case 'h': + theaterChaseRainbow(20); + break; + } +} + +// Fill strip pixels one after another with a color. Strip is NOT cleared +// first; anything there will be covered pixel by pixel. Pass in color +// (as a single 'packed' 32-bit value, which you can get by calling +// strip.Color(red, green, blue) as shown in the loop() function above), +// and a delay time (in milliseconds) between pixels. +void colorWipe(uint32_t color, int wait) { + for(int i=0; i RGB + strip.setPixelColor(c, color); // Set pixel 'c' to value 'color' + } + strip.show(); // Update strip with new contents + delay(wait); // Pause for a moment + firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames + } + } +} diff --git a/lib/Adafruit_NeoPixel/examples/buttoncycler/buttoncycler.ino b/lib/Adafruit_NeoPixel/examples/buttoncycler/buttoncycler.ino new file mode 100644 index 0000000..f6d87ed --- /dev/null +++ b/lib/Adafruit_NeoPixel/examples/buttoncycler/buttoncycler.ino @@ -0,0 +1,164 @@ +// Simple demonstration on using an input device to trigger changes on your +// NeoPixels. Wire a momentary push button to connect from ground to a +// digital IO pin. When the button is pressed it will change to a new pixel +// animation. Initial state has all pixels off -- press the button once to +// start the first animation. As written, the button does not interrupt an +// animation in-progress, it works only when idle. + +#include +#ifdef __AVR__ + #include // Required for 16 MHz Adafruit Trinket +#endif + +// Digital IO pin connected to the button. This will be driven with a +// pull-up resistor so the switch pulls the pin to ground momentarily. +// On a high -> low transition the button press logic will execute. +#define BUTTON_PIN 2 + +#define PIXEL_PIN 6 // Digital IO pin connected to the NeoPixels. + +#define PIXEL_COUNT 16 // Number of NeoPixels + +// Declare our NeoPixel strip object: +Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800); +// Argument 1 = Number of pixels in NeoPixel strip +// Argument 2 = Arduino pin number (most are valid) +// Argument 3 = Pixel type flags, add together as needed: +// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) +// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) +// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) +// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) +// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products) + +boolean oldState = HIGH; +int mode = 0; // Currently-active animation mode, 0-9 + +void setup() { + pinMode(BUTTON_PIN, INPUT_PULLUP); + strip.begin(); // Initialize NeoPixel strip object (REQUIRED) + strip.show(); // Initialize all pixels to 'off' +} + +void loop() { + // Get current button state. + boolean newState = digitalRead(BUTTON_PIN); + + // Check if state changed from high to low (button press). + if((newState == LOW) && (oldState == HIGH)) { + // Short delay to debounce button. + delay(20); + // Check if button is still low after debounce. + newState = digitalRead(BUTTON_PIN); + if(newState == LOW) { // Yes, still low + if(++mode > 8) mode = 0; // Advance to next mode, wrap around after #8 + switch(mode) { // Start the new animation... + case 0: + colorWipe(strip.Color( 0, 0, 0), 50); // Black/off + break; + case 1: + colorWipe(strip.Color(255, 0, 0), 50); // Red + break; + case 2: + colorWipe(strip.Color( 0, 255, 0), 50); // Green + break; + case 3: + colorWipe(strip.Color( 0, 0, 255), 50); // Blue + break; + case 4: + theaterChase(strip.Color(127, 127, 127), 50); // White + break; + case 5: + theaterChase(strip.Color(127, 0, 0), 50); // Red + break; + case 6: + theaterChase(strip.Color( 0, 0, 127), 50); // Blue + break; + case 7: + rainbow(10); + break; + case 8: + theaterChaseRainbow(50); + break; + } + } + } + + // Set the last-read button state to the old state. + oldState = newState; +} + +// Fill strip pixels one after another with a color. Strip is NOT cleared +// first; anything there will be covered pixel by pixel. Pass in color +// (as a single 'packed' 32-bit value, which you can get by calling +// strip.Color(red, green, blue) as shown in the loop() function above), +// and a delay time (in milliseconds) between pixels. +void colorWipe(uint32_t color, int wait) { + for(int i=0; i RGB + strip.setPixelColor(c, color); // Set pixel 'c' to value 'color' + } + strip.show(); // Update strip with new contents + delay(wait); // Pause for a moment + firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames + } + } +} diff --git a/lib/Adafruit_NeoPixel/examples/simple/simple.ino b/lib/Adafruit_NeoPixel/examples/simple/simple.ino new file mode 100644 index 0000000..09f458e --- /dev/null +++ b/lib/Adafruit_NeoPixel/examples/simple/simple.ino @@ -0,0 +1,50 @@ +// NeoPixel Ring simple sketch (c) 2013 Shae Erisson +// Released under the GPLv3 license to match the rest of the +// Adafruit NeoPixel library + +#include +#ifdef __AVR__ + #include // Required for 16 MHz Adafruit Trinket +#endif + +// Which pin on the Arduino is connected to the NeoPixels? +#define PIN 6 // On Trinket or Gemma, suggest changing this to 1 + +// How many NeoPixels are attached to the Arduino? +#define NUMPIXELS 16 // Popular NeoPixel ring size + +// When setting up the NeoPixel library, we tell it how many pixels, +// and which pin to use to send signals. Note that for older NeoPixel +// strips you might need to change the third parameter -- see the +// strandtest example for more information on possible values. +Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); + +#define DELAYVAL 500 // Time (in milliseconds) to pause between pixels + +void setup() { + // These lines are specifically to support the Adafruit Trinket 5V 16 MHz. + // Any other board, you can remove this part (but no harm leaving it): +#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000) + clock_prescale_set(clock_div_1); +#endif + // END of Trinket-specific code. + + pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) +} + +void loop() { + pixels.clear(); // Set all pixel colors to 'off' + + // The first NeoPixel in a strand is #0, second is 1, all the way up + // to the count of pixels minus one. + for(int i=0; i +#ifdef __AVR__ + #include // Required for 16 MHz Adafruit Trinket +#endif + +// Which pin on the Arduino is connected to the NeoPixels? +int pin = 6; // On Trinket or Gemma, suggest changing this to 1 + +// How many NeoPixels are attached to the Arduino? +int numPixels = 16; // Popular NeoPixel ring size + +// NeoPixel color format & data rate. See the strandtest example for +// information on possible values. +int pixelFormat = NEO_GRB + NEO_KHZ800; + +// Rather than declaring the whole NeoPixel object here, we just create +// a pointer for one, which we'll then allocate later... +Adafruit_NeoPixel *pixels; + +#define DELAYVAL 500 // Time (in milliseconds) to pause between pixels + +void setup() { + // These lines are specifically to support the Adafruit Trinket 5V 16 MHz. + // Any other board, you can remove this part (but no harm leaving it): +#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000) + clock_prescale_set(clock_div_1); +#endif + // END of Trinket-specific code. + + // Right about here is where we could read 'pin', 'numPixels' and/or + // 'pixelFormat' from EEPROM or a file on SD or whatever. This is a simple + // example and doesn't do that -- those variables are just set to fixed + // values at the top of this code -- but this is where it would happen. + + // Then create a new NeoPixel object dynamically with these values: + pixels = new Adafruit_NeoPixel(numPixels, pin, pixelFormat); + + // Going forward from here, code works almost identically to any other + // NeoPixel example, but instead of the dot operator on function calls + // (e.g. pixels.begin()), we instead use pointer indirection (->) like so: + pixels->begin(); // INITIALIZE NeoPixel strip object (REQUIRED) + // You'll see more of this in the loop() function below. +} + +void loop() { + pixels->clear(); // Set all pixel colors to 'off' + + // The first NeoPixel in a strand is #0, second is 1, all the way up + // to the count of pixels minus one. + for(int i=0; iColor() takes RGB values, from 0,0,0 up to 255,255,255 + // Here we're using a moderately bright green color: + pixels->setPixelColor(i, pixels->Color(0, 150, 0)); + + pixels->show(); // Send the updated pixel colors to the hardware. + + delay(DELAYVAL); // Pause before next pass through loop + } +} diff --git a/lib/Adafruit_NeoPixel/examples/strandtest/strandtest.ino b/lib/Adafruit_NeoPixel/examples/strandtest/strandtest.ino new file mode 100644 index 0000000..d7b08e3 --- /dev/null +++ b/lib/Adafruit_NeoPixel/examples/strandtest/strandtest.ino @@ -0,0 +1,147 @@ +// A basic everyday NeoPixel strip test program. + +// NEOPIXEL BEST PRACTICES for most reliable operation: +// - Add 1000 uF CAPACITOR between NeoPixel strip's + and - connections. +// - MINIMIZE WIRING LENGTH between microcontroller board and first pixel. +// - NeoPixel strip's DATA-IN should pass through a 300-500 OHM RESISTOR. +// - AVOID connecting NeoPixels on a LIVE CIRCUIT. If you must, ALWAYS +// connect GROUND (-) first, then +, then data. +// - When using a 3.3V microcontroller with a 5V-powered NeoPixel strip, +// a LOGIC-LEVEL CONVERTER on the data line is STRONGLY RECOMMENDED. +// (Skipping these may work OK on your workbench but can fail in the field) + +#include +#ifdef __AVR__ + #include // Required for 16 MHz Adafruit Trinket +#endif + +// Which pin on the Arduino is connected to the NeoPixels? +// On a Trinket or Gemma we suggest changing this to 1: +#define LED_PIN 6 + +// How many NeoPixels are attached to the Arduino? +#define LED_COUNT 60 + +// Declare our NeoPixel strip object: +Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800); +// Argument 1 = Number of pixels in NeoPixel strip +// Argument 2 = Arduino pin number (most are valid) +// Argument 3 = Pixel type flags, add together as needed: +// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) +// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) +// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) +// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) +// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products) + + +// setup() function -- runs once at startup -------------------------------- + +void setup() { + // These lines are specifically to support the Adafruit Trinket 5V 16 MHz. + // Any other board, you can remove this part (but no harm leaving it): +#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000) + clock_prescale_set(clock_div_1); +#endif + // END of Trinket-specific code. + + strip.begin(); // INITIALIZE NeoPixel strip object (REQUIRED) + strip.show(); // Turn OFF all pixels ASAP + strip.setBrightness(50); // Set BRIGHTNESS to about 1/5 (max = 255) +} + + +// loop() function -- runs repeatedly as long as board is on --------------- + +void loop() { + // Fill along the length of the strip in various colors... + colorWipe(strip.Color(255, 0, 0), 50); // Red + colorWipe(strip.Color( 0, 255, 0), 50); // Green + colorWipe(strip.Color( 0, 0, 255), 50); // Blue + + // Do a theater marquee effect in various colors... + theaterChase(strip.Color(127, 127, 127), 50); // White, half brightness + theaterChase(strip.Color(127, 0, 0), 50); // Red, half brightness + theaterChase(strip.Color( 0, 0, 127), 50); // Blue, half brightness + + rainbow(10); // Flowing rainbow cycle along the whole strip + theaterChaseRainbow(50); // Rainbow-enhanced theaterChase variant +} + + +// Some functions of our own for creating animated effects ----------------- + +// Fill strip pixels one after another with a color. Strip is NOT cleared +// first; anything there will be covered pixel by pixel. Pass in color +// (as a single 'packed' 32-bit value, which you can get by calling +// strip.Color(red, green, blue) as shown in the loop() function above), +// and a delay time (in milliseconds) between pixels. +void colorWipe(uint32_t color, int wait) { + for(int i=0; i RGB + strip.setPixelColor(c, color); // Set pixel 'c' to value 'color' + } + strip.show(); // Update strip with new contents + delay(wait); // Pause for a moment + firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames + } + } +} diff --git a/lib/Adafruit_NeoPixel/examples/strandtest_wheel/strandtest_wheel.ino b/lib/Adafruit_NeoPixel/examples/strandtest_wheel/strandtest_wheel.ino new file mode 100644 index 0000000..c0ca41e --- /dev/null +++ b/lib/Adafruit_NeoPixel/examples/strandtest_wheel/strandtest_wheel.ino @@ -0,0 +1,134 @@ +#include +#ifdef __AVR__ + #include +#endif + +#define PIN 6 + +// Parameter 1 = number of pixels in strip +// Parameter 2 = Arduino pin number (most are valid) +// Parameter 3 = pixel type flags, add together as needed: +// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) +// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) +// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) +// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) +// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products) +Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800); + +// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across +// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input +// and minimize distance between Arduino and first pixel. Avoid connecting +// on a live circuit...if you must, connect GND first. + +void setup() { + // This is for Trinket 5V 16MHz, you can remove these three lines if you are not using a Trinket + #if defined (__AVR_ATtiny85__) + if (F_CPU == 16000000) clock_prescale_set(clock_div_1); + #endif + // End of trinket special code + + strip.begin(); + strip.setBrightness(50); + strip.show(); // Initialize all pixels to 'off' +} + +void loop() { + // Some example procedures showing how to display to the pixels: + colorWipe(strip.Color(255, 0, 0), 50); // Red + colorWipe(strip.Color(0, 255, 0), 50); // Green + colorWipe(strip.Color(0, 0, 255), 50); // Blue +//colorWipe(strip.Color(0, 0, 0, 255), 50); // White RGBW + // Send a theater pixel chase in... + theaterChase(strip.Color(127, 127, 127), 50); // White + theaterChase(strip.Color(127, 0, 0), 50); // Red + theaterChase(strip.Color(0, 0, 127), 50); // Blue + + rainbow(20); + rainbowCycle(20); + theaterChaseRainbow(50); +} + +// Fill the dots one after the other with a color +void colorWipe(uint32_t c, uint8_t wait) { + for(uint16_t i=0; i +sentence=Arduino library for controlling single-wire-based LED pixels and strip. +paragraph=Arduino library for controlling single-wire-based LED pixels and strip. +category=Display +url=https://github.com/adafruit/Adafruit_NeoPixel +architectures=* diff --git a/lib/Adafruit_SHT31/.github/ISSUE_TEMPLATE.md b/lib/Adafruit_SHT31/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..f0e2614 --- /dev/null +++ b/lib/Adafruit_SHT31/.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_SHT31/.github/PULL_REQUEST_TEMPLATE.md b/lib/Adafruit_SHT31/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..7b641eb --- /dev/null +++ b/lib/Adafruit_SHT31/.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_SHT31/.travis.yml b/lib/Adafruit_SHT31/.travis.yml new file mode 100644 index 0000000..5be25af --- /dev/null +++ b/lib/Adafruit_SHT31/.travis.yml @@ -0,0 +1,29 @@ +language: c +sudo: false +cache: + directories: + - ~/arduino_ide + - ~/.arduino15/packages/ +git: + depth: false + quiet: true +env: + global: + - ARDUINO_IDE_VERSION="1.8.7" + - PRETTYNAME="Adafruit SHT31-D Library" +# Optional, will default to "$TRAVIS_BUILD_DIR/Doxyfile" +# - DOXYFILE: $TRAVIS_BUILD_DIR/Doxyfile + +before_install: + - source <(curl -SLs https://raw.githubusercontent.com/adafruit/travis-ci-arduino/master/install.sh) + +install: + - true + +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) diff --git a/lib/Adafruit_SHT31/Adafruit_SHT31.cpp b/lib/Adafruit_SHT31/Adafruit_SHT31.cpp new file mode 100644 index 0000000..c9434be --- /dev/null +++ b/lib/Adafruit_SHT31/Adafruit_SHT31.cpp @@ -0,0 +1,144 @@ +/*************************************************** + This is a library for the SHT31 Digital Humidity & Temp Sensor + + Designed specifically to work with the SHT31 Digital sensor from Adafruit + ----> https://www.adafruit.com/products/2857 + + These sensors use 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 Limor Fried/Ladyada for Adafruit Industries. + BSD license, all text above must be included in any redistribution + ****************************************************/ + +#include "Adafruit_SHT31.h" + +Adafruit_SHT31::Adafruit_SHT31() { + _i2caddr = NULL; + humidity = 0.0f; + temp = 0.0f; +} + +boolean Adafruit_SHT31::begin(uint8_t i2caddr) { + Wire.begin(); + _i2caddr = i2caddr; + reset(); + // return (readStatus() == 0x40); + return true; +} + +uint16_t Adafruit_SHT31::readStatus(void) { + writeCommand(SHT31_READSTATUS); + Wire.requestFrom(_i2caddr, (uint8_t)3); + uint16_t stat = Wire.read(); + stat <<= 8; + stat |= Wire.read(); + // Serial.println(stat, HEX); + return stat; +} + +void Adafruit_SHT31::reset(void) { + writeCommand(SHT31_SOFTRESET); + delay(10); +} + +void Adafruit_SHT31::heater(boolean h) { + if (h) + writeCommand(SHT31_HEATEREN); + else + writeCommand(SHT31_HEATERDIS); +} + +float Adafruit_SHT31::readTemperature(void) { + if (!readTempHum()) + return NAN; + + return temp; +} + +float Adafruit_SHT31::readHumidity(void) { + if (!readTempHum()) + return NAN; + + return humidity; +} + +boolean Adafruit_SHT31::readTempHum(void) { + uint8_t readbuffer[6]; + + writeCommand(SHT31_MEAS_HIGHREP); + + delay(20); + Wire.requestFrom(_i2caddr, (uint8_t)6); + if (Wire.available() != 6) + return false; + for (uint8_t i = 0; i < 6; i++) { + readbuffer[i] = Wire.read(); + // Serial.print("0x"); Serial.println(readbuffer[i], HEX); + } + + uint16_t ST, SRH; + ST = readbuffer[0]; + ST <<= 8; + ST |= readbuffer[1]; + + if (readbuffer[2] != crc8(readbuffer, 2)) + return false; + + SRH = readbuffer[3]; + SRH <<= 8; + SRH |= readbuffer[4]; + + if (readbuffer[5] != crc8(readbuffer + 3, 2)) + return false; + + // Serial.print("ST = "); Serial.println(ST); + double stemp = ST; + stemp *= 175; + stemp /= 0xffff; + stemp = -45 + stemp; + temp = stemp; + + // Serial.print("SRH = "); Serial.println(SRH); + double shum = SRH; + shum *= 100; + shum /= 0xFFFF; + + humidity = shum; + + return true; +} + +void Adafruit_SHT31::writeCommand(uint16_t cmd) { + Wire.beginTransmission(_i2caddr); + Wire.write(cmd >> 8); + Wire.write(cmd & 0xFF); + Wire.endTransmission(); +} + +uint8_t Adafruit_SHT31::crc8(const uint8_t *data, int len) { + /* + * + * CRC-8 formula from page 14 of SHT spec pdf + * + * Test data 0xBE, 0xEF should yield 0x92 + * + * Initialization data 0xFF + * Polynomial 0x31 (x8 + x5 +x4 +1) + * Final XOR 0x00 + */ + + const uint8_t POLYNOMIAL(0x31); + uint8_t crc(0xFF); + + for (int j = len; j; --j) { + crc ^= *data++; + + for (int i = 8; i; --i) { + crc = (crc & 0x80) ? (crc << 1) ^ POLYNOMIAL : (crc << 1); + } + } + return crc; +} diff --git a/lib/Adafruit_SHT31/Adafruit_SHT31.h b/lib/Adafruit_SHT31/Adafruit_SHT31.h new file mode 100644 index 0000000..cc9b041 --- /dev/null +++ b/lib/Adafruit_SHT31/Adafruit_SHT31.h @@ -0,0 +1,135 @@ +/*************************************************** + This is a library for the SHT31 Digital Humidity & Temp Sensor + + Designed specifically to work with the SHT31 Digital sensor from Adafruit + ----> https://www.adafruit.com/products/2857 + + These sensors use 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 Limor Fried/Ladyada for Adafruit Industries. + BSD license, all text above must be included in any redistribution + ****************************************************/ + +#ifndef ADAFRUIT_SHT31_H +#define ADAFRUIT_SHT31_H + +#include "Arduino.h" +#include "Wire.h" + +#define SHT31_DEFAULT_ADDR 0x44 +#define SHT31_MEAS_HIGHREP_STRETCH 0x2C06 +#define SHT31_MEAS_MEDREP_STRETCH 0x2C0D +#define SHT31_MEAS_LOWREP_STRETCH 0x2C10 +#define SHT31_MEAS_HIGHREP 0x2400 +#define SHT31_MEAS_MEDREP 0x240B +#define SHT31_MEAS_LOWREP 0x2416 +#define SHT31_READSTATUS 0xF32D +#define SHT31_CLEARSTATUS 0x3041 +#define SHT31_SOFTRESET 0x30A2 +#define SHT31_HEATEREN 0x306D +#define SHT31_HEATERDIS 0x3066 + +/** + * Driver for the Adafruit SHT31-D Temperature and Humidity breakout board. + */ +class Adafruit_SHT31 { + public: + /** + * Constructor. + */ + Adafruit_SHT31(); + + /** + * Initialises the I2C bus, and assigns the I2C address to us. + * + * @param i2caddr The I2C address to use for the sensor. + * + * @return True if initialisation was successful, otherwise False. + */ + boolean begin(uint8_t i2caddr = SHT31_DEFAULT_ADDR); + + /** + * Gets a single temperature reading from the sensor. + * + * @return A float value indicating the temperature. + */ + float readTemperature(void); + + /** + * Gets a single relative humidity reading from the sensor. + * + * @return A float value representing relative humidity. + */ + float readHumidity(void); + + /** + * Gets the current status register contents. + * + * @return The 16-bit status register. + */ + uint16_t readStatus(void); + + /** + * Performs a reset of the sensor to put it into a known state. + */ + void reset(void); + + /** + * Enables or disabled the heating element. + * + * @param h True to enable the heater, False to disable it. + */ + void heater(boolean h); + + /** + * Performs a CRC8 calculation on the supplied values. + * + * @param data Pointer to the data to use when calculating the CRC8. + * @param len The number of bytes in 'data'. + * + * @return The computed CRC8 value. + */ + uint8_t crc8(const uint8_t *data, int len); + + private: + /** + * Placeholder to track the I2C address. + */ + uint8_t _i2caddr; + + /** + * Placeholder to track humidity internally. + */ + float humidity; + + /** + * Placeholder to track temperature internally. + */ + float temp; + + /** + * Internal function to perform a temp + humidity read. + * + * @return True if successful, otherwise false. + */ + boolean readTempHum(void); + + /** + * Internal function to perform and I2C write. + * + * @param cmd The 16-bit command ID to send. + */ + void writeCommand(uint16_t cmd); + + /** + * Internal function to read data over the I2C bus. + * + * @return True if successful, otherwise False. + */ + boolean readData(void); +}; + +#endif diff --git a/lib/Adafruit_SHT31/README.md b/lib/Adafruit_SHT31/README.md new file mode 100644 index 0000000..91f6c13 --- /dev/null +++ b/lib/Adafruit_SHT31/README.md @@ -0,0 +1,58 @@ +# Adafruit SHT31-D Temperature and Humidity Sensor Breakout [![Build Status](https://travis-ci.org/adafruit/Adafruit_SHT31.svg?branch=master)](https://travis-ci.org/adafruit/Adafruit_SHT31) + +![Adafruit SHT31](https://cdn-learn.adafruit.com/assets/assets/000/028/970/small360/adafruit_products_2857_iso_ORIG.jpg?1449606376) + +This is a library for the SHT31 Digital Humidity + Temp sensor. + +It is designed specifically to work with the SHT31 Digital in the Adafruit shop: + +- https://www.adafruit.com/products/2857 + +These sensors use **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 Limor Fried/Ladyada for Adafruit Industries. +BSD license, all text above must be included in any redistribution + +Check out the links above for our tutorials and wiring diagrams + +## Installation + +Use the Arduino Library Manager to install this library. If you're unfamiliar +with how this works, we have a great tutorial on Arduino library installation +at: http://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use + + + +## Compatibility + +MCU | Tested Works | Doesn't Work | Not Tested | Notes +------------------ | :----------: | :----------: | :---------: | ----- +Atmega328 @ 16MHz | X | | | +Atmega328 @ 12MHz | X | | | +Atmega32u4 @ 16MHz | X | | | +Atmega32u4 @ 8MHz | X | | | +ESP8266 | X | | | +Atmega2560 @ 16MHz | X | | | +ATSAM3X8E | X | | | +ATSAM21D | X | | | +ATtiny85 @ 16MHz | X | | | +ATtiny85 @ 8MHz | X | | | +Intel Curie @ 32MHz | | | X | +STM32F2 | | | X | + + * ATmega328 @ 16MHz : Arduino UNO, Adafruit Pro Trinket 5V, Adafruit Metro 328, Adafruit Metro Mini + * ATmega328 @ 12MHz : Adafruit Pro Trinket 3V + * ATmega32u4 @ 16MHz : Arduino Leonardo, Arduino Micro, Arduino Yun, Teensy 2.0 + * ATmega32u4 @ 8MHz : Adafruit Flora, Bluefruit Micro + * ESP8266 : Adafruit Huzzah + * ATmega2560 @ 16MHz : Arduino Mega + * ATSAM3X8E : Arduino Due + * ATSAM21D : Arduino Zero, M0 Pro + * ATtiny85 @ 16MHz : Adafruit Trinket 5V + * ATtiny85 @ 8MHz : Adafruit Gemma, Arduino Gemma, Adafruit Trinket 3V + + diff --git a/lib/Adafruit_SHT31/examples/SHT31test/SHT31test.ino b/lib/Adafruit_SHT31/examples/SHT31test/SHT31test.ino new file mode 100644 index 0000000..7caabdb --- /dev/null +++ b/lib/Adafruit_SHT31/examples/SHT31test/SHT31test.ino @@ -0,0 +1,48 @@ +/*************************************************** + This is an example for the SHT31-D Humidity & Temp Sensor + + Designed specifically to work with the SHT31-D sensor from Adafruit + ----> https://www.adafruit.com/products/2857 + + These sensors use I2C to communicate, 2 pins are required to + interface + ****************************************************/ + +#include +#include +#include "Adafruit_SHT31.h" + +Adafruit_SHT31 sht31 = Adafruit_SHT31(); + +void setup() { + Serial.begin(9600); + + while (!Serial) + delay(10); // will pause Zero, Leonardo, etc until serial console opens + + Serial.println("SHT31 test"); + if (! sht31.begin(0x44)) { // Set to 0x45 for alternate i2c addr + Serial.println("Couldn't find SHT31"); + while (1) delay(1); + } +} + + +void loop() { + float t = sht31.readTemperature(); + float h = sht31.readHumidity(); + + if (! isnan(t)) { // check if 'is not a number' + Serial.print("Temp *C = "); Serial.println(t); + } else { + Serial.println("Failed to read temperature"); + } + + if (! isnan(h)) { // check if 'is not a number' + Serial.print("Hum. % = "); Serial.println(h); + } else { + Serial.println("Failed to read humidity"); + } + Serial.println(); + delay(1000); +} \ No newline at end of file diff --git a/lib/Adafruit_SHT31/library.properties b/lib/Adafruit_SHT31/library.properties new file mode 100644 index 0000000..c8880df --- /dev/null +++ b/lib/Adafruit_SHT31/library.properties @@ -0,0 +1,9 @@ +name=Adafruit SHT31 Library +version=1.1.0 +author=Adafruit +maintainer=Adafruit +sentence=Arduino library for SHT31 temperature & humidity sensor. +paragraph=Arduino library for SHT31 temperature & humidity sensor. +category=Sensors +url=https://github.com/adafruit/Adafruit_SHT31 +architectures=* diff --git a/lib/Adafruit_Si7021/Adafruit_Si7021.cpp b/lib/Adafruit_Si7021/Adafruit_Si7021.cpp new file mode 100644 index 0000000..d082998 --- /dev/null +++ b/lib/Adafruit_Si7021/Adafruit_Si7021.cpp @@ -0,0 +1,173 @@ +/**************************************************************************/ +/*! + @file Adafruit_Si7021.cpp + @author Limor Fried (Adafruit Industries) + @license BSD (see license.txt) + + This is a library for the Adafruit Si7021 breakout board + ----> https://www.adafruit.com/products/3251 + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + @section HISTORY + + v1.0 - First release +*/ +/**************************************************************************/ + +#if ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +#include +#include + + +/**************************************************************************/ + +Adafruit_Si7021::Adafruit_Si7021(void) { + _i2caddr = SI7021_DEFAULT_ADDRESS; + sernum_a = sernum_b = 0; +} + +bool Adafruit_Si7021::begin(void) { + Wire.begin(); + + reset(); + if (readRegister8(SI7021_READRHT_REG_CMD) != 0x3A) return false; + + readSerialNumber(); + + //Serial.println(sernum_a, HEX); + //Serial.println(sernum_b, HEX); + + return true; +} + +float Adafruit_Si7021::readHumidity(void) { + Wire.beginTransmission(_i2caddr); + Wire.write((uint8_t)SI7021_MEASRH_NOHOLD_CMD); + Wire.endTransmission(false); + delay(25); + + Wire.requestFrom(_i2caddr, 3); + uint16_t hum = Wire.read(); + hum <<= 8; + hum |= Wire.read(); + uint8_t chxsum = Wire.read(); + + float humidity = hum; + humidity *= 125; + humidity /= 65536; + humidity -= 6; + + return humidity; +} + +float Adafruit_Si7021::readTemperature(void) { + Wire.beginTransmission(_i2caddr); + Wire.write((uint8_t)SI7021_MEASTEMP_NOHOLD_CMD); + Wire.endTransmission(false); + delay(25); + + Wire.requestFrom(_i2caddr, 3); + uint16_t temp = Wire.read(); + temp <<= 8; + temp |= Wire.read(); + uint8_t chxsum = Wire.read(); + + float temperature = temp; + temperature *= 175.72; + temperature /= 65536; + temperature -= 46.85; + + return temperature; +} + +void Adafruit_Si7021::reset(void) { + Wire.beginTransmission(_i2caddr); + Wire.write((uint8_t)SI7021_RESET_CMD); + Wire.endTransmission(); + delay(50); +} + +void Adafruit_Si7021::readSerialNumber(void) { + Wire.beginTransmission(_i2caddr); + Wire.write((uint8_t)(SI7021_ID1_CMD>>8)); + Wire.write((uint8_t)(SI7021_ID1_CMD&0xFF)); + Wire.endTransmission(); + + Wire.requestFrom(_i2caddr, 8); + sernum_a = Wire.read(); + Wire.read(); + sernum_a <<= 8; + sernum_a |= Wire.read(); + Wire.read(); + sernum_a <<= 8; + sernum_a |= Wire.read(); + Wire.read(); + sernum_a <<= 8; + sernum_a |= Wire.read(); + Wire.read(); + + Wire.beginTransmission(_i2caddr); + Wire.write((uint8_t)(SI7021_ID2_CMD>>8)); + Wire.write((uint8_t)(SI7021_ID2_CMD&0xFF)); + Wire.endTransmission(); + + Wire.requestFrom(_i2caddr, 8); + sernum_b = Wire.read(); + Wire.read(); + sernum_b <<= 8; + sernum_b |= Wire.read(); + Wire.read(); + sernum_b <<= 8; + sernum_b |= Wire.read(); + Wire.read(); + sernum_b <<= 8; + sernum_b |= Wire.read(); + Wire.read(); +} + +/*******************************************************************/ + +void Adafruit_Si7021::writeRegister8(uint8_t reg, uint8_t value) { + Wire.beginTransmission(_i2caddr); + Wire.write((uint8_t)reg); + Wire.write((uint8_t)value); + Wire.endTransmission(); + + //Serial.print("Wrote $"); Serial.print(reg, HEX); Serial.print(": 0x"); Serial.println(value, HEX); +} + +uint8_t Adafruit_Si7021::readRegister8(uint8_t reg) { + uint8_t value; + Wire.beginTransmission(_i2caddr); + Wire.write((uint8_t)reg); + Wire.endTransmission(false); + + Wire.requestFrom(_i2caddr, 1); + value = Wire.read(); + + //Serial.print("Read $"); Serial.print(reg, HEX); Serial.print(": 0x"); Serial.println(value, HEX); + return value; +} + +uint16_t Adafruit_Si7021::readRegister16(uint8_t reg) { + uint16_t value; + Wire.beginTransmission(_i2caddr); + Wire.write((uint8_t)reg); + Wire.endTransmission(); + + Wire.requestFrom(_i2caddr, 2); + value = Wire.read(); + value <<= 8; + value |= Wire.read(); + + //Serial.print("Read $"); Serial.print(reg, HEX); Serial.print(": 0x"); Serial.println(value, HEX); + return value; +} diff --git a/lib/Adafruit_Si7021/Adafruit_Si7021.h b/lib/Adafruit_Si7021/Adafruit_Si7021.h new file mode 100644 index 0000000..de687d2 --- /dev/null +++ b/lib/Adafruit_Si7021/Adafruit_Si7021.h @@ -0,0 +1,74 @@ +/**************************************************************************/ +/*! + @file Adafruit_Si7021.h + @author Limor Fried (Adafruit Industries) + @license BSD (see license.txt) + + This is a library for the Adafruit Si7021 breakout board + ----> https://www.adafruit.com/products/3251 + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + @section HISTORY + + v1.0 - First release +*/ +/**************************************************************************/ + +#ifndef __Si7021_H__ +#define __Si7021_H__ + +#if ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +/*========================================================================= + I2C ADDRESS/BITS + -----------------------------------------------------------------------*/ +#define SI7021_DEFAULT_ADDRESS (0x40) + +#define SI7021_MEASRH_HOLD_CMD 0xE5 +#define SI7021_MEASRH_NOHOLD_CMD 0xF5 +#define SI7021_MEASTEMP_HOLD_CMD 0xE3 +#define SI7021_MEASTEMP_NOHOLD_CMD 0xF3 +#define SI7021_READPREVTEMP_CMD 0xE0 +#define SI7021_RESET_CMD 0xFE +#define SI7021_WRITERHT_REG_CMD 0xE6 +#define SI7021_READRHT_REG_CMD 0xE7 +#define SI7021_WRITEHEATER_REG_CMD 0x51 +#define SI7021_READHEATER_REG_CMD 0x11 +#define SI7021_ID1_CMD 0xFA0F +#define SI7021_ID2_CMD 0xFCC9 +#define SI7021_FIRMVERS_CMD 0x84B8 + + +/*=========================================================================*/ + +class Adafruit_Si7021 { + public: + Adafruit_Si7021(void); + bool begin(void); + + float readTemperature(void); + void reset(void); + void readSerialNumber(void); + float readHumidity(void); + + uint32_t sernum_a, sernum_b; + + private: + + uint8_t readRegister8(uint8_t reg); + uint16_t readRegister16(uint8_t reg); + void writeRegister8(uint8_t reg, uint8_t value); + + int8_t _i2caddr; +}; + +/**************************************************************************/ + +#endif // __Si7021_H__ diff --git a/lib/Adafruit_Si7021/README.md b/lib/Adafruit_Si7021/README.md new file mode 100644 index 0000000..4cfd83b --- /dev/null +++ b/lib/Adafruit_Si7021/README.md @@ -0,0 +1,23 @@ +Adafruit Si7021 +=============== + +Driver for Adafruit's Si7021 humidity / temp sensor breakout + +Designed specifically to work with the Si7021 breakout in the adafruit shop + + * https://www.adafruit.com/products/3251 + +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! + +Check out the links above for our tutorials and wiring diagrams + +Written by Limor Fried/Ladyada for Adafruit Industries. +BSD license, all text above must be included in any redistribution + +To download. click the ZIP button on the right, rename the uncompressed folder Adafruit_Si7021. Check that the Adafruit_Si7021 folder contains Adafruit_Si7021.cpp and Adafruit_Si7021.h + +Place the Adafruit_Si7021 library folder your arduinosketchfolder/libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE. diff --git a/lib/Adafruit_Si7021/examples/si7021.ino b/lib/Adafruit_Si7021/examples/si7021.ino new file mode 100644 index 0000000..4101caf --- /dev/null +++ b/lib/Adafruit_Si7021/examples/si7021.ino @@ -0,0 +1,25 @@ +#include "Adafruit_Si7021.h" + +Adafruit_Si7021 sensor = Adafruit_Si7021(); + +void setup() { + Serial.begin(115200); + + // wait for serial port to open + while (!Serial) { + delay(10); + } + + Serial.println("Si7021 test!"); + + if (!sensor.begin()) { + Serial.println("Did not find Si7021 sensor!"); + while (true); + } +} + +void loop() { + Serial.print("Humidity: "); Serial.print(sensor.readHumidity(), 2); + Serial.print("\tTemperature: "); Serial.println(sensor.readTemperature(), 2); + delay(1000); +} diff --git a/lib/Adafruit_Si7021/library.properties b/lib/Adafruit_Si7021/library.properties new file mode 100644 index 0000000..2ebf00d --- /dev/null +++ b/lib/Adafruit_Si7021/library.properties @@ -0,0 +1,9 @@ +name=Adafruit Si7021 Library +version=1.0.1 +author=Adafruit +maintainer=Adafruit +sentence=Arduino library for Si7021 sensors. +paragraph=Arduino library for Si7021 temperature + humidity sensors. +category=Sensors +url=https://github.com/adafruit/Adafruit_Si7021 +architectures=* diff --git a/lib/Adafruit_TCS34725/Adafruit_TCS34725.cpp b/lib/Adafruit_TCS34725/Adafruit_TCS34725.cpp new file mode 100644 index 0000000..a92ec43 --- /dev/null +++ b/lib/Adafruit_TCS34725/Adafruit_TCS34725.cpp @@ -0,0 +1,601 @@ +/*! + * @file Adafruit_TCS34725.cpp + * + * @mainpage Driver for the TCS34725 digital color sensors. + * + * @section intro_sec Introduction + * + * 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 + * + * KTOWN (Adafruit Industries) + * + * @section license License + * + * BSD (see license.txt) + * + * @section HISTORY + * + * v1.0 - First release + */ +#ifdef __AVR +#include +#elif defined(ESP8266) +#include +#endif +#include +#include + +#include "Adafruit_TCS34725.h" + +/*! + * @brief Implements missing powf function + * @param x + * Base number + * @param y + * Exponent + * @return x raised to the power of y + */ +float powf(const float x, const float y) { + return (float)(pow((double)x, (double)y)); +} + +/*! + * @brief Writes a register and an 8 bit value over I2C + * @param reg + * @param value + */ +void Adafruit_TCS34725::write8(uint8_t reg, uint32_t value) { + _wire->beginTransmission(_i2caddr); +#if ARDUINO >= 100 + _wire->write(TCS34725_COMMAND_BIT | reg); + _wire->write(value & 0xFF); +#else + _wire->send(TCS34725_COMMAND_BIT | reg); + _wire->send(value & 0xFF); +#endif + _wire->endTransmission(); +} + +/*! + * @brief Reads an 8 bit value over I2C + * @param reg + * @return value + */ +uint8_t Adafruit_TCS34725::read8(uint8_t reg) { + _wire->beginTransmission(_i2caddr); +#if ARDUINO >= 100 + _wire->write(TCS34725_COMMAND_BIT | reg); +#else + _wire->send(TCS34725_COMMAND_BIT | reg); +#endif + _wire->endTransmission(); + + _wire->requestFrom(_i2caddr, 1); +#if ARDUINO >= 100 + return _wire->read(); +#else + return _wire->receive(); +#endif +} + +/*! + * @brief Reads a 16 bit values over I2C + * @param reg + * @return value + */ +uint16_t Adafruit_TCS34725::read16(uint8_t reg) { + uint16_t x; + uint16_t t; + + _wire->beginTransmission(_i2caddr); +#if ARDUINO >= 100 + _wire->write(TCS34725_COMMAND_BIT | reg); +#else + _wire->send(TCS34725_COMMAND_BIT | reg); +#endif + _wire->endTransmission(); + + _wire->requestFrom(_i2caddr, 2); +#if ARDUINO >= 100 + t = _wire->read(); + x = _wire->read(); +#else + t = _wire->receive(); + x = _wire->receive(); +#endif + x <<= 8; + x |= t; + return x; +} + +/*! + * @brief Enables the device + */ +void Adafruit_TCS34725::enable() { + write8(TCS34725_ENABLE, TCS34725_ENABLE_PON); + delay(3); + write8(TCS34725_ENABLE, TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN); + /* Set a delay for the integration time. + This is only necessary in the case where enabling and then + immediately trying to read values back. This is because setting + AEN triggers an automatic integration, so if a read RGBC is + performed too quickly, the data is not yet valid and all 0's are + returned */ + switch (_tcs34725IntegrationTime) { + case TCS34725_INTEGRATIONTIME_2_4MS: + delay(3); + break; + case TCS34725_INTEGRATIONTIME_24MS: + delay(24); + break; + case TCS34725_INTEGRATIONTIME_50MS: + delay(50); + break; + case TCS34725_INTEGRATIONTIME_101MS: + delay(101); + break; + case TCS34725_INTEGRATIONTIME_154MS: + delay(154); + break; + case TCS34725_INTEGRATIONTIME_700MS: + delay(700); + break; + } +} + +/*! + * @brief Disables the device (putting it in lower power sleep mode) + */ +void Adafruit_TCS34725::disable() { + /* Turn the device off to save power */ + uint8_t reg = 0; + reg = read8(TCS34725_ENABLE); + write8(TCS34725_ENABLE, reg & ~(TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN)); +} + +/*! + * @brief Constructor + * @param it + * Integration Time + * @param gain + * Gain + */ +Adafruit_TCS34725::Adafruit_TCS34725(tcs34725IntegrationTime_t it, + tcs34725Gain_t gain) { + _tcs34725Initialised = false; + _tcs34725IntegrationTime = it; + _tcs34725Gain = gain; +} + +/*! + * @brief Initializes I2C and configures the sensor + * @param addr + * i2c address + * @return True if initialization was successful, otherwise false. + */ +boolean Adafruit_TCS34725::begin(uint8_t addr) { + _i2caddr = addr; + _wire = &Wire; + + return init(); +} + +/*! + * @brief Initializes I2C and configures the sensor + * @param addr + * i2c address + * @param *theWire + * The Wire object + * @return True if initialization was successful, otherwise false. + */ +boolean Adafruit_TCS34725::begin(uint8_t addr, TwoWire *theWire) { + _i2caddr = addr; + _wire = theWire; + + return init(); +} + +/*! + * @brief Initializes I2C and configures the sensor + * @return True if initialization was successful, otherwise false. + */ +boolean Adafruit_TCS34725::begin() { + _i2caddr = TCS34725_ADDRESS; + _wire = &Wire; + + return init(); +} + +/*! + * @brief Part of begin + * @return True if initialization was successful, otherwise false. + */ +boolean Adafruit_TCS34725::init() { + _wire->begin(); + + /* Make sure we're actually connected */ + uint8_t x = read8(TCS34725_ID); + if ((x != 0x44) && (x != 0x10)) { + return false; + } + _tcs34725Initialised = true; + + /* Set default integration time and gain */ + setIntegrationTime(_tcs34725IntegrationTime); + setGain(_tcs34725Gain); + + /* Note: by default, the device is in power down mode on bootup */ + enable(); + + return true; +} + +/*! + * @brief Sets the integration time for the TC34725 + * @param it + * Integration Time + */ +void Adafruit_TCS34725::setIntegrationTime(tcs34725IntegrationTime_t it) { + if (!_tcs34725Initialised) + begin(); + + /* Update the timing register */ + write8(TCS34725_ATIME, it); + + /* Update value placeholders */ + _tcs34725IntegrationTime = it; +} + +/*! + * @brief Adjusts the gain on the TCS34725 + * @param gain + * Gain (sensitivity to light) + */ +void Adafruit_TCS34725::setGain(tcs34725Gain_t gain) { + if (!_tcs34725Initialised) + begin(); + + /* Update the timing register */ + write8(TCS34725_CONTROL, gain); + + /* Update value placeholders */ + _tcs34725Gain = gain; +} + +/*! + * @brief Reads the raw red, green, blue and clear channel values + * @param *r + * Red value + * @param *g + * Green value + * @param *b + * Blue value + * @param *c + * Clear channel value + */ +void Adafruit_TCS34725::getRawData(uint16_t *r, uint16_t *g, uint16_t *b, + uint16_t *c) { + if (!_tcs34725Initialised) + begin(); + + *c = read16(TCS34725_CDATAL); + *r = read16(TCS34725_RDATAL); + *g = read16(TCS34725_GDATAL); + *b = read16(TCS34725_BDATAL); + + /* Set a delay for the integration time */ + switch (_tcs34725IntegrationTime) { + case TCS34725_INTEGRATIONTIME_2_4MS: + delay(3); + break; + case TCS34725_INTEGRATIONTIME_24MS: + delay(24); + break; + case TCS34725_INTEGRATIONTIME_50MS: + delay(50); + break; + case TCS34725_INTEGRATIONTIME_101MS: + delay(101); + break; + case TCS34725_INTEGRATIONTIME_154MS: + delay(154); + break; + case TCS34725_INTEGRATIONTIME_700MS: + delay(700); + break; + } +} + +/*! + * @brief Reads the raw red, green, blue and clear channel values in + * one-shot mode (e.g., wakes from sleep, takes measurement, enters + * sleep) + * @param *r + * Red value + * @param *g + * Green value + * @param *b + * Blue value + * @param *c + * Clear channel value + */ +void Adafruit_TCS34725::getRawDataOneShot(uint16_t *r, uint16_t *g, uint16_t *b, + uint16_t *c) { + if (!_tcs34725Initialised) + begin(); + + enable(); + getRawData(r, g, b, c); + disable(); +} + +/*! + * @brief Read the RGB color detected by the sensor. + * @param *r + * Red value normalized to 0-255 + * @param *g + * Green value normalized to 0-255 + * @param *b + * Blue value normalized to 0-255 + */ +void Adafruit_TCS34725::getRGB(float *r, float *g, float *b) { + uint16_t red, green, blue, clear; + getRawData(&red, &green, &blue, &clear); + uint32_t sum = clear; + + // Avoid divide by zero errors ... if clear = 0 return black + if (clear == 0) { + *r = *g = *b = 0; + return; + } + + *r = (float)red / sum * 255.0; + *g = (float)green / sum * 255.0; + *b = (float)blue / sum * 255.0; +} + +/*! + * @brief Converts the raw R/G/B values to color temperature in degrees Kelvin + * @param r + * Red value + * @param g + * Green value + * @param b + * Blue value + * @return Color temperature in degrees Kelvin + */ +uint16_t Adafruit_TCS34725::calculateColorTemperature(uint16_t r, uint16_t g, + uint16_t b) { + float X, Y, Z; /* RGB to XYZ correlation */ + float xc, yc; /* Chromaticity co-ordinates */ + float n; /* McCamy's formula */ + float cct; + + /* 1. Map RGB values to their XYZ counterparts. */ + /* Based on 6500K fluorescent, 3000K fluorescent */ + /* and 60W incandescent values for a wide range. */ + /* Note: Y = Illuminance or lux */ + X = (-0.14282F * r) + (1.54924F * g) + (-0.95641F * b); + Y = (-0.32466F * r) + (1.57837F * g) + (-0.73191F * b); + Z = (-0.68202F * r) + (0.77073F * g) + (0.56332F * b); + + /* 2. Calculate the chromaticity co-ordinates */ + xc = (X) / (X + Y + Z); + yc = (Y) / (X + Y + Z); + + /* 3. Use McCamy's formula to determine the CCT */ + n = (xc - 0.3320F) / (0.1858F - yc); + + /* Calculate the final CCT */ + cct = + (449.0F * powf(n, 3)) + (3525.0F * powf(n, 2)) + (6823.3F * n) + 5520.33F; + + /* Return the results in degrees Kelvin */ + return (uint16_t)cct; +} + +/*! + * @brief Converts the raw R/G/B values to color temperature in degrees + * Kelvin using the algorithm described in DN40 from Taos (now AMS). + * @param r + * Red value + * @param g + * Green value + * @param b + * Blue value + * @param c + * Clear channel value + * @return Color temperature in degrees Kelvin + */ +uint16_t Adafruit_TCS34725::calculateColorTemperature_dn40(uint16_t r, + uint16_t g, + uint16_t b, + uint16_t c) { + int rc; /* Error return code */ + uint16_t r2, g2, b2; /* RGB values minus IR component */ + int gl; /* Results of the initial lux conversion */ + uint8_t gain_int; /* Gain multiplier as a normal integer */ + uint16_t sat; /* Digital saturation level */ + uint16_t ir; /* Inferred IR content */ + + /* Analog/Digital saturation: + * + * (a) As light becomes brighter, the clear channel will tend to + * saturate first since R+G+B is approximately equal to C. + * (b) The TCS34725 accumulates 1024 counts per 2.4ms of integration + * time, up to a maximum values of 65535. This means analog + * saturation can occur up to an integration time of 153.6ms + * (64*2.4ms=153.6ms). + * (c) If the integration time is > 153.6ms, digital saturation will + * occur before analog saturation. Digital saturation occurs when + * the count reaches 65535. + */ + if ((256 - _tcs34725IntegrationTime) > 63) { + /* Track digital saturation */ + sat = 65535; + } else { + /* Track analog saturation */ + sat = 1024 * (256 - _tcs34725IntegrationTime); + } + + /* Ripple rejection: + * + * (a) An integration time of 50ms or multiples of 50ms are required to + * reject both 50Hz and 60Hz ripple. + * (b) If an integration time faster than 50ms is required, you may need + * to average a number of samples over a 50ms period to reject ripple + * from fluorescent and incandescent light sources. + * + * Ripple saturation notes: + * + * (a) If there is ripple in the received signal, the value read from C + * will be less than the max, but still have some effects of being + * saturated. This means that you can be below the 'sat' value, but + * still be saturating. At integration times >150ms this can be + * ignored, but <= 150ms you should calculate the 75% saturation + * level to avoid this problem. + */ + if ((256 - _tcs34725IntegrationTime) <= 63) { + /* Adjust sat to 75% to avoid analog saturation if atime < 153.6ms */ + sat -= sat / 4; + } + + /* Check for saturation and mark the sample as invalid if true */ + if (c >= sat) { + return 0; + } + + /* AMS RGB sensors have no IR channel, so the IR content must be */ + /* calculated indirectly. */ + ir = (r + g + b > c) ? (r + g + b - c) / 2 : 0; + + /* Remove the IR component from the raw RGB values */ + r2 = r - ir; + g2 = g - ir; + b2 = b - ir; + + /* Convert gain to a usable integer value */ + switch (_tcs34725Gain) { + case TCS34725_GAIN_4X: /* GAIN 4X */ + gain_int = 4; + break; + case TCS34725_GAIN_16X: /* GAIN 16X */ + gain_int = 16; + break; + case TCS34725_GAIN_60X: /* GAIN 60X */ + gain_int = 60; + break; + case TCS34725_GAIN_1X: /* GAIN 1X */ + default: + gain_int = 1; + break; + } + + /* Calculate the counts per lux (CPL), taking into account the optional + * arguments for Glass Attenuation (GA) and Device Factor (DF). + * + * GA = 1/T where T is glass transmissivity, meaning if glass is 50% + * transmissive, the GA is 2 (1/0.5=2), and if the glass attenuates light + * 95% the GA is 20 (1/0.05). A GA of 1.0 assumes perfect transmission. + * + * NOTE: It is recommended to have a CPL > 5 to have a lux accuracy + * < +/- 0.5 lux, where the digitization error can be calculated via: + * 'DER = (+/-2) / CPL'. + */ + float cpl = + (((256 - _tcs34725IntegrationTime) * 2.4f) * gain_int) / (1.0f * 310.0f); + + /* Determine lux accuracy (+/- lux) */ + float der = 2.0f / cpl; + + /* Determine the maximum lux value */ + float max_lux = 65535.0 / (cpl * 3); + + /* Lux is a function of the IR-compensated RGB channels and the associated + * color coefficients, with G having a particularly heavy influence to + * match the nature of the human eye. + * + * NOTE: The green value should be > 10 to ensure the accuracy of the lux + * conversions. If it is below 10, the gain should be increased, but + * the clear<100 check earlier should cover this edge case. + */ + gl = 0.136f * (float)r2 + /** Red coefficient. */ + 1.000f * (float)g2 + /** Green coefficient. */ + -0.444f * (float)b2; /** Blue coefficient. */ + + float lux = gl / cpl; + + /* A simple method of measuring color temp is to use the ratio of blue */ + /* to red light, taking IR cancellation into account. */ + uint16_t cct = (3810 * (uint32_t)b2) / /** Color temp coefficient. */ + (uint32_t)r2 + + 1391; /** Color temp offset. */ + + return cct; +} + +/*! + * @brief Converts the raw R/G/B values to lux + * @param r + * Red value + * @param g + * Green value + * @param b + * Blue value + * @return Lux value + */ +uint16_t Adafruit_TCS34725::calculateLux(uint16_t r, uint16_t g, uint16_t b) { + float illuminance; + + /* This only uses RGB ... how can we integrate clear or calculate lux */ + /* based exclusively on clear since this might be more reliable? */ + illuminance = (-0.32466F * r) + (1.57837F * g) + (-0.73191F * b); + + return (uint16_t)illuminance; +} + +/*! + * @brief Sets inerrupt for TCS34725 + * @param i + * Interrupt (True/False) + */ +void Adafruit_TCS34725::setInterrupt(boolean i) { + uint8_t r = read8(TCS34725_ENABLE); + if (i) { + r |= TCS34725_ENABLE_AIEN; + } else { + r &= ~TCS34725_ENABLE_AIEN; + } + write8(TCS34725_ENABLE, r); +} + +/*! + * @brief Clears inerrupt for TCS34725 + */ +void Adafruit_TCS34725::clearInterrupt() { + _wire->beginTransmission(_i2caddr); +#if ARDUINO >= 100 + _wire->write(TCS34725_COMMAND_BIT | 0x66); +#else + _wire->send(TCS34725_COMMAND_BIT | 0x66); +#endif + _wire->endTransmission(); +} + +/*! + * @brief Sets inerrupt limits + * @param low + * Low limit + * @param high + * High limit + */ +void Adafruit_TCS34725::setIntLimits(uint16_t low, uint16_t high) { + write8(0x04, low & 0xFF); + write8(0x05, low >> 8); + write8(0x06, high & 0xFF); + write8(0x07, high >> 8); +} diff --git a/lib/Adafruit_TCS34725/Adafruit_TCS34725.h b/lib/Adafruit_TCS34725/Adafruit_TCS34725.h new file mode 100644 index 0000000..260366c --- /dev/null +++ b/lib/Adafruit_TCS34725/Adafruit_TCS34725.h @@ -0,0 +1,204 @@ +/*! + * @file Adafruit_TCS34725.h + * + * Software License Agreement (BSD License) + * + * Copyright (c) 2013, 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. + */ +#ifndef _TCS34725_H_ +#define _TCS34725_H_ + +#if ARDUINO >= 100 +#include +#else +#include +#endif + +#include + +#define TCS34725_ADDRESS (0x29) /**< I2C address **/ +#define TCS34725_COMMAND_BIT (0x80) /**< Command bit **/ +#define TCS34725_ENABLE (0x00) /**< Interrupt Enable register */ +#define TCS34725_ENABLE_AIEN (0x10) /**< RGBC Interrupt Enable */ +#define TCS34725_ENABLE_WEN \ + (0x08) /**< Wait Enable - Writing 1 activates the wait timer */ +#define TCS34725_ENABLE_AEN \ + (0x02) /**< RGBC Enable - Writing 1 actives the ADC, 0 disables it */ +#define TCS34725_ENABLE_PON \ + (0x01) /**< Power on - Writing 1 activates the internal oscillator, 0 \ + disables it */ +#define TCS34725_ATIME (0x01) /**< Integration time */ +#define TCS34725_WTIME \ + (0x03) /**< Wait time (if TCS34725_ENABLE_WEN is asserted) */ +#define TCS34725_WTIME_2_4MS (0xFF) /**< WLONG0 = 2.4ms WLONG1 = 0.029s */ +#define TCS34725_WTIME_204MS (0xAB) /**< WLONG0 = 204ms WLONG1 = 2.45s */ +#define TCS34725_WTIME_614MS (0x00) /**< WLONG0 = 614ms WLONG1 = 7.4s */ +#define TCS34725_AILTL \ + (0x04) /**< Clear channel lower interrupt threshold (lower byte) */ +#define TCS34725_AILTH \ + (0x05) /**< Clear channel lower interrupt threshold (higher byte) */ +#define TCS34725_AIHTL \ + (0x06) /**< Clear channel upper interrupt threshold (lower byte) */ +#define TCS34725_AIHTH \ + (0x07) /**< Clear channel upper interrupt threshold (higher byte) */ +#define TCS34725_PERS \ + (0x0C) /**< Persistence register - basic SW filtering mechanism for \ + interrupts */ +#define TCS34725_PERS_NONE \ + (0b0000) /**< Every RGBC cycle generates an interrupt */ +#define TCS34725_PERS_1_CYCLE \ + (0b0001) /**< 1 clean channel value outside threshold range generates an \ + interrupt */ +#define TCS34725_PERS_2_CYCLE \ + (0b0010) /**< 2 clean channel values outside threshold range generates an \ + interrupt */ +#define TCS34725_PERS_3_CYCLE \ + (0b0011) /**< 3 clean channel values outside threshold range generates an \ + interrupt */ +#define TCS34725_PERS_5_CYCLE \ + (0b0100) /**< 5 clean channel values outside threshold range generates an \ + interrupt */ +#define TCS34725_PERS_10_CYCLE \ + (0b0101) /**< 10 clean channel values outside threshold range generates an \ + interrupt*/ +#define TCS34725_PERS_15_CYCLE \ + (0b0110) /**< 15 clean channel values outside threshold range generates an \ + interrupt*/ +#define TCS34725_PERS_20_CYCLE \ + (0b0111) /**< 20 clean channel values outside threshold range generates an \ + interrupt*/ +#define TCS34725_PERS_25_CYCLE \ + (0b1000) /**< 25 clean channel values outside threshold range generates an \ + interrupt*/ +#define TCS34725_PERS_30_CYCLE \ + (0b1001) /**< 30 clean channel values outside threshold range generates an \ + interrupt*/ +#define TCS34725_PERS_35_CYCLE \ + (0b1010) /**< 35 clean channel values outside threshold range generates an \ + interrupt*/ +#define TCS34725_PERS_40_CYCLE \ + (0b1011) /**< 40 clean channel values outside threshold range generates an \ + interrupt*/ +#define TCS34725_PERS_45_CYCLE \ + (0b1100) /**< 45 clean channel values outside threshold range generates an \ + interrupt*/ +#define TCS34725_PERS_50_CYCLE \ + (0b1101) /**< 50 clean channel values outside threshold range generates an \ + interrupt*/ +#define TCS34725_PERS_55_CYCLE \ + (0b1110) /**< 55 clean channel values outside threshold range generates an \ + interrupt*/ +#define TCS34725_PERS_60_CYCLE \ + (0b1111) /**< 60 clean channel values outside threshold range generates an \ + interrupt*/ +#define TCS34725_CONFIG (0x0D) /**< Configuration **/ +#define TCS34725_CONFIG_WLONG \ + (0x02) /**< Choose between short and long (12x) wait times via \ + TCS34725_WTIME */ +#define TCS34725_CONTROL (0x0F) /**< Set the gain level for the sensor */ +#define TCS34725_ID \ + (0x12) /**< 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727 */ +#define TCS34725_STATUS (0x13) /**< Device status **/ +#define TCS34725_STATUS_AINT (0x10) /**< RGBC Clean channel interrupt */ +#define TCS34725_STATUS_AVALID \ + (0x01) /**< Indicates that the RGBC channels have completed an integration \ + cycle */ +#define TCS34725_CDATAL (0x14) /**< Clear channel data low byte */ +#define TCS34725_CDATAH (0x15) /**< Clear channel data high byte */ +#define TCS34725_RDATAL (0x16) /**< Red channel data low byte */ +#define TCS34725_RDATAH (0x17) /**< Red channel data high byte */ +#define TCS34725_GDATAL (0x18) /**< Green channel data low byte */ +#define TCS34725_GDATAH (0x19) /**< Green channel data high byte */ +#define TCS34725_BDATAL (0x1A) /**< Blue channel data low byte */ +#define TCS34725_BDATAH (0x1B) /**< Blue channel data high byte */ + +/** Integration time settings for TCS34725 */ +typedef enum { + TCS34725_INTEGRATIONTIME_2_4MS = + 0xFF, /**< 2.4ms - 1 cycle - Max Count: 1024 */ + TCS34725_INTEGRATIONTIME_24MS = + 0xF6, /**< 24ms - 10 cycles - Max Count: 10240 */ + TCS34725_INTEGRATIONTIME_50MS = + 0xEB, /**< 50ms - 20 cycles - Max Count: 20480 */ + TCS34725_INTEGRATIONTIME_101MS = + 0xD5, /**< 101ms - 42 cycles - Max Count: 43008 */ + TCS34725_INTEGRATIONTIME_154MS = + 0xC0, /**< 154ms - 64 cycles - Max Count: 65535 */ + TCS34725_INTEGRATIONTIME_700MS = + 0x00 /**< 700ms - 256 cycles - Max Count: 65535 */ +} tcs34725IntegrationTime_t; + +/** Gain settings for TCS34725 */ +typedef enum { + TCS34725_GAIN_1X = 0x00, /**< No gain */ + TCS34725_GAIN_4X = 0x01, /**< 4x gain */ + TCS34725_GAIN_16X = 0x02, /**< 16x gain */ + TCS34725_GAIN_60X = 0x03 /**< 60x gain */ +} tcs34725Gain_t; + +/*! + * @brief Class that stores state and functions for interacting with + * TCS34725 Color Sensor + */ +class Adafruit_TCS34725 { +public: + Adafruit_TCS34725(tcs34725IntegrationTime_t = TCS34725_INTEGRATIONTIME_2_4MS, + tcs34725Gain_t = TCS34725_GAIN_1X); + + boolean begin(uint8_t addr, TwoWire *theWire); + boolean begin(uint8_t addr); + boolean begin(); + boolean init(); + + void setIntegrationTime(tcs34725IntegrationTime_t it); + void setGain(tcs34725Gain_t gain); + void getRawData(uint16_t *r, uint16_t *g, uint16_t *b, uint16_t *c); + void getRGB(float *r, float *g, float *b); + void getRawDataOneShot(uint16_t *r, uint16_t *g, uint16_t *b, uint16_t *c); + uint16_t calculateColorTemperature(uint16_t r, uint16_t g, uint16_t b); + uint16_t calculateColorTemperature_dn40(uint16_t r, uint16_t g, uint16_t b, + uint16_t c); + uint16_t calculateLux(uint16_t r, uint16_t g, uint16_t b); + void write8(uint8_t reg, uint32_t value); + uint8_t read8(uint8_t reg); + uint16_t read16(uint8_t reg); + void setInterrupt(boolean flag); + void clearInterrupt(); + void setIntLimits(uint16_t l, uint16_t h); + void enable(); + void disable(); + +private: + TwoWire *_wire; + uint8_t _i2caddr; + boolean _tcs34725Initialised; + tcs34725Gain_t _tcs34725Gain; + tcs34725IntegrationTime_t _tcs34725IntegrationTime; +}; + +#endif diff --git a/lib/Adafruit_TCS34725/README.md b/lib/Adafruit_TCS34725/README.md new file mode 100644 index 0000000..175e54c --- /dev/null +++ b/lib/Adafruit_TCS34725/README.md @@ -0,0 +1,21 @@ +# Adafruit TCS34725 Color Sensor Driver [![Build Status](https://travis-ci.com/adafruit/Adafruit_TCS34725.svg?branch=master)](https://travis-ci.com/adafruit/Adafruit_TCS34725) + + + +This driver is for the Adafruit TCS34725 Breakout. + +Tested and works great with the Adafruit MCP9808 Breakout Board +* http://www.adafruit.com/products/1334 + +These modules use 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 (KTOWN) Townsend for Adafruit Industries. +BSD license, check license.txt for more information +All text above must be included in any redistribution + +To install, use the Arduino Library Manager and search for 'Adafruit TCS34725' and install the library diff --git a/lib/Adafruit_TCS34725/assets/board.jpg b/lib/Adafruit_TCS34725/assets/board.jpg new file mode 100644 index 0000000..1d9defa Binary files /dev/null and b/lib/Adafruit_TCS34725/assets/board.jpg differ diff --git a/lib/Adafruit_TCS34725/code-of-conduct.md b/lib/Adafruit_TCS34725/code-of-conduct.md new file mode 100644 index 0000000..8ee6e44 --- /dev/null +++ b/lib/Adafruit_TCS34725/code-of-conduct.md @@ -0,0 +1,127 @@ +# Adafruit Community Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and leaders pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level or type of +experience, education, socio-economic status, nationality, personal appearance, +race, religion, or sexual identity and orientation. + +## Our Standards + +We are committed to providing a friendly, safe and welcoming environment for +all. + +Examples of behavior that contributes to creating a positive environment +include: + +* Be kind and courteous to others +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Collaborating with other community members +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and sexual attention or advances +* The use of inappropriate images, including in a community member's avatar +* The use of inappropriate language, including in a community member's nickname +* Any spamming, flaming, baiting or other attention-stealing behavior +* Excessive or unwelcome helping; answering outside the scope of the question + asked +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate + +The goal of the standards and moderation guidelines outlined here is to build +and maintain a respectful community. We ask that you don’t just aim to be +"technically unimpeachable", but rather try to be your best self. + +We value many things beyond technical expertise, including collaboration and +supporting others within our community. Providing a positive experience for +other community members can have a much more significant impact than simply +providing the correct answer. + +## Our Responsibilities + +Project leaders are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project leaders have the right and responsibility to remove, edit, or +reject messages, comments, commits, code, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any community member for other behaviors that they deem +inappropriate, threatening, offensive, or harmful. + +## Moderation + +Instances of behaviors that violate the Adafruit Community Code of Conduct +may be reported by any member of the community. Community members are +encouraged to report these situations, including situations they witness +involving other community members. + +You may report in the following ways: + +In any situation, you may send an email to . + +On the Adafruit Discord, you may send an open message from any channel +to all Community Helpers by tagging @community helpers. You may also send an +open message from any channel, or a direct message to @kattni#1507, +@tannewt#4653, @Dan Halbert#1614, @cater#2442, @sommersoft#0222, or +@Andon#8175. + +Email and direct message reports will be kept confidential. + +In situations on Discord where the issue is particularly egregious, possibly +illegal, requires immediate action, or violates the Discord terms of service, +you should also report the message directly to Discord. + +These are the steps for upholding our community’s standards of conduct. + +1. Any member of the community may report any situation that violates the +Adafruit Community Code of Conduct. All reports will be reviewed and +investigated. +2. If the behavior is an egregious violation, the community member who +committed the violation may be banned immediately, without warning. +3. Otherwise, moderators will first respond to such behavior with a warning. +4. Moderators follow a soft "three strikes" policy - the community member may +be given another chance, if they are receptive to the warning and change their +behavior. +5. If the community member is unreceptive or unreasonable when warned by a +moderator, or the warning goes unheeded, they may be banned for a first or +second offense. Repeated offenses will result in the community member being +banned. + +## Scope + +This Code of Conduct and the enforcement policies listed above apply to all +Adafruit Community venues. This includes but is not limited to any community +spaces (both public and private), the entire Adafruit Discord server, and +Adafruit GitHub repositories. Examples of Adafruit Community spaces include +but are not limited to meet-ups, audio chats on the Adafruit Discord, or +interaction at a conference. + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. As a community +member, you are representing our community, and are expected to behave +accordingly. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 1.4, available at +, +and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html). + +For other projects adopting the Adafruit Community Code of +Conduct, please contact the maintainers of those projects for enforcement. +If you wish to use this code of conduct for your own project, consider +explicitly mentioning your moderation policy or making a copy with your +own moderation policy so as to avoid confusion. diff --git a/lib/Adafruit_TCS34725/examples/colorview/colorview.ino b/lib/Adafruit_TCS34725/examples/colorview/colorview.ino new file mode 100644 index 0000000..ca4d01b --- /dev/null +++ b/lib/Adafruit_TCS34725/examples/colorview/colorview.ino @@ -0,0 +1,111 @@ +#include +#include "Adafruit_TCS34725.h" + +// Pick analog outputs, for the UNO these three work well +// use ~560 ohm resistor between Red & Blue, ~1K for green (its brighter) +#define redpin 3 +#define greenpin 5 +#define bluepin 6 +// for a common anode LED, connect the common pin to +5V +// for common cathode, connect the common to ground + +// set to false if using a common cathode LED +#define commonAnode true + +// our RGB -> eye-recognized gamma color +byte gammatable[256]; + + +Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X); + +void setup() { + Serial.begin(9600); + //Serial.println("Color View Test!"); + + if (tcs.begin()) { + //Serial.println("Found sensor"); + } else { + Serial.println("No TCS34725 found ... check your connections"); + while (1); // halt! + } + + // use these three pins to drive an LED +#if defined(ARDUINO_ARCH_ESP32) + ledcAttachPin(redpin, 1); + ledcSetup(1, 12000, 8); + ledcAttachPin(greenpin, 2); + ledcSetup(2, 12000, 8); + ledcAttachPin(bluepin, 3); + ledcSetup(3, 12000, 8); +#else + pinMode(redpin, OUTPUT); + pinMode(greenpin, OUTPUT); + pinMode(bluepin, OUTPUT); +#endif + + // thanks PhilB for this gamma table! + // it helps convert RGB colors to what humans see + for (int i=0; i<256; i++) { + float x = i; + x /= 255; + x = pow(x, 2.5); + x *= 255; + + if (commonAnode) { + gammatable[i] = 255 - x; + } else { + gammatable[i] = x; + } + //Serial.println(gammatable[i]); + } +} + +// The commented out code in loop is example of getRawData with clear value. +// Processing example colorview.pde can work with this kind of data too, but It requires manual conversion to +// [0-255] RGB value. You can still uncomments parts of colorview.pde and play with clear value. +void loop() { + float red, green, blue; + + tcs.setInterrupt(false); // turn on LED + + delay(60); // takes 50ms to read + + tcs.getRGB(&red, &green, &blue); + + tcs.setInterrupt(true); // turn off LED + + Serial.print("R:\t"); Serial.print(int(red)); + Serial.print("\tG:\t"); Serial.print(int(green)); + Serial.print("\tB:\t"); Serial.print(int(blue)); + +// Serial.print("\t"); +// Serial.print((int)red, HEX); Serial.print((int)green, HEX); Serial.print((int)blue, HEX); + Serial.print("\n"); + +// uint16_t red, green, blue, clear; +// +// tcs.setInterrupt(false); // turn on LED +// +// delay(60); // takes 50ms to read +// +// tcs.getRawData(&red, &green, &blue, &clear); +// +// tcs.setInterrupt(true); // turn off LED +// +// Serial.print("C:\t"); Serial.print(int(clear)); +// Serial.print("R:\t"); Serial.print(int(red)); +// Serial.print("\tG:\t"); Serial.print(int(green)); +// Serial.print("\tB:\t"); Serial.print(int(blue)); +// Serial.println(); + + +#if defined(ARDUINO_ARCH_ESP32) + ledcWrite(1, gammatable[(int)red]); + ledcWrite(2, gammatable[(int)green]); + ledcWrite(3, gammatable[(int)blue]); +#else + analogWrite(redpin, gammatable[(int)red]); + analogWrite(greenpin, gammatable[(int)green]); + analogWrite(bluepin, gammatable[(int)blue]); +#endif +} diff --git a/lib/Adafruit_TCS34725/examples/colorview/processing/colorview/colorview.pde b/lib/Adafruit_TCS34725/examples/colorview/processing/colorview/colorview.pde new file mode 100644 index 0000000..0326acf --- /dev/null +++ b/lib/Adafruit_TCS34725/examples/colorview/processing/colorview/colorview.pde @@ -0,0 +1,80 @@ +/* For use with the colorview Arduino example sketch + Update the Serial() new call to match your serial port + e.g. COM4, /dev/usbserial, etc! +*/ + + +import processing.serial.*; +import java.awt.datatransfer.*; +import java.awt.Toolkit; + +Serial port; + +void setup(){ + size(200,200); + port = new Serial(this, "COM4", 9600); //remember to replace COM20 with the appropriate serial port on your computer +} + + +String buff = ""; + +int wRed, wGreen, wBlue, wClear; +String hexColor = "ffffff"; + + +void draw(){ + background(wRed,wGreen,wBlue); + // check for serial, and process + while (port.available() > 0) { + serialEvent(port.read()); + } +} + +void serialEvent(int serial) { + if(serial != '\n') { + buff += char(serial); + } else { + //println(buff); + + int cRed = buff.indexOf("R"); + int cGreen = buff.indexOf("G"); + int cBlue = buff.indexOf("B"); + int clear = buff.indexOf("C"); + if(clear >=0){ + String val = buff.substring(clear+3); + val = val.split("\t")[0]; + wClear = Integer.parseInt(val.trim()); + } else { return; } + + if(cRed >=0){ + String val = buff.substring(cRed+3); + val = val.split("\t")[0]; + wRed = Integer.parseInt(val.trim()); + } else { return; } + + if(cGreen >=0) { + String val = buff.substring(cGreen+3); + val = val.split("\t")[0]; + wGreen = Integer.parseInt(val.trim()); + } else { return; } + + if(cBlue >=0) { + String val = buff.substring(cBlue+3); + val = val.split("\t")[0]; + wBlue = Integer.parseInt(val.trim()); + } else { return; } + + print("Red: "); print(wRed); + print("\tGrn: "); print(wGreen); + print("\tBlue: "); print(wBlue); + print("\tClr: "); println(wClear); + + wRed *= 255; wRed /= wClear; + wGreen *= 255; wGreen /= wClear; + wBlue *= 255; wBlue /= wClear; + + hexColor = hex(color(wRed, wGreen, wBlue), 6); + println(hexColor); + buff = ""; + } +} diff --git a/lib/Adafruit_TCS34725/examples/interrupt/interrupt.ino b/lib/Adafruit_TCS34725/examples/interrupt/interrupt.ino new file mode 100644 index 0000000..f3fffdf --- /dev/null +++ b/lib/Adafruit_TCS34725/examples/interrupt/interrupt.ino @@ -0,0 +1,69 @@ +#include +#include + + +/* Initialise with specific int time and gain values */ +Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_700MS, TCS34725_GAIN_1X); +const int interruptPin = 2; +volatile boolean state = false; + + +//Interrupt Service Routine +void isr() +{ + state = true; +} + + +/* tcs.getRawData() does a delay(Integration_Time) after the sensor readout. +We don't need to wait for the next integration cycle because we receive an interrupt when the integration cycle is complete*/ +void getRawData_noDelay(uint16_t *r, uint16_t *g, uint16_t *b, uint16_t *c) +{ + *c = tcs.read16(TCS34725_CDATAL); + *r = tcs.read16(TCS34725_RDATAL); + *g = tcs.read16(TCS34725_GDATAL); + *b = tcs.read16(TCS34725_BDATAL); +} + + +void setup() { + pinMode(interruptPin, INPUT_PULLUP); //TCS interrupt output is Active-LOW and Open-Drain + attachInterrupt(digitalPinToInterrupt(interruptPin), isr, FALLING); + + Serial.begin(9600); + + if (tcs.begin()) { + Serial.println("Found sensor"); + } else { + Serial.println("No TCS34725 found ... check your connections"); + while (1); + } + + // Set persistence filter to generate an interrupt for every RGB Cycle, regardless of the integration limits + tcs.write8(TCS34725_PERS, TCS34725_PERS_NONE); + tcs.setInterrupt(true); + + Serial.flush(); +} + + +void loop() { + if (state) { + uint16_t r, g, b, c, colorTemp, lux; + getRawData_noDelay(&r, &g, &b, &c); + colorTemp = tcs.calculateColorTemperature(r, g, b); + lux = tcs.calculateLux(r, g, b); + + Serial.print("Color Temp: "); Serial.print(colorTemp, DEC); Serial.print(" K - "); + Serial.print("Lux: "); Serial.print(lux, DEC); Serial.print(" - "); + Serial.print("R: "); Serial.print(r, DEC); Serial.print(" "); + Serial.print("G: "); Serial.print(g, DEC); Serial.print(" "); + Serial.print("B: "); Serial.print(b, DEC); Serial.print(" "); + Serial.print("C: "); Serial.print(c, DEC); Serial.print(" "); + Serial.println(" "); + Serial.flush(); + + tcs.clearInterrupt(); + state = false; + } +} diff --git a/lib/Adafruit_TCS34725/examples/tcs34725/tcs34725.ino b/lib/Adafruit_TCS34725/examples/tcs34725/tcs34725.ino new file mode 100644 index 0000000..56b15f7 --- /dev/null +++ b/lib/Adafruit_TCS34725/examples/tcs34725/tcs34725.ino @@ -0,0 +1,45 @@ +#include +#include "Adafruit_TCS34725.h" + +/* Example code for the Adafruit TCS34725 breakout library */ + +/* Connect SCL to analog 5 + Connect SDA to analog 4 + Connect VDD to 3.3V DC + Connect GROUND to common ground */ + +/* Initialise with default values (int time = 2.4ms, gain = 1x) */ +// Adafruit_TCS34725 tcs = Adafruit_TCS34725(); + +/* Initialise with specific int time and gain values */ +Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_700MS, TCS34725_GAIN_1X); + +void setup(void) { + Serial.begin(9600); + + if (tcs.begin()) { + Serial.println("Found sensor"); + } else { + Serial.println("No TCS34725 found ... check your connections"); + while (1); + } + + // Now we're ready to get readings! +} + +void loop(void) { + uint16_t r, g, b, c, colorTemp, lux; + + tcs.getRawData(&r, &g, &b, &c); + // colorTemp = tcs.calculateColorTemperature(r, g, b); + colorTemp = tcs.calculateColorTemperature_dn40(r, g, b, c); + lux = tcs.calculateLux(r, g, b); + + Serial.print("Color Temp: "); Serial.print(colorTemp, DEC); Serial.print(" K - "); + Serial.print("Lux: "); Serial.print(lux, DEC); Serial.print(" - "); + Serial.print("R: "); Serial.print(r, DEC); Serial.print(" "); + Serial.print("G: "); Serial.print(g, DEC); Serial.print(" "); + Serial.print("B: "); Serial.print(b, DEC); Serial.print(" "); + Serial.print("C: "); Serial.print(c, DEC); Serial.print(" "); + Serial.println(" "); +} diff --git a/lib/Adafruit_TCS34725/examples/tcs34725/tcs34725.pde b/lib/Adafruit_TCS34725/examples/tcs34725/tcs34725.pde new file mode 100644 index 0000000..d1b4c6a --- /dev/null +++ b/lib/Adafruit_TCS34725/examples/tcs34725/tcs34725.pde @@ -0,0 +1,44 @@ +#include +#include "Adafruit_TCS34725.h" + +/* Example code for the Adafruit TCS34725 breakout library */ + +/* Connect SCL to analog 5 + Connect SDA to analog 4 + Connect VDD to 3.3V DC + Connect GROUND to common ground */ + +/* Initialise with default values (int time = 2.4ms, gain = 1x) */ +// Adafruit_TCS34725 tcs = Adafruit_TCS34725(); + +/* Initialise with specific int time and gain values */ +Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_700MS, TCS34725_GAIN_1X); + +void setup(void) { + Serial.begin(9600); + + if (tcs.begin()) { + Serial.println("Found sensor"); + } else { + Serial.println("No TCS34725 found ... check your connections"); + while (1); + } + + // Now we're ready to get readings! +} + +void loop(void) { + uint16_t r, g, b, c, colorTemp, lux; + + tcs.getRawData(&r, &g, &b, &c); + colorTemp = tcs.calculateColorTemperature(r, g, b); + lux = tcs.calculateLux(r, g, b); + + Serial.print("Color Temp: "); Serial.print(colorTemp, DEC); Serial.print(" K - "); + Serial.print("Lux: "); Serial.print(lux, DEC); Serial.print(" - "); + Serial.print("R: "); Serial.print(r, DEC); Serial.print(" "); + Serial.print("G: "); Serial.print(g, DEC); Serial.print(" "); + Serial.print("B: "); Serial.print(b, DEC); Serial.print(" "); + Serial.print("C: "); Serial.print(c, DEC); Serial.print(" "); + Serial.println(" "); +} diff --git a/lib/Adafruit_TCS34725/examples/tcs34725autorange/tcs34725autorange.ino b/lib/Adafruit_TCS34725/examples/tcs34725autorange/tcs34725autorange.ino new file mode 100644 index 0000000..9e18c39 --- /dev/null +++ b/lib/Adafruit_TCS34725/examples/tcs34725autorange/tcs34725autorange.ino @@ -0,0 +1,211 @@ +#include +#include "Adafruit_TCS34725.h" + +// +// An experimental wrapper class that implements the improved lux and color temperature from +// TAOS and a basic autorange mechanism. +// +// Written by ductsoup, public domain +// + +// RGB Color Sensor with IR filter and White LED - TCS34725 +// I2C 7-bit address 0x29, 8-bit address 0x52 +// +// http://www.adafruit.com/product/1334 +// http://learn.adafruit.com/adafruit-color-sensors/overview +// http://www.adafruit.com/datasheets/TCS34725.pdf +// http://www.ams.com/eng/Products/Light-Sensors/Color-Sensor/TCS34725 +// http://www.ams.com/eng/content/view/download/265215 <- DN40, calculations +// http://www.ams.com/eng/content/view/download/181895 <- DN39, some thoughts on autogain +// http://www.ams.com/eng/content/view/download/145158 <- DN25 (original Adafruit calculations) +// +// connect LED to digital 4 or GROUND for ambient light sensing +// connect SCL to analog 5 +// connect SDA to analog 4 +// connect Vin to 3.3-5V DC +// connect GROUND to common ground + +// some magic numbers for this device from the DN40 application note +#define TCS34725_R_Coef 0.136 +#define TCS34725_G_Coef 1.000 +#define TCS34725_B_Coef -0.444 +#define TCS34725_GA 1.0 +#define TCS34725_DF 310.0 +#define TCS34725_CT_Coef 3810.0 +#define TCS34725_CT_Offset 1391.0 + +// Autorange class for TCS34725 +class tcs34725 { +private: + struct tcs_agc { + tcs34725Gain_t ag; + tcs34725IntegrationTime_t at; + uint16_t mincnt; + uint16_t maxcnt; + }; + static const tcs_agc agc_lst[]; + uint16_t agc_cur; + + void setGainTime(void); + Adafruit_TCS34725 tcs; + +public: + tcs34725(void); + + boolean begin(void); + void getData(void); + + boolean isAvailable, isSaturated; + uint16_t againx, atime, atime_ms; + uint16_t r, g, b, c; + uint16_t ir; + uint16_t r_comp, g_comp, b_comp, c_comp; + uint16_t saturation, saturation75; + float cratio, cpl, ct, lux, maxlux; +}; +// +// Gain/time combinations to use and the min/max limits for hysteresis +// that avoid saturation. They should be in order from dim to bright. +// +// Also set the first min count and the last max count to 0 to indicate +// the start and end of the list. +// +const tcs34725::tcs_agc tcs34725::agc_lst[] = { + { TCS34725_GAIN_60X, TCS34725_INTEGRATIONTIME_700MS, 0, 20000 }, + { TCS34725_GAIN_60X, TCS34725_INTEGRATIONTIME_154MS, 4990, 63000 }, + { TCS34725_GAIN_16X, TCS34725_INTEGRATIONTIME_154MS, 16790, 63000 }, + { TCS34725_GAIN_4X, TCS34725_INTEGRATIONTIME_154MS, 15740, 63000 }, + { TCS34725_GAIN_1X, TCS34725_INTEGRATIONTIME_154MS, 15740, 0 } +}; +tcs34725::tcs34725() : agc_cur(0), isAvailable(0), isSaturated(0) { +} + +// initialize the sensor +boolean tcs34725::begin(void) { + tcs = Adafruit_TCS34725(agc_lst[agc_cur].at, agc_lst[agc_cur].ag); + if ((isAvailable = tcs.begin())) + setGainTime(); + return(isAvailable); +} + +// Set the gain and integration time +void tcs34725::setGainTime(void) { + tcs.setGain(agc_lst[agc_cur].ag); + tcs.setIntegrationTime(agc_lst[agc_cur].at); + atime = int(agc_lst[agc_cur].at); + atime_ms = ((256 - atime) * 2.4); + switch(agc_lst[agc_cur].ag) { + case TCS34725_GAIN_1X: + againx = 1; + break; + case TCS34725_GAIN_4X: + againx = 4; + break; + case TCS34725_GAIN_16X: + againx = 16; + break; + case TCS34725_GAIN_60X: + againx = 60; + break; + } +} + +// Retrieve data from the sensor and do the calculations +void tcs34725::getData(void) { + // read the sensor and autorange if necessary + tcs.getRawData(&r, &g, &b, &c); + while(1) { + if (agc_lst[agc_cur].maxcnt && c > agc_lst[agc_cur].maxcnt) + agc_cur++; + else if (agc_lst[agc_cur].mincnt && c < agc_lst[agc_cur].mincnt) + agc_cur--; + else break; + + setGainTime(); + delay((256 - atime) * 2.4 * 2); // shock absorber + tcs.getRawData(&r, &g, &b, &c); + break; + } + + // DN40 calculations + ir = (r + g + b > c) ? (r + g + b - c) / 2 : 0; + r_comp = r - ir; + g_comp = g - ir; + b_comp = b - ir; + c_comp = c - ir; + cratio = float(ir) / float(c); + + saturation = ((256 - atime) > 63) ? 65535 : 1024 * (256 - atime); + saturation75 = (atime_ms < 150) ? (saturation - saturation / 4) : saturation; + isSaturated = (atime_ms < 150 && c > saturation75) ? 1 : 0; + cpl = (atime_ms * againx) / (TCS34725_GA * TCS34725_DF); + maxlux = 65535 / (cpl * 3); + + lux = (TCS34725_R_Coef * float(r_comp) + TCS34725_G_Coef * float(g_comp) + TCS34725_B_Coef * float(b_comp)) / cpl; + ct = TCS34725_CT_Coef * float(b_comp) / float(r_comp) + TCS34725_CT_Offset; +} + +tcs34725 rgb_sensor; + +void setup(void) { + Serial.begin(115200); + rgb_sensor.begin(); + pinMode(4, OUTPUT); + digitalWrite(4, LOW); // @gremlins Bright light, bright light! +} + +void loop(void) { + rgb_sensor.getData(); + Serial.print(F("Gain:")); + Serial.print(rgb_sensor.againx); + Serial.print(F("x ")); + Serial.print(F("Time:")); + Serial.print(rgb_sensor.atime_ms); + Serial.print(F("ms (0x")); + Serial.print(rgb_sensor.atime, HEX); + Serial.println(F(")")); + + Serial.print(F("Raw R:")); + Serial.print(rgb_sensor.r); + Serial.print(F(" G:")); + Serial.print(rgb_sensor.g); + Serial.print(F(" B:")); + Serial.print(rgb_sensor.b); + Serial.print(F(" C:")); + Serial.println(rgb_sensor.c); + + Serial.print(F("IR:")); + Serial.print(rgb_sensor.ir); + Serial.print(F(" CRATIO:")); + Serial.print(rgb_sensor.cratio); + Serial.print(F(" Sat:")); + Serial.print(rgb_sensor.saturation); + Serial.print(F(" Sat75:")); + Serial.print(rgb_sensor.saturation75); + Serial.print(F(" ")); + Serial.println(rgb_sensor.isSaturated ? "*SATURATED*" : ""); + + Serial.print(F("CPL:")); + Serial.print(rgb_sensor.cpl); + Serial.print(F(" Max lux:")); + Serial.println(rgb_sensor.maxlux); + + Serial.print(F("Compensated R:")); + Serial.print(rgb_sensor.r_comp); + Serial.print(F(" G:")); + Serial.print(rgb_sensor.g_comp); + Serial.print(F(" B:")); + Serial.print(rgb_sensor.b_comp); + Serial.print(F(" C:")); + Serial.println(rgb_sensor.c_comp); + + Serial.print(F("Lux:")); + Serial.print(rgb_sensor.lux); + Serial.print(F(" CT:")); + Serial.print(rgb_sensor.ct); + Serial.println(F("K")); + + Serial.println(); + + delay(2000); +} diff --git a/lib/Adafruit_TCS34725/examples_processing/colorview/colorview.pde b/lib/Adafruit_TCS34725/examples_processing/colorview/colorview.pde new file mode 100644 index 0000000..f7f2871 --- /dev/null +++ b/lib/Adafruit_TCS34725/examples_processing/colorview/colorview.pde @@ -0,0 +1,82 @@ +/* For use with the colorview Arduino example sketch + Update the Serial() new call to match your serial port + e.g. COM4, /dev/usbserial, etc! +*/ + +import processing.serial.*; +import java.awt.datatransfer.*; +import java.awt.Toolkit; + +Serial port; + +void setup(){ + size(200,200); + // remember to replace COM20 with the appropriate serial port on your computer ex Serial.list()[1] + port = new Serial(this, "COM20", 9600); + port.clear(); +} + +String buff = ""; + +int wRed, wGreen, wBlue, wClear; +String hexColor = "ffffff"; + + +void draw(){ + background(wRed,wGreen,wBlue); + // check for serial, and process + + while (port.available() > 0) { + serialEvent(port.read()); + } +} + +void serialEvent(int serial) { + if(serial != '\n') { + buff += char(serial); + } else { + int cRed = buff.indexOf("R"); + int cGreen = buff.indexOf("G"); + int cBlue = buff.indexOf("B"); + //int clear = buff.indexOf("C"); + + //if(clear >=0){ + // String val = buff.substring(clear+3); + // val = val.split("\t")[0]; + // wClear = Integer.parseInt(val.trim()); + //} else { return; } + + if(cRed >=0){ + String val = buff.substring(cRed+3); + val = val.split("\t")[0]; + wRed = Integer.parseInt(val.trim()); + } else { return; } + + if(cGreen >=0) { + String val = buff.substring(cGreen+3); + val = val.split("\t")[0]; + wGreen = Integer.parseInt(val.trim()); + } else { return; } + + if(cBlue >=0) { + String val = buff.substring(cBlue+3); + val = val.split("\t")[0]; + wBlue = Integer.parseInt(val.trim()); + } else { return; } + + //wRed *= 255; wRed /= wClear; + //wGreen *= 255; wGreen /= wClear; + //wBlue *= 255; wBlue /= wClear; + + print("Red: "); print(wRed); + print("\tGrn: "); print(wGreen); + print("\tBlue: "); print(wBlue); + //print("\tClr: "); println(wClear); + + hexColor = hex(color(wRed, wGreen, wBlue), 6); + print("\t HEX: "); + print(hexColor); + println(); + buff = ""; + } +} diff --git a/lib/Adafruit_TCS34725/library.properties b/lib/Adafruit_TCS34725/library.properties new file mode 100644 index 0000000..e029216 --- /dev/null +++ b/lib/Adafruit_TCS34725/library.properties @@ -0,0 +1,9 @@ +name=Adafruit TCS34725 +version=1.3.0 +author=Adafruit +maintainer=Adafruit +sentence=Driver for Adafruit's TCS34725 RGB Color Sensor Breakout +paragraph=Driver for Adafruit's TCS34725 RGB Color Sensor Breakout +category=Sensors +url=https://github.com/adafruit/Adafruit_TCS34725 +architectures=* diff --git a/lib/Adafruit_TCS34725/license.txt b/lib/Adafruit_TCS34725/license.txt new file mode 100644 index 0000000..f6a0f22 --- /dev/null +++ b/lib/Adafruit_TCS34725/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/lib/Adafruit_TSL2561/Adafruit_TSL2561_U.cpp b/lib/Adafruit_TSL2561/Adafruit_TSL2561_U.cpp new file mode 100644 index 0000000..50706f9 --- /dev/null +++ b/lib/Adafruit_TSL2561/Adafruit_TSL2561_U.cpp @@ -0,0 +1,575 @@ +/*! + * @file Adafruit_TSL2561_U.cpp + * + * @mainpage Adafruit TSL2561 Light/Lux sensor driver + * + * @section intro_sec Introduction + * + * This is the documentation for Adafruit's TSL2561 driver for the + * Arduino platform. It is designed specifically to work with the + * Adafruit TSL2561 breakout: http://www.adafruit.com/products/439 + * + * These sensors use I2C to communicate, 2 pins (SCL+SDA) are required + * to interface with the breakout. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * @section dependencies Dependencies + * + * This library depends on + * Adafruit_Sensor being present on your system. Please make sure you have + * installed the latest version before using this library. + * + * @section author Author + * + * Written by Kevin "KTOWN" Townsend for Adafruit Industries. + * + * @section license License + * + * BSD license, all text here must be included in any redistribution. + * + * @section HISTORY + * + * v2.0 - Rewrote driver for Adafruit_Sensor and Auto-Gain support, and + * added lux clipping check (returns 0 lux on sensor saturation) + * v1.0 - First release (previously TSL2561) +*/ +/**************************************************************************/ + +#include "Adafruit_TSL2561_U.h" + +/*========================================================================*/ +/* CONSTRUCTORS */ +/*========================================================================*/ + +/**************************************************************************/ +/*! + @brief Constructor + @param addr The I2C address this chip can be found on, 0x29, 0x39 or 0x49 + @param sensorID An optional ID that will be placed in sensor events to help + keep track if you have many sensors in use +*/ +/**************************************************************************/ +Adafruit_TSL2561_Unified::Adafruit_TSL2561_Unified(uint8_t addr, int32_t sensorID) +{ + _addr = addr; + _tsl2561Initialised = false; + _tsl2561AutoGain = false; + _tsl2561IntegrationTime = TSL2561_INTEGRATIONTIME_13MS; + _tsl2561Gain = TSL2561_GAIN_1X; + _tsl2561SensorID = sensorID; +} + +/*========================================================================*/ +/* PUBLIC FUNCTIONS */ +/*========================================================================*/ + +/**************************************************************************/ +/*! + @brief Initializes I2C and configures the sensor with default Wire I2C + (call this function before doing anything else) + @returns True if sensor is found and initialized, false otherwise. +*/ +/**************************************************************************/ +boolean Adafruit_TSL2561_Unified::begin() +{ + _i2c = &Wire; + _i2c->begin(); + return init(); +} + +/**************************************************************************/ +/*! + @brief Initializes I2C and configures the sensor with provided I2C device + (call this function before doing anything else) + @param theWire A pointer to any I2C interface (e.g. &Wire1) + @returns True if sensor is found and initialized, false otherwise. +*/ +/**************************************************************************/ +boolean Adafruit_TSL2561_Unified::begin(TwoWire *theWire) +{ + _i2c = theWire; + _i2c-> begin(); + return init(); +} + +/**************************************************************************/ +/*! + @brief Initializes I2C connection and settings. + Attempts to determine if the sensor is contactable, then sets up a default + integration time and gain. Then powers down the chip. + @returns True if sensor is found and initialized, false otherwise. +*/ +/**************************************************************************/ +boolean Adafruit_TSL2561_Unified::init() +{ + /* Make sure we're actually connected */ + uint8_t x = read8(TSL2561_REGISTER_ID); + if (x & 0x05) { // ID code for TSL2561 + return false; + } + _tsl2561Initialised = true; + + /* Set default integration time and gain */ + setIntegrationTime(_tsl2561IntegrationTime); + setGain(_tsl2561Gain); + + /* Note: by default, the device is in power down mode on bootup */ + disable(); + + return true; +} + +/**************************************************************************/ +/*! + @brief Enables or disables the auto-gain settings when reading + data from the sensor + @param enable Set to true to enable, False to disable +*/ +/**************************************************************************/ +void Adafruit_TSL2561_Unified::enableAutoRange(bool enable) +{ + _tsl2561AutoGain = enable ? true : false; +} + +/**************************************************************************/ +/*! + @brief Sets the integration time for the TSL2561. Higher time means + more light captured (better for low light conditions) but will + take longer to run readings. + @param time The amount of time we'd like to add up values +*/ +/**************************************************************************/ +void Adafruit_TSL2561_Unified::setIntegrationTime(tsl2561IntegrationTime_t time) +{ + if (!_tsl2561Initialised) begin(); + + /* Enable the device by setting the control bit to 0x03 */ + enable(); + + /* Update the timing register */ + write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, time | _tsl2561Gain); + + /* Update value placeholders */ + _tsl2561IntegrationTime = time; + + /* Turn the device off to save power */ + disable(); +} + +/**************************************************************************/ +/*! + @brief Adjusts the gain on the TSL2561 (adjusts the sensitivity to light) + @param gain The value we'd like to set the gain to +*/ +/**************************************************************************/ +void Adafruit_TSL2561_Unified::setGain(tsl2561Gain_t gain) +{ + if (!_tsl2561Initialised) begin(); + + /* Enable the device by setting the control bit to 0x03 */ + enable(); + + /* Update the timing register */ + write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_TIMING, _tsl2561IntegrationTime | gain); + + /* Update value placeholders */ + _tsl2561Gain = gain; + + /* Turn the device off to save power */ + disable(); +} + +/**************************************************************************/ +/*! + @brief Gets the broadband (mixed lighting) and IR only values from + the TSL2561, adjusting gain if auto-gain is enabled + @param broadband Pointer to a uint16_t we will fill with a sensor + reading from the IR+visible light diode. + @param ir Pointer to a uint16_t we will fill with a sensor the + IR-only light diode. +*/ +/**************************************************************************/ +void Adafruit_TSL2561_Unified::getLuminosity (uint16_t *broadband, uint16_t *ir) +{ + bool valid = false; + + if (!_tsl2561Initialised) begin(); + + /* If Auto gain disabled get a single reading and continue */ + if(!_tsl2561AutoGain) + { + getData (broadband, ir); + return; + } + + /* Read data until we find a valid range */ + bool _agcCheck = false; + do + { + uint16_t _b, _ir; + uint16_t _hi, _lo; + tsl2561IntegrationTime_t _it = _tsl2561IntegrationTime; + + /* Get the hi/low threshold for the current integration time */ + switch(_it) + { + case TSL2561_INTEGRATIONTIME_13MS: + _hi = TSL2561_AGC_THI_13MS; + _lo = TSL2561_AGC_TLO_13MS; + break; + case TSL2561_INTEGRATIONTIME_101MS: + _hi = TSL2561_AGC_THI_101MS; + _lo = TSL2561_AGC_TLO_101MS; + break; + default: + _hi = TSL2561_AGC_THI_402MS; + _lo = TSL2561_AGC_TLO_402MS; + break; + } + + getData(&_b, &_ir); + + /* Run an auto-gain check if we haven't already done so ... */ + if (!_agcCheck) + { + if ((_b < _lo) && (_tsl2561Gain == TSL2561_GAIN_1X)) + { + /* Increase the gain and try again */ + setGain(TSL2561_GAIN_16X); + /* Drop the previous conversion results */ + getData(&_b, &_ir); + /* Set a flag to indicate we've adjusted the gain */ + _agcCheck = true; + } + else if ((_b > _hi) && (_tsl2561Gain == TSL2561_GAIN_16X)) + { + /* Drop gain to 1x and try again */ + setGain(TSL2561_GAIN_1X); + /* Drop the previous conversion results */ + getData(&_b, &_ir); + /* Set a flag to indicate we've adjusted the gain */ + _agcCheck = true; + } + else + { + /* Nothing to look at here, keep moving .... + Reading is either valid, or we're already at the chips limits */ + *broadband = _b; + *ir = _ir; + valid = true; + } + } + else + { + /* If we've already adjusted the gain once, just return the new results. + This avoids endless loops where a value is at one extreme pre-gain, + and the the other extreme post-gain */ + *broadband = _b; + *ir = _ir; + valid = true; + } + } while (!valid); +} + + + +/**************************************************************************/ +/*! + Enables the device +*/ +/**************************************************************************/ +void Adafruit_TSL2561_Unified::enable(void) +{ + /* Enable the device by setting the control bit to 0x03 */ + write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWERON); +} + +/**************************************************************************/ +/*! + Disables the device (putting it in lower power sleep mode) +*/ +/**************************************************************************/ +void Adafruit_TSL2561_Unified::disable(void) +{ + /* Turn the device off to save power */ + write8(TSL2561_COMMAND_BIT | TSL2561_REGISTER_CONTROL, TSL2561_CONTROL_POWEROFF); +} + +/**************************************************************************/ +/*! + Private function to read luminosity on both channels +*/ +/**************************************************************************/ +void Adafruit_TSL2561_Unified::getData (uint16_t *broadband, uint16_t *ir) +{ + /* Enable the device by setting the control bit to 0x03 */ + enable(); + + /* Wait x ms for ADC to complete */ + switch (_tsl2561IntegrationTime) + { + case TSL2561_INTEGRATIONTIME_13MS: + delay(TSL2561_DELAY_INTTIME_13MS); // KTOWN: Was 14ms + break; + case TSL2561_INTEGRATIONTIME_101MS: + delay(TSL2561_DELAY_INTTIME_101MS); // KTOWN: Was 102ms + break; + default: + delay(TSL2561_DELAY_INTTIME_402MS); // KTOWN: Was 403ms + break; + } + + /* Reads a two byte value from channel 0 (visible + infrared) */ + *broadband = read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN0_LOW); + + /* Reads a two byte value from channel 1 (infrared) */ + *ir = read16(TSL2561_COMMAND_BIT | TSL2561_WORD_BIT | TSL2561_REGISTER_CHAN1_LOW); + + /* Turn the device off to save power */ + disable(); +} + + +/**************************************************************************/ +/*! + @brief Converts the raw sensor values to the standard SI lux equivalent. + @param broadband The 16-bit sensor reading from the IR+visible light diode. + @param ir The 16-bit sensor reading from the IR-only light diode. + @returns The integer Lux value we calcuated. + Returns 0 if the sensor is saturated and the values are + unreliable, or 65536 if the sensor is saturated. +*/ +/**************************************************************************/ +/**************************************************************************/ +/*! + + Returns +*/ +/**************************************************************************/ +uint32_t Adafruit_TSL2561_Unified::calculateLux(uint16_t broadband, uint16_t ir) +{ + unsigned long chScale; + unsigned long channel1; + unsigned long channel0; + + /* Make sure the sensor isn't saturated! */ + uint16_t clipThreshold; + switch (_tsl2561IntegrationTime) + { + case TSL2561_INTEGRATIONTIME_13MS: + clipThreshold = TSL2561_CLIPPING_13MS; + break; + case TSL2561_INTEGRATIONTIME_101MS: + clipThreshold = TSL2561_CLIPPING_101MS; + break; + default: + clipThreshold = TSL2561_CLIPPING_402MS; + break; + } + + /* Return 65536 lux if the sensor is saturated */ + if ((broadband > clipThreshold) || (ir > clipThreshold)) + { + return 65536; + } + + /* Get the correct scale depending on the intergration time */ + 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 = (broadband * chScale) >> TSL2561_LUX_CHSCALE; + channel1 = (ir * 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; + +#ifdef 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;} +#endif + + 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; +} + +/**************************************************************************/ +/*! + @brief Gets the most recent sensor event + @param event Pointer to a sensor_event_t type that will be filled + with the lux value, timestamp, data type and sensor ID. + @returns True if sensor reading is between 0 and 65535 lux, + false if sensor is saturated +*/ +/**************************************************************************/ +bool Adafruit_TSL2561_Unified::getEvent(sensors_event_t *event) +{ + uint16_t broadband, ir; + + /* Clear the event */ + memset(event, 0, sizeof(sensors_event_t)); + + event->version = sizeof(sensors_event_t); + event->sensor_id = _tsl2561SensorID; + event->type = SENSOR_TYPE_LIGHT; + event->timestamp = millis(); + + /* Calculate the actual lux value */ + getLuminosity(&broadband, &ir); + event->light = calculateLux(broadband, ir); + + if (event->light == 65536) { + return false; + } + return true; +} + +/**************************************************************************/ +/*! + @brief Gets the sensor_t data + @param sensor A pointer to a sensor_t structure that we will fill with + details about the TSL2561 and its capabilities +*/ +/**************************************************************************/ +void Adafruit_TSL2561_Unified::getSensor(sensor_t *sensor) +{ + /* Clear the sensor_t object */ + memset(sensor, 0, sizeof(sensor_t)); + + /* Insert the sensor name in the fixed length char array */ + strncpy (sensor->name, "TSL2561", sizeof(sensor->name) - 1); + sensor->name[sizeof(sensor->name)- 1] = 0; + sensor->version = 1; + sensor->sensor_id = _tsl2561SensorID; + sensor->type = SENSOR_TYPE_LIGHT; + sensor->min_delay = 0; + sensor->max_value = 17000.0; /* Based on trial and error ... confirm! */ + sensor->min_value = 1.0; + sensor->resolution = 1.0; +} + + + +/*========================================================================*/ +/* PRIVATE FUNCTIONS */ +/*========================================================================*/ + +/**************************************************************************/ +/*! + @brief Writes a register and an 8 bit value over I2C + @param reg I2C register to write the value to + @param value The 8-bit value we're writing to the register +*/ +/**************************************************************************/ +void Adafruit_TSL2561_Unified::write8 (uint8_t reg, uint8_t value) +{ + _i2c->beginTransmission(_addr); + _i2c->write(reg); + _i2c->write(value); + _i2c->endTransmission(); +} + +/**************************************************************************/ +/*! + @brief Reads an 8 bit value over I2C + @param reg I2C register to read from + @returns 8-bit value containing single byte data read +*/ +/**************************************************************************/ +uint8_t Adafruit_TSL2561_Unified::read8(uint8_t reg) +{ + _i2c->beginTransmission(_addr); + _i2c->write(reg); + _i2c->endTransmission(); + + _i2c->requestFrom(_addr, 1); + return _i2c-> read(); +} + +/**************************************************************************/ +/*! + @brief Reads a 16 bit values over I2C + @param reg I2C register to read from + @returns 16-bit value containing 2-byte data read +*/ +/**************************************************************************/ +uint16_t Adafruit_TSL2561_Unified::read16(uint8_t reg) +{ + uint16_t x, t; + + _i2c->beginTransmission(_addr); + _i2c->write(reg); + _i2c->endTransmission(); + + _i2c->requestFrom(_addr, 2); + t = _i2c->read(); + x = _i2c->read(); + x <<= 8; + x |= t; + return x; +} diff --git a/lib/Adafruit_TSL2561/Adafruit_TSL2561_U.h b/lib/Adafruit_TSL2561/Adafruit_TSL2561_U.h new file mode 100644 index 0000000..e1aa191 --- /dev/null +++ b/lib/Adafruit_TSL2561/Adafruit_TSL2561_U.h @@ -0,0 +1,203 @@ +/*! + * @file Adafruit_TSL2561_U.h + * + * This is part of Adafruit's FXOS8700 driver for the Arduino platform. It is + * designed specifically to work with the Adafruit FXOS8700 breakout: + * https://www.adafruit.com/products/3463 + * + * These sensors use I2C to communicate, 2 pins (SCL+SDA) are required + * to interface with the breakout. + * + * 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 "KTOWN" Townsend for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * + */ + +#ifndef ADAFRUIT_TSL2561_H_ +#define ADAFRUIT_TSL2561_H_ + +#include +#include +#include + +#define TSL2561_VISIBLE 2 ///< channel 0 - channel 1 +#define TSL2561_INFRARED 1 ///< channel 1 +#define TSL2561_FULLSPECTRUM 0 ///< channel 0 + +// I2C address options +#define TSL2561_ADDR_LOW (0x29) ///< Default address (pin pulled low) +#define TSL2561_ADDR_FLOAT (0x39) ///< Default address (pin left floating) +#define TSL2561_ADDR_HIGH (0x49) ///< Default address (pin pulled high) + +// Lux calculations differ slightly for CS package +//#define TSL2561_PACKAGE_CS ///< Chip scale package +#define TSL2561_PACKAGE_T_FN_CL ///< Dual Flat No-Lead package + +#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) ///< Control register setting to turn on +#define TSL2561_CONTROL_POWEROFF (0x00) ///< Control register setting to turn off + +#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 + +// Auto-gain thresholds +#define TSL2561_AGC_THI_13MS (4850) ///< Max value at Ti 13ms = 5047 +#define TSL2561_AGC_TLO_13MS (100) ///< Min value at Ti 13ms = 100 +#define TSL2561_AGC_THI_101MS (36000) ///< Max value at Ti 101ms = 37177 +#define TSL2561_AGC_TLO_101MS (200) ///< Min value at Ti 101ms = 200 +#define TSL2561_AGC_THI_402MS (63000) ///< Max value at Ti 402ms = 65535 +#define TSL2561_AGC_TLO_402MS (500) ///< Min value at Ti 402ms = 500 + +// Clipping thresholds +#define TSL2561_CLIPPING_13MS (4900) ///< # Counts that trigger a change in gain/integration +#define TSL2561_CLIPPING_101MS (37000) ///< # Counts that trigger a change in gain/integration +#define TSL2561_CLIPPING_402MS (65000) ///< # Counts that trigger a change in gain/integration + +// Delay for integration times +#define TSL2561_DELAY_INTTIME_13MS (15) ///< Wait 15ms for 13ms integration +#define TSL2561_DELAY_INTTIME_101MS (120) ///< Wait 120ms for 101ms integration +#define TSL2561_DELAY_INTTIME_402MS (450) ///< Wait 450ms for 402ms integration + +/** TSL2561 I2C Registers */ +enum +{ + TSL2561_REGISTER_CONTROL = 0x00, // Control/power register + TSL2561_REGISTER_TIMING = 0x01, // Set integration time register + TSL2561_REGISTER_THRESHHOLDL_LOW = 0x02, // Interrupt low threshold low-byte + TSL2561_REGISTER_THRESHHOLDL_HIGH = 0x03, // Interrupt low threshold high-byte + TSL2561_REGISTER_THRESHHOLDH_LOW = 0x04, // Interrupt high threshold low-byte + TSL2561_REGISTER_THRESHHOLDH_HIGH = 0x05, // Interrupt high threshold high-byte + TSL2561_REGISTER_INTERRUPT = 0x06, // Interrupt settings + TSL2561_REGISTER_CRC = 0x08, // Factory use only + TSL2561_REGISTER_ID = 0x0A, // TSL2561 identification setting + TSL2561_REGISTER_CHAN0_LOW = 0x0C, // Light data channel 0, low byte + TSL2561_REGISTER_CHAN0_HIGH = 0x0D, // Light data channel 0, high byte + TSL2561_REGISTER_CHAN1_LOW = 0x0E, // Light data channel 1, low byte + TSL2561_REGISTER_CHAN1_HIGH = 0x0F // Light data channel 1, high byte +}; + +/** Three options for how long to integrate readings for */ +typedef enum +{ + TSL2561_INTEGRATIONTIME_13MS = 0x00, // 13.7ms + TSL2561_INTEGRATIONTIME_101MS = 0x01, // 101ms + TSL2561_INTEGRATIONTIME_402MS = 0x02 // 402ms +} +tsl2561IntegrationTime_t; + +/** TSL2561 offers 2 gain settings */ +typedef enum +{ + TSL2561_GAIN_1X = 0x00, // No gain + TSL2561_GAIN_16X = 0x10, // 16x gain +} +tsl2561Gain_t; + + + +/**************************************************************************/ +/*! + @brief Class that stores state and functions for interacting with TSL2561 Light Sensor +*/ +/**************************************************************************/ +class Adafruit_TSL2561_Unified : public Adafruit_Sensor { + public: + Adafruit_TSL2561_Unified(uint8_t addr, int32_t sensorID = -1); + boolean begin(void); + boolean begin(TwoWire *theWire); + boolean init(); + + /* TSL2561 Functions */ + void enableAutoRange(bool enable); + void setIntegrationTime(tsl2561IntegrationTime_t time); + void setGain(tsl2561Gain_t gain); + void getLuminosity (uint16_t *broadband, uint16_t *ir); + uint32_t calculateLux(uint16_t broadband, uint16_t ir); + + /* Unified Sensor API Functions */ + bool getEvent(sensors_event_t*); + void getSensor(sensor_t*); + + private: + TwoWire *_i2c; + + int8_t _addr; + boolean _tsl2561Initialised; + boolean _tsl2561AutoGain; + tsl2561IntegrationTime_t _tsl2561IntegrationTime; + tsl2561Gain_t _tsl2561Gain; + int32_t _tsl2561SensorID; + + void enable (void); + void disable (void); + void write8 (uint8_t reg, uint8_t value); + uint8_t read8 (uint8_t reg); + uint16_t read16 (uint8_t reg); + void getData (uint16_t *broadband, uint16_t *ir); +}; + +#endif // ADAFRUIT_TSL2561_H diff --git a/lib/Adafruit_TSL2561/README.md b/lib/Adafruit_TSL2561/README.md new file mode 100644 index 0000000..c63d59f --- /dev/null +++ b/lib/Adafruit_TSL2561/README.md @@ -0,0 +1,50 @@ +# Adafruit TSL2561 Light Sensor Driver [![Build Status](https://travis-ci.com/adafruit/Adafruit_TSL2561.svg?branch=master)](https://travis-ci.com/adafruit/Adafruit_TSL2561) + +This driver is for the Adafruit TSL2561 Breakout, and is based on Adafruit's Unified Sensor Library (Adafruit_Sensor). + + + + +The driver supports manual or 'auto' gain. Adjusting the gain allows you to make the sensor more or less 'sensitive' to light (depending on if you are indoors or outdoors, for example): +``` +tsl.setGain(TSL2561_GAIN_1X); /* No gain ... use in bright light to avoid sensor saturation */ +tsl.setGain(TSL2561_GAIN_16X); /* 16x gain ... use in low light to boost sensitivity */ +tsl.enableAutoGain(true); /* Auto-gain ... switches automatically between 1x and 16x */ +``` + +The driver also supports as automatic clipping detection, and will return '65536' lux when the sensor is saturated and data is unreliable. tsl.getEvent will return false in case of saturation and true in case of valid light data. + +## About the TSL2561 ## + +The TSL2561 is a 16-bit digital (I2C) light sensor, with adjustable gain and 'integration time'. + +Adjusting the 'integration time' essentially increases the resolution of the device, since the analog converter inside the chip has time to take more samples. The integration time can be set as follows: +``` +tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS); /* fast but low resolution */ +tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS); /* medium resolution and speed */ +tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS); /* 16-bit data but slowest conversions */ +``` + +One of the big advantages of the TSL2561 is that it is capable of measuring both broadband (visible plus infrared) and infrared light thanks to two distinct sensing units on the device. This is important in certain lighting environments to be able to read the light level reliably. + +More information on the TSL2561 can be found in the datasheet: http://www.adafruit.com/datasheets/TSL2561.pdf + +## What is the Adafruit Unified Sensor Library? ## + +The Adafruit Unified Sensor Library (Adafruit_Sensor) provides a common interface and data type for any supported sensor. It defines some basic information about the sensor (sensor limits, etc.), and returns standard SI units of a specific type and scale for each supported sensor type. + +It provides a simple abstraction layer between your application and the actual sensor HW, allowing you to drop in any comparable sensor with only one or two lines of code to change in your project (essentially the constructor since the functions to read sensor data and get information about the sensor are defined in the base Adafruit_Sensor class). + +This is imporant useful for two reasons: + +1.) You can use the data right away because it's already converted to SI units that you understand and can compare, rather than meaningless values like 0..1023. + +2.) Because SI units are standardised in the sensor library, you can also do quick sanity checks working with new sensors, or drop in any comparable sensor if you need better sensitivity or if a lower cost unit becomes available, etc. + +Light sensors will always report units in lux, gyroscopes will always report units in rad/s, etc. ... freeing you up to focus on the data, rather than digging through the datasheet to understand what the sensor's raw numbers really mean. + +## About this Driver ## + +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 (KTOWN) Townsend for Adafruit Industries. diff --git a/lib/Adafruit_TSL2561/examples/sensorapi/sensorapi.ino b/lib/Adafruit_TSL2561/examples/sensorapi/sensorapi.ino new file mode 100644 index 0000000..09298d6 --- /dev/null +++ b/lib/Adafruit_TSL2561/examples/sensorapi/sensorapi.ino @@ -0,0 +1,140 @@ +#include +#include +#include + +/* This driver uses the Adafruit unified sensor library (Adafruit_Sensor), + which provides a common 'type' for sensor data and some helper functions. + + To use this driver you will also need to download the Adafruit_Sensor + library and include it in your libraries folder. + + You should also assign a unique ID to this sensor for use with + the Adafruit Sensor API so that you can identify this particular + sensor in any data logs, etc. To assign a unique ID, simply + provide an appropriate value in the constructor below (12345 + is used by default in this example). + + Connections + =========== + Connect SCL to I2C SCL Clock + Connect SDA to I2C SDA Data + Connect VCC/VDD to 3.3V or 5V (depends on sensor's logic level, check the datasheet) + Connect GROUND to common ground + + I2C Address + =========== + The address will be different depending on whether you leave + the ADDR pin floating (addr 0x39), or tie it to ground or vcc. + The default addess is 0x39, which assumes the ADDR pin is floating + (not connected to anything). If you set the ADDR pin high + or low, use TSL2561_ADDR_HIGH (0x49) or TSL2561_ADDR_LOW + (0x29) respectively. + + History + ======= + 2013/JAN/31 - First version (KTOWN) +*/ + +Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 12345); + +/**************************************************************************/ +/* + Displays some basic information on this sensor from the unified + sensor API sensor_t type (see Adafruit_Sensor for more information) +*/ +/**************************************************************************/ +void displaySensorDetails(void) +{ + sensor_t sensor; + tsl.getSensor(&sensor); + Serial.println("------------------------------------"); + Serial.print ("Sensor: "); Serial.println(sensor.name); + Serial.print ("Driver Ver: "); Serial.println(sensor.version); + Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id); + Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux"); + Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux"); + Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux"); + Serial.println("------------------------------------"); + Serial.println(""); + delay(500); +} + +/**************************************************************************/ +/* + Configures the gain and integration time for the TSL2561 +*/ +/**************************************************************************/ +void configureSensor(void) +{ + /* You can also manually set the gain or enable auto-gain support */ + // tsl.setGain(TSL2561_GAIN_1X); /* No gain ... use in bright light to avoid sensor saturation */ + // tsl.setGain(TSL2561_GAIN_16X); /* 16x gain ... use in low light to boost sensitivity */ + tsl.enableAutoRange(true); /* Auto-gain ... switches automatically between 1x and 16x */ + + /* Changing the integration time gives you better sensor resolution (402ms = 16-bit data) */ + tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS); /* fast but low resolution */ + // tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS); /* medium resolution and speed */ + // tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS); /* 16-bit data but slowest conversions */ + + /* Update these values depending on what you've set above! */ + Serial.println("------------------------------------"); + Serial.print ("Gain: "); Serial.println("Auto"); + Serial.print ("Timing: "); Serial.println("13 ms"); + Serial.println("------------------------------------"); +} + +/**************************************************************************/ +/* + Arduino setup function (automatically called at startup) +*/ +/**************************************************************************/ +void setup(void) +{ + Serial.begin(9600); + Serial.println("Light Sensor Test"); Serial.println(""); + + /* Initialise the sensor */ + //use tsl.begin() to default to Wire, + //tsl.begin(&Wire2) directs api to use Wire2, etc. + if(!tsl.begin()) + { + /* There was a problem detecting the TSL2561 ... check your connections */ + Serial.print("Ooops, no TSL2561 detected ... Check your wiring or I2C ADDR!"); + while(1); + } + + /* Display some basic information on this sensor */ + displaySensorDetails(); + + /* Setup the sensor gain and integration time */ + configureSensor(); + + /* We're ready to go! */ + Serial.println(""); +} + +/**************************************************************************/ +/* + Arduino loop function, called once 'setup' is complete (your own code + should go here) +*/ +/**************************************************************************/ +void loop(void) +{ + /* Get a new sensor event */ + sensors_event_t event; + tsl.getEvent(&event); + + /* Display the results (light is measured in lux) */ + if (event.light) + { + Serial.print(event.light); Serial.println(" lux"); + } + else + { + /* If event.light = 0 lux the sensor is probably saturated + and no reliable data could be generated! */ + Serial.println("Sensor overload"); + } + delay(250); +} diff --git a/lib/Adafruit_TSL2561/library.properties b/lib/Adafruit_TSL2561/library.properties new file mode 100644 index 0000000..ab74d51 --- /dev/null +++ b/lib/Adafruit_TSL2561/library.properties @@ -0,0 +1,9 @@ +name=Adafruit TSL2561 +version=1.0.3 +author=Adafruit +maintainer=Adafruit +sentence=Unified sensor driver for Adafruit's TSL2561 breakouts +paragraph=Unified sensor driver for Adafruit's TSL2561 breakouts +category=Sensors +url=https://github.com/adafruit/Adafruit_TSL2561 +architectures=* diff --git a/lib/Adafruit_Unified_Sensor/Adafruit_Sensor.h b/lib/Adafruit_Unified_Sensor/Adafruit_Sensor.h new file mode 100644 index 0000000..8ac638f --- /dev/null +++ b/lib/Adafruit_Unified_Sensor/Adafruit_Sensor.h @@ -0,0 +1,156 @@ +/* +* Copyright (C) 2008 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software< /span> +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/* Update by K. Townsend (Adafruit Industries) for lighter typedefs, and + * extended sensor support to include color, voltage and current */ + +#ifndef _ADAFRUIT_SENSOR_H +#define _ADAFRUIT_SENSOR_H + +#ifndef ARDUINO + #include +#elif ARDUINO >= 100 + #include "Arduino.h" + #include "Print.h" +#else + #include "WProgram.h" +#endif + +/* Intentionally modeled after sensors.h in the Android API: + * https://github.com/android/platform_hardware_libhardware/blob/master/include/hardware/sensors.h */ + +/* Constants */ +#define SENSORS_GRAVITY_EARTH (9.80665F) /**< Earth's gravity in m/s^2 */ +#define SENSORS_GRAVITY_MOON (1.6F) /**< The moon's gravity in m/s^2 */ +#define SENSORS_GRAVITY_SUN (275.0F) /**< The sun's gravity in m/s^2 */ +#define SENSORS_GRAVITY_STANDARD (SENSORS_GRAVITY_EARTH) +#define SENSORS_MAGFIELD_EARTH_MAX (60.0F) /**< Maximum magnetic field on Earth's surface */ +#define SENSORS_MAGFIELD_EARTH_MIN (30.0F) /**< Minimum magnetic field on Earth's surface */ +#define SENSORS_PRESSURE_SEALEVELHPA (1013.25F) /**< Average sea level pressure is 1013.25 hPa */ +#define SENSORS_DPS_TO_RADS (0.017453293F) /**< Degrees/s to rad/s multiplier */ +#define SENSORS_GAUSS_TO_MICROTESLA (100) /**< Gauss to micro-Tesla multiplier */ + +/** Sensor types */ +typedef enum +{ + SENSOR_TYPE_ACCELEROMETER = (1), /**< Gravity + linear acceleration */ + SENSOR_TYPE_MAGNETIC_FIELD = (2), + SENSOR_TYPE_ORIENTATION = (3), + SENSOR_TYPE_GYROSCOPE = (4), + SENSOR_TYPE_LIGHT = (5), + SENSOR_TYPE_PRESSURE = (6), + SENSOR_TYPE_PROXIMITY = (8), + SENSOR_TYPE_GRAVITY = (9), + SENSOR_TYPE_LINEAR_ACCELERATION = (10), /**< Acceleration not including gravity */ + SENSOR_TYPE_ROTATION_VECTOR = (11), + SENSOR_TYPE_RELATIVE_HUMIDITY = (12), + SENSOR_TYPE_AMBIENT_TEMPERATURE = (13), + SENSOR_TYPE_VOLTAGE = (15), + SENSOR_TYPE_CURRENT = (16), + SENSOR_TYPE_COLOR = (17) +} sensors_type_t; + +/** struct sensors_vec_s is used to return a vector in a common format. */ +typedef struct { + union { + float v[3]; + struct { + float x; + float y; + float z; + }; + /* Orientation sensors */ + struct { + float roll; /**< Rotation around the longitudinal axis (the plane body, 'X axis'). Roll is positive and increasing when moving downward. -90°<=roll<=90° */ + float pitch; /**< Rotation around the lateral axis (the wing span, 'Y axis'). Pitch is positive and increasing when moving upwards. -180°<=pitch<=180°) */ + float heading; /**< Angle between the longitudinal axis (the plane body) and magnetic north, measured clockwise when viewing from the top of the device. 0-359° */ + }; + }; + int8_t status; + uint8_t reserved[3]; +} sensors_vec_t; + +/** struct sensors_color_s is used to return color data in a common format. */ +typedef struct { + union { + float c[3]; + /* RGB color space */ + struct { + float r; /**< Red component */ + float g; /**< Green component */ + float b; /**< Blue component */ + }; + }; + uint32_t rgba; /**< 24-bit RGBA value */ +} sensors_color_t; + +/* Sensor event (36 bytes) */ +/** struct sensor_event_s is used to provide a single sensor event in a common format. */ +typedef struct +{ + int32_t version; /**< must be sizeof(struct sensors_event_t) */ + int32_t sensor_id; /**< unique sensor identifier */ + int32_t type; /**< sensor type */ + int32_t reserved0; /**< reserved */ + int32_t timestamp; /**< time is in milliseconds */ + union + { + float data[4]; + sensors_vec_t acceleration; /**< acceleration values are in meter per second per second (m/s^2) */ + sensors_vec_t magnetic; /**< magnetic vector values are in micro-Tesla (uT) */ + sensors_vec_t orientation; /**< orientation values are in degrees */ + sensors_vec_t gyro; /**< gyroscope values are in rad/s */ + float temperature; /**< temperature is in degrees centigrade (Celsius) */ + float distance; /**< distance in centimeters */ + float light; /**< light in SI lux units */ + float pressure; /**< pressure in hectopascal (hPa) */ + float relative_humidity; /**< relative humidity in percent */ + float current; /**< current in milliamps (mA) */ + float voltage; /**< voltage in volts (V) */ + sensors_color_t color; /**< color in RGB component values */ + }; +} sensors_event_t; + +/* Sensor details (40 bytes) */ +/** struct sensor_s is used to describe basic information about a specific sensor. */ +typedef struct +{ + char name[12]; /**< sensor name */ + int32_t version; /**< version of the hardware + driver */ + int32_t sensor_id; /**< unique sensor identifier */ + int32_t type; /**< this sensor's type (ex. SENSOR_TYPE_LIGHT) */ + float max_value; /**< maximum value of this sensor's value in SI units */ + float min_value; /**< minimum value of this sensor's value in SI units */ + float resolution; /**< smallest difference between two values reported by this sensor */ + int32_t min_delay; /**< min delay in microseconds between events. zero = not a constant rate */ +} sensor_t; + +class Adafruit_Sensor { + public: + // Constructor(s) + Adafruit_Sensor() {} + virtual ~Adafruit_Sensor() {} + + // These must be defined by the subclass + virtual void enableAutoRange(bool enabled) { (void)enabled; /* suppress unused warning */ }; + virtual bool getEvent(sensors_event_t*) = 0; + virtual void getSensor(sensor_t*) = 0; + + private: + bool _autoRange; +}; + +#endif diff --git a/lib/Adafruit_Unified_Sensor/README.md b/lib/Adafruit_Unified_Sensor/README.md new file mode 100644 index 0000000..fd99597 --- /dev/null +++ b/lib/Adafruit_Unified_Sensor/README.md @@ -0,0 +1,229 @@ +# Adafruit Unified Sensor Driver # + +Many small embedded systems exist to collect data from sensors, analyse the data, and either take an appropriate action or send that sensor data to another system for processing. + +One of the many challenges of embedded systems design is the fact that parts you used today may be out of production tomorrow, or system requirements may change and you may need to choose a different sensor down the road. + +Creating new drivers is a relatively easy task, but integrating them into existing systems is both error prone and time consuming since sensors rarely use the exact same units of measurement. + +By reducing all data to a single **sensors\_event\_t** 'type' and settling on specific, **standardised SI units** for each sensor family the same sensor types return values that are comparable with any other similar sensor. This enables you to switch sensor models with very little impact on the rest of the system, which can help mitigate some of the risks and problems of sensor availability and code reuse. + +The unified sensor abstraction layer is also useful for data-logging and data-transmission since you only have one well-known type to log or transmit over the air or wire. + +## Unified Sensor Drivers ## + +The following drivers are based on the Adafruit Unified Sensor Driver: + +**Accelerometers** + - [Adafruit\_ADXL345](https://github.com/adafruit/Adafruit_ADXL345) + - [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC) + - [Adafruit\_MMA8451\_Library](https://github.com/adafruit/Adafruit_MMA8451_Library) + +**Gyroscope** + - [Adafruit\_L3GD20\_U](https://github.com/adafruit/Adafruit_L3GD20_U) + +**Light** + - [Adafruit\_TSL2561](https://github.com/adafruit/Adafruit_TSL2561) + - [Adafruit\_TSL2591\_Library](https://github.com/adafruit/Adafruit_TSL2591_Library) + +**Magnetometers** + - [Adafruit\_LSM303DLHC](https://github.com/adafruit/Adafruit_LSM303DLHC) + - [Adafruit\_HMC5883\_Unified](https://github.com/adafruit/Adafruit_HMC5883_Unified) + +**Barometric Pressure** + - [Adafruit\_BMP085\_Unified](https://github.com/adafruit/Adafruit_BMP085_Unified) + - [Adafruit\_BMP183\_Unified\_Library](https://github.com/adafruit/Adafruit_BMP183_Unified_Library) + +**Humidity & Temperature** + - [DHT-sensor-library](https://github.com/adafruit/DHT-sensor-library) + +**Humidity, Temperature, & Barometric Pressure** + - [Adafruit_BME280_Library](https://github.com/adafruit/Adafruit_BME280_Library/) + +**Orientation** + - [Adafruit_BNO055](https://github.com/adafruit/Adafruit_BNO055) + +**All in one device** +- [Adafruit_LSM9DS0](https://github.com/adafruit/Adafruit_LSM9DS0_Library) (accelerometer, gyroscope, magnetometer) +- [Adafruit_LSM9DS1](https://github.com/adafruit/Adafruit_LSM9DS1/) (accelerometer, gyroscope, magnetometer) + + +## How Does it Work? ## + +Any driver that supports the Adafruit unified sensor abstraction layer will implement the Adafruit\_Sensor base class. There are two main typedefs and one enum defined in Adafruit_Sensor.h that are used to 'abstract' away the sensor details and values: + +**Sensor Types (sensors\_type\_t)** + +These pre-defined sensor types are used to properly handle the two related typedefs below, and allows us determine what types of units the sensor uses, etc. + +``` +/** Sensor types */ +typedef enum +{ + SENSOR_TYPE_ACCELEROMETER = (1), + SENSOR_TYPE_MAGNETIC_FIELD = (2), + SENSOR_TYPE_ORIENTATION = (3), + SENSOR_TYPE_GYROSCOPE = (4), + SENSOR_TYPE_LIGHT = (5), + SENSOR_TYPE_PRESSURE = (6), + SENSOR_TYPE_PROXIMITY = (8), + SENSOR_TYPE_GRAVITY = (9), + SENSOR_TYPE_LINEAR_ACCELERATION = (10), + SENSOR_TYPE_ROTATION_VECTOR = (11), + SENSOR_TYPE_RELATIVE_HUMIDITY = (12), + SENSOR_TYPE_AMBIENT_TEMPERATURE = (13), + SENSOR_TYPE_VOLTAGE = (15), + SENSOR_TYPE_CURRENT = (16), + SENSOR_TYPE_COLOR = (17) +} sensors_type_t; +``` + +**Sensor Details (sensor\_t)** + +This typedef describes the specific capabilities of this sensor, and allows us to know what sensor we are using beneath the abstraction layer. + +``` +/* Sensor details (40 bytes) */ +/** struct sensor_s is used to describe basic information about a specific sensor. */ +typedef struct +{ + char name[12]; + int32_t version; + int32_t sensor_id; + int32_t type; + float max_value; + float min_value; + float resolution; + int32_t min_delay; +} sensor_t; +``` + +The individual fields are intended to be used as follows: + +- **name**: The sensor name or ID, up to a maximum of twelve characters (ex. "MPL115A2") +- **version**: The version of the sensor HW and the driver to allow us to differentiate versions of the board or driver +- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network +- **type**: The sensor type, based on **sensors\_type\_t** in sensors.h +- **max\_value**: The maximum value that this sensor can return (in the appropriate SI unit) +- **min\_value**: The minimum value that this sensor can return (in the appropriate SI unit) +- **resolution**: The smallest difference between two values that this sensor can report (in the appropriate SI unit) +- **min\_delay**: The minimum delay in microseconds between two sensor events, or '0' if there is no constant sensor rate + +**Sensor Data/Events (sensors\_event\_t)** + +This typedef is used to return sensor data from any sensor supported by the abstraction layer, using standard SI units and scales. + +``` +/* Sensor event (36 bytes) */ +/** struct sensor_event_s is used to provide a single sensor event in a common format. */ +typedef struct +{ + int32_t version; + int32_t sensor_id; + int32_t type; + int32_t reserved0; + int32_t timestamp; + union + { + float data[4]; + sensors_vec_t acceleration; + sensors_vec_t magnetic; + sensors_vec_t orientation; + sensors_vec_t gyro; + float temperature; + float distance; + float light; + float pressure; + float relative_humidity; + float current; + float voltage; + sensors_color_t color; + }; +} sensors_event_t; +``` +It includes the following fields: + +- **version**: Contain 'sizeof(sensors\_event\_t)' to identify which version of the API we're using in case this changes in the future +- **sensor\_id**: A unique sensor identifier that is used to differentiate this specific sensor instance from any others that are present on the system or in the sensor network (must match the sensor\_id value in the corresponding sensor\_t enum above!) +- **type**: the sensor type, based on **sensors\_type\_t** in sensors.h +- **timestamp**: time in milliseconds when the sensor value was read +- **data[4]**: An array of four 32-bit values that allows us to encapsulate any type of sensor data via a simple union (further described below) + +**Required Functions** + +In addition to the two standard types and the sensor type enum, all drivers based on Adafruit_Sensor must also implement the following two functions: + +``` +bool getEvent(sensors_event_t*); +``` +Calling this function will populate the supplied sensors\_event\_t reference with the latest available sensor data. You should call this function as often as you want to update your data. + +``` +void getSensor(sensor_t*); +``` +Calling this function will provide some basic information about the sensor (the sensor name, driver version, min and max values, etc. + +**Standardised SI values for sensors\_event\_t** + +A key part of the abstraction layer is the standardisation of values on SI units of a particular scale, which is accomplished via the data[4] union in sensors\_event\_t above. This 16 byte union includes fields for each main sensor type, and uses the following SI units and scales: + +- **acceleration**: values are in **meter per second per second** (m/s^2) +- **magnetic**: values are in **micro-Tesla** (uT) +- **orientation**: values are in **degrees** +- **gyro**: values are in **rad/s** +- **temperature**: values in **degrees centigrade** (Celsius) +- **distance**: values are in **centimeters** +- **light**: values are in **SI lux** units +- **pressure**: values are in **hectopascal** (hPa) +- **relative\_humidity**: values are in **percent** +- **current**: values are in **milliamps** (mA) +- **voltage**: values are in **volts** (V) +- **color**: values are in 0..1.0 RGB channel luminosity and 32-bit RGBA format + +## The Unified Driver Abstraction Layer in Practice ## + +Using the unified sensor abstraction layer is relatively easy once a compliant driver has been created. + +Every compliant sensor can now be read using a single, well-known 'type' (sensors\_event\_t), and there is a standardised way of interrogating a sensor about its specific capabilities (via sensor\_t). + +An example of reading the [TSL2561](https://github.com/adafruit/Adafruit_TSL2561) light sensor can be seen below: + +``` + Adafruit_TSL2561 tsl = Adafruit_TSL2561(TSL2561_ADDR_FLOAT, 12345); + ... + /* Get a new sensor event */ + sensors_event_t event; + tsl.getEvent(&event); + + /* Display the results (light is measured in lux) */ + if (event.light) + { + Serial.print(event.light); Serial.println(" lux"); + } + else + { + /* If event.light = 0 lux the sensor is probably saturated + and no reliable data could be generated! */ + Serial.println("Sensor overload"); + } +``` + +Similarly, we can get the basic technical capabilities of this sensor with the following code: + +``` + sensor_t sensor; + + sensor_t sensor; + tsl.getSensor(&sensor); + + /* Display the sensor details */ + Serial.println("------------------------------------"); + Serial.print ("Sensor: "); Serial.println(sensor.name); + Serial.print ("Driver Ver: "); Serial.println(sensor.version); + Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id); + Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux"); + Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux"); + Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux"); + Serial.println("------------------------------------"); + Serial.println(""); +``` diff --git a/lib/Adafruit_Unified_Sensor/library.properties b/lib/Adafruit_Unified_Sensor/library.properties new file mode 100644 index 0000000..e0bcd3e --- /dev/null +++ b/lib/Adafruit_Unified_Sensor/library.properties @@ -0,0 +1,10 @@ +name=Adafruit Unified Sensor +version=1.0.3 +author=Adafruit +maintainer=Adafruit +sentence=Required for all Adafruit Unified Sensor based libraries. +paragraph=A unified sensor abstraction layer used by many Adafruit sensor libraries. +category=Sensors +url=https://github.com/adafruit/Adafruit_Sensor +architectures=* +includes=Adafruit_Sensor.h diff --git a/lib/Adafruit_VEML7700_Library/Adafruit_VEML7700.cpp b/lib/Adafruit_VEML7700_Library/Adafruit_VEML7700.cpp new file mode 100644 index 0000000..07b59e9 --- /dev/null +++ b/lib/Adafruit_VEML7700_Library/Adafruit_VEML7700.cpp @@ -0,0 +1,197 @@ +/*! + * @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 HW + * @param addr + * @return True if initialization was successful, otherwise false. + */ +boolean Adafruit_VEML7700::begin(TwoWire *theWire) { + i2c_dev = new Adafruit_I2CDevice(VEML7700_I2CADDR_DEFAULT); + + 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(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; +} + +float Adafruit_VEML7700::readLux() { + return normalize(ALS_Data->read()) * 0.0576; // see app note lux table on page 5 +} + +uint16_t Adafruit_VEML7700::readALS() { + return ALS_Data->read(); +} + + +float Adafruit_VEML7700::readWhite() { + return normalize(White_Data->read()) * 0.0576; // Unclear if this is the right multiplier +} + + +void Adafruit_VEML7700::enable(bool enable) { + ALS_Shutdown->write(!enable); +} + +bool Adafruit_VEML7700::enabled(void) { + return !ALS_Shutdown->read(); +} + +void Adafruit_VEML7700::interruptEnable(bool enable) { + ALS_Interrupt_Enable->write(enable); +} + +bool Adafruit_VEML7700::interruptEnabled(void) { + return ALS_Interrupt_Enable->read(); +} + +void Adafruit_VEML7700::setPersistence(uint8_t pers) { + ALS_Persistence->write(pers); +} + +uint8_t Adafruit_VEML7700::getPersistence(void) { + return ALS_Persistence->read(); +} + +void Adafruit_VEML7700::setIntegrationTime(uint8_t it) { + ALS_Integration_Time->write(it); +} + +uint8_t Adafruit_VEML7700::getIntegrationTime(void) { + return ALS_Integration_Time->read(); +} + +void Adafruit_VEML7700::setGain(uint8_t gain) { + ALS_Gain->write(gain); +} + +uint8_t Adafruit_VEML7700::getGain(void) { + return ALS_Gain->read(); +} + +void Adafruit_VEML7700::powerSaveEnable(bool enable) { + PowerSave_Enable->write(enable); +} + +bool Adafruit_VEML7700::powerSaveEnabled(void) { + return PowerSave_Enable->read(); +} + +void Adafruit_VEML7700::setPowerSaveMode(uint8_t mode) { + PowerSave_Mode->write(mode); +} + +uint8_t Adafruit_VEML7700::getPowerSaveMode(void) { + return PowerSave_Mode->read(); +} + +void Adafruit_VEML7700::setLowThreshold(uint16_t value) { + ALS_LowThreshold->write(value); +} + +uint16_t Adafruit_VEML7700::getLowThreshold(void) { + return ALS_LowThreshold->read(); +} + + +void Adafruit_VEML7700::setHighThreshold(uint16_t value) { + ALS_HighThreshold->write(value); +} + +uint16_t Adafruit_VEML7700::getHighThreshold(void) { + return ALS_HighThreshold->read(); +} + +uint16_t Adafruit_VEML7700::interruptStatus(void) { + return Interrupt_Status->read(); +} diff --git a/lib/Adafruit_VEML7700_Library/Adafruit_VEML7700.h b/lib/Adafruit_VEML7700_Library/Adafruit_VEML7700.h new file mode 100644 index 0000000..53c29c3 --- /dev/null +++ b/lib/Adafruit_VEML7700_Library/Adafruit_VEML7700.h @@ -0,0 +1,111 @@ +/*! + * @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 +#define VEML7700_ALS_THREHOLD_HIGH 0x01 +#define VEML7700_ALS_THREHOLD_LOW 0x02 +#define VEML7700_ALS_POWER_SAVE 0x03 +#define VEML7700_ALS_DATA 0x04 +#define VEML7700_WHITE_DATA 0x05 +#define VEML7700_INTERRUPTSTATUS 0x06 + +#define VEML7700_INTERRUPT_HIGH 0x4000 +#define VEML7700_INTERRUPT_LOW 0x8000 + +#define VEML7700_GAIN_1 0x00 +#define VEML7700_GAIN_2 0x01 +#define VEML7700_GAIN_1_8 0x02 +#define VEML7700_GAIN_1_4 0x03 + +#define VEML7700_IT_100MS 0x00 +#define VEML7700_IT_200MS 0x01 +#define VEML7700_IT_400MS 0x02 +#define VEML7700_IT_800MS 0x03 +#define VEML7700_IT_50MS 0x08 +#define VEML7700_IT_25MS 0x0C + +#define VEML7700_PERS_1 0x00 +#define VEML7700_PERS_2 0x01 +#define VEML7700_PERS_4 0x02 +#define VEML7700_PERS_8 0x03 + +#define VEML7700_POWERSAVE_MODE1 0x00 +#define VEML7700_POWERSAVE_MODE2 0x01 +#define VEML7700_POWERSAVE_MODE3 0x02 +#define VEML7700_POWERSAVE_MODE4 0x03 + + +/*! + * @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(); + uint16_t readALS(); + float readWhite(); + + 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; + + +private: + float normalize(float value); + + Adafruit_I2CDevice *i2c_dev; + +}; + +#endif diff --git a/lib/Adafruit_VEML7700_Library/README.md b/lib/Adafruit_VEML7700_Library/README.md new file mode 100644 index 0000000..397343e --- /dev/null +++ b/lib/Adafruit_VEML7700_Library/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 \ No newline at end of file diff --git a/lib/Adafruit_VEML7700_Library/examples/veml7700_test/veml7700_test.ino b/lib/Adafruit_VEML7700_Library/examples/veml7700_test/veml7700_test.ino new file mode 100644 index 0000000..6471811 --- /dev/null +++ b/lib/Adafruit_VEML7700_Library/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/library.properties b/lib/Adafruit_VEML7700_Library/library.properties new file mode 100644 index 0000000..754bd2f --- /dev/null +++ b/lib/Adafruit_VEML7700_Library/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_Library/license.txt b/lib/Adafruit_VEML7700_Library/license.txt new file mode 100644 index 0000000..f6a0f22 --- /dev/null +++ b/lib/Adafruit_VEML7700_Library/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/lib/Arduino_MKRTHERM/README.adoc b/lib/Arduino_MKRTHERM/README.adoc new file mode 100644 index 0000000..8233b5a --- /dev/null +++ b/lib/Arduino_MKRTHERM/README.adoc @@ -0,0 +1,24 @@ += MKRTHERM Library for Arduino = + +Allows you to read the temperature sensors connected to your MKR THERM shield. + +For more information about this library please visit us at https://www.arduino.cc/en/Reference/Arduino_MKRTHERM + + +== License == + +Copyright (c) 2019 Arduino SA. All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/lib/Arduino_MKRTHERM/examples/ReadSensor/ReadSensor.ino b/lib/Arduino_MKRTHERM/examples/ReadSensor/ReadSensor.ino new file mode 100644 index 0000000..8b2a5a9 --- /dev/null +++ b/lib/Arduino_MKRTHERM/examples/ReadSensor/ReadSensor.ino @@ -0,0 +1,43 @@ +/* + MKR THERM Shield - Read Sensors + + This example reads the temperatures measured by the thermocouple + connected to the MKR THERM shield and prints them to the Serial Monitor + once a second. + + The circuit: + - Arduino MKR board + - Arduino MKR THERM Shield attached + - A K Type thermocouple temperature sensor connected to the shield + + This example code is in the public domain. +*/ + +#include + +void setup() { + + Serial.begin(9600); + + while (!Serial); + + if (!THERM.begin()) { + Serial.println("Failed to initialize MKR THERM shield!"); + while (1); + } +} + +void loop() { + + Serial.print("Reference temperature "); + Serial.print(THERM.readReferenceTemperature()); + Serial.println(" °C"); + + Serial.print("Temperature "); + Serial.print(THERM.readTemperature()); + Serial.println(" °C"); + + Serial.println(); + + delay(1000); +} diff --git a/lib/Arduino_MKRTHERM/keywords.txt b/lib/Arduino_MKRTHERM/keywords.txt new file mode 100644 index 0000000..20bb273 --- /dev/null +++ b/lib/Arduino_MKRTHERM/keywords.txt @@ -0,0 +1,23 @@ +####################################### +# Syntax Coloring Map For Arduino_MKRTHERM +####################################### +# Class +####################################### + +Arduino_MKRTHERM KEYWORD1 +MKRTHERM KEYWORD1 +THERM KEYWORD1 + +####################################### +# Methods and Functions +####################################### + +begin KEYWORD2 +end KEYWORD2 + +readTemperature KEYWORD2 +readReferenceTemperature KEYWORD2 + +####################################### +# Constants +####################################### \ No newline at end of file diff --git a/lib/Arduino_MKRTHERM/library.properties b/lib/Arduino_MKRTHERM/library.properties new file mode 100644 index 0000000..5bc7db4 --- /dev/null +++ b/lib/Arduino_MKRTHERM/library.properties @@ -0,0 +1,10 @@ +name=Arduino_MKRTHERM +version=1.0.0 +author=Arduino +maintainer=Arduino +sentence=Allows you to read the temperature sensors connected to your MKR THERM shield. +paragraph= +category=Sensors +url=https://github.com/arduino-libraries/Arduino_MKRTHERM +architectures=samd +includes=Arduino_MKRTHERM.h diff --git a/lib/Arduino_MKRTHERM/src/Arduino_MKRTHERM.h b/lib/Arduino_MKRTHERM/src/Arduino_MKRTHERM.h new file mode 100644 index 0000000..a505ebc --- /dev/null +++ b/lib/Arduino_MKRTHERM/src/Arduino_MKRTHERM.h @@ -0,0 +1,25 @@ +/* + This file is part of the Arduino_MKRTHERM library. + Copyright (c) 2019 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _ARDUINO_MKRTHERM_H_ +#define _ARDUINO_MKRTHERM_H_ + +#include "MKRTHERM.h" + +#endif diff --git a/lib/Arduino_MKRTHERM/src/MKRTHERM.cpp b/lib/Arduino_MKRTHERM/src/MKRTHERM.cpp new file mode 100644 index 0000000..64aefe2 --- /dev/null +++ b/lib/Arduino_MKRTHERM/src/MKRTHERM.cpp @@ -0,0 +1,126 @@ +/* + This file is part of the Arduino_MKRTHERM library. + Copyright (c) 2019 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "MKRTHERM.h" + +THERMClass::THERMClass(int cs, SPIClass& spi) : + _cs(cs), + _spi(&spi), + _spiSettings(4000000, MSBFIRST, SPI_MODE0) +{ +} + +int THERMClass::begin() +{ + uint32_t rawword; + + pinMode(_cs, OUTPUT); + digitalWrite(_cs, HIGH); + _spi->begin(); + + rawword = readSensor(); + if (rawword == 0xFFFFFF) { + end(); + + return 0; + } + + return 1; +} + +void THERMClass::end() +{ + pinMode(_cs, INPUT); + digitalWrite(_cs, LOW); + _spi->end(); +} + +uint32_t THERMClass::readSensor() +{ + uint32_t read = 0x00; + + digitalWrite(_cs, LOW); + delayMicroseconds(1); + + _spi->beginTransaction(_spiSettings); + + + for (int i = 0; i < 4; i++) { + read <<= 8; + read |= _spi->transfer(0); + } + + _spi->endTransaction(); + + digitalWrite(_cs, HIGH); + + return read; +} + +float THERMClass::readTemperature() +{ + uint32_t rawword; + float celsius; + + rawword = readSensor(); + + // Check for reading error + if (rawword & 0x7) { + return NAN; + } + // The temperature is stored in the last 14 word's bits + // sendend by the Thermocouple-to-Digital Converter + if (rawword & 0x80000000) { + // Negative value, drop the lower 18 bits and explicitly extend sign bits. + rawword = 0xFFFFC000 | ((rawword >> 18) & 0x00003FFFF); + } else { + // Positive value, just drop the lower 18 bits. + rawword >>= 18; + } + // multiply for the LSB value + celsius = rawword * 0.25f; + + return celsius; +} + +float THERMClass::readReferenceTemperature() +{ + uint32_t rawword; + float ref; + + rawword = readSensor(); + + // ignore first 4 FAULT bits + rawword >>= 4; + + // The cold junction reference temperature is stored in the first 11 word's bits + // sendend by the Thermocouple-to-Digital Converter + rawword = rawword & 0x7FF; + // check sign bit and convert to negative value. + if (rawword & 0x800) { + ref = (0xF800 | (rawword & 0x7FF))*0.0625; + } else { + // multiply for the LSB value + ref = rawword * 0.0625f; + } + + return ref; +} + +THERMClass THERM; diff --git a/lib/Arduino_MKRTHERM/src/MKRTHERM.h b/lib/Arduino_MKRTHERM/src/MKRTHERM.h new file mode 100644 index 0000000..91985c2 --- /dev/null +++ b/lib/Arduino_MKRTHERM/src/MKRTHERM.h @@ -0,0 +1,46 @@ +/* + This file is part of the Arduino_MKRTHERM library. + Copyright (c) 2019 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _MKRTHERM_H_ +#define _MKRTHERM_H_ + +#include +#include + +class THERMClass { +public: + THERMClass(int cs = A4, SPIClass& spi = SPI); + + int begin(); + void end(); + + float readTemperature(); + float readReferenceTemperature(); + +private: + uint32_t readSensor(); + + int _cs; + SPIClass* _spi; + SPISettings _spiSettings; +}; + +extern THERMClass THERM; + +#endif diff --git a/lib/BH1750/.gitignore b/lib/BH1750/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/lib/BH1750/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/lib/BH1750/.travis.yml b/lib/BH1750/.travis.yml new file mode 100644 index 0000000..6b937ce --- /dev/null +++ b/lib/BH1750/.travis.yml @@ -0,0 +1,27 @@ +language: cpp +env: + global: + - ARDUINO_PACKAGE_VERSION=1.8.5 + - DISPLAY=:1.0 + +before_install: + # arduino requires an X server even with command line + - /sbin/start-stop-daemon --start --quiet --pidfile /tmp/xvfb_$TRAVIS_JOB_NUMBER.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16 + +install: + - wget -q -O- http://downloads.arduino.cc/arduino-$ARDUINO_PACKAGE_VERSION-linux64.tar.xz | tar -Jxf - + - sudo mv arduino-$ARDUINO_PACKAGE_VERSION /usr/local/share/arduino + - sudo ln -s /usr/local/share/arduino/arduino /usr/local/bin/arduino + # Add esp8266 board support + # - arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json" --save-prefs + # - arduino --install-boards esp8266:esp8266 + # link project directory into Arduino libraries area. + - ln -s $PWD /usr/local/share/arduino/libraries/BH1750 + +script: + # uno + - arduino --verify --board arduino:avr:uno $PWD/examples/BH1750test/BH1750test.ino + - arduino --verify --board arduino:avr:uno $PWD/examples/BH1750advanced/BH1750advanced.ino + # esp8266 + # - arduino --verify --board esp8266:esp8266:generic $PWD/examples/BH1570test/BH1750test.ino + # - arduino --verify --board esp8266:esp8266:generic $PWD/examples/BH1570advanced/BH1750advanced.ino diff --git a/lib/BH1750/BH1750.cpp b/lib/BH1750/BH1750.cpp new file mode 100644 index 0000000..f82c370 --- /dev/null +++ b/lib/BH1750/BH1750.cpp @@ -0,0 +1,207 @@ +/* + + This is a library for the BH1750FVI Digital Light Sensor breakout board. + + The BH1750 board uses I2C for communication. Two pins are required to + interface to the device. Configuring the I2C bus is expected to be done + in user code. The BH1750 library doesn't do this automatically. + + Written by Christopher Laws, March, 2013. + + Modified by Dan Ogorchock on 2018-07-04 for ST_Anything compatability + +*/ + +#include "BH1750.h" + +// Define milliseconds delay for ESP8266 platform +#if defined(ESP8266) + + #include + #define _delay_ms(ms) delayMicroseconds((ms) * 1000) + +// Use _delay_ms from utils for AVR-based platforms +#elif defined(__avr__) + #include + +// Use Wiring's delay for compability with another platforms +#else + #define _delay_ms(ms) delay(ms) +#endif + + +// Legacy Wire.write() function fix +#if (ARDUINO >= 100) + #define __wire_write(d) Wire.write(d) +#else + #define __wire_write(d) Wire.send(d) +#endif + + +// Legacy Wire.read() function fix +#if (ARDUINO >= 100) + #define __wire_read() Wire.read() +#else + #define __wire_read() Wire.receive() +#endif + + +/** + * Constructor + * @params addr Sensor address (0x23 or 0x5C, see datasheet) + * + * Default for BH1750 is 0x23 + */ +BH1750::BH1750(byte addr) { + + BH1750_I2CADDR = addr; + +} + + +/** + * Configure sensor + * @param mode Measurement mode + */ +bool BH1750::begin(Mode mode) { + + // I2C is expected to be initialized outside this library + //DGO Revision for ST_Anything compatability - all other I2C sensor initialize I2C. + // This one was the exception, but I have modified it to be like the others. + Wire.begin(); + // Configure sensor in specified mode + return configure(mode); + +} + + +/** + * Configure BH1750 with specified mode + * @param mode Measurement mode + */ +bool BH1750::configure(Mode mode) { + + // default transmission result to a value out of normal range + byte ack = 5; + + // Check measurement mode is valid + switch (mode) { + + case BH1750::CONTINUOUS_HIGH_RES_MODE: + case BH1750::CONTINUOUS_HIGH_RES_MODE_2: + case BH1750::CONTINUOUS_LOW_RES_MODE: + case BH1750::ONE_TIME_HIGH_RES_MODE: + case BH1750::ONE_TIME_HIGH_RES_MODE_2: + case BH1750::ONE_TIME_LOW_RES_MODE: + + // Send mode to sensor + Wire.beginTransmission(BH1750_I2CADDR); + __wire_write((uint8_t)BH1750_MODE); + ack = Wire.endTransmission(); + + // Wait a few moments to wake up + _delay_ms(10); + break; + + default: + // Invalid measurement mode + Serial.println(F("[BH1750] ERROR: Invalid mode")); + break; + + } + + // Check result code + switch (ack) { + case 0: + BH1750_MODE = mode; + return true; + case 1: // too long for transmit buffer + Serial.println(F("[BH1750] ERROR: too long for transmit buffer")); + case 2: // received NACK on transmit of address + Serial.println(F("[BH1750] ERROR: received NACK on transmit of address")); + case 3: // received NACK on transmit of data + Serial.println(F("[BH1750] ERROR: received NACK on transmit of data")); + case 4: // other error + Serial.println(F("[BH1750] ERROR: other error")); + default: + Serial.println(F("[BH1750] ERROR: undefined error")); + break; + } + + return false; + +} + + +/** + * Read light level from sensor + * @return Light level in lux (0 ~ 65535) + */ +uint16_t BH1750::readLightLevel(bool maxWait) { + + if (BH1750_MODE == UNCONFIGURED) { + Serial.println(F("[BH1750] Device is not configured!")); + return 0; + } + + // Measurement result will be stored here + uint16_t level=65535; + + // Send mode to sensor + Wire.beginTransmission(BH1750_I2CADDR); + __wire_write((uint8_t)BH1750_MODE); + Wire.endTransmission(); + + // Wait for measurement to be taken. + // Measurements have a maximum measurement time and a typical measurement + // time. The maxWait argument determines which measurement wait time is + // used when a one-time mode is being used. The typical (shorter) + // measurement time is used by default and if maxWait is set to True then + // the maximum measurement time will be used. See data sheet pages 2, 5 + // and 7 for more details. + // A continuous mode measurement can be read immediately after re-sending + // the mode command. + + switch (BH1750_MODE) { + + case BH1750::ONE_TIME_LOW_RES_MODE: + case BH1750::ONE_TIME_HIGH_RES_MODE: + case BH1750::ONE_TIME_HIGH_RES_MODE_2: + + if (BH1750_MODE == BH1750::ONE_TIME_LOW_RES_MODE) { + maxWait ? _delay_ms(24) : _delay_ms(16); + } + else { + maxWait ? _delay_ms(180) :_delay_ms(120); + } + break; + default: break; + } + + // Read two bytes from the sensor, which are low and high parts of the sensor + // value + Wire.requestFrom(BH1750_I2CADDR, 2); + if (Wire.available() == 2) { + level = __wire_read(); + level <<= 8; + level |= __wire_read(); + } + + // Print raw value if debug enabled + #ifdef BH1750_DEBUG + Serial.print(F("[BH1750] Raw value: ")); + Serial.println(level); + #endif + + // Convert raw value to lux + level /= 1.2; + + // Print converted value if debug enabled + #ifdef BH1750_DEBUG + Serial.print(F("[BH1750] Converted value: ")); + Serial.println(level); + #endif + + return level; + +} diff --git a/lib/BH1750/BH1750.h b/lib/BH1750/BH1750.h new file mode 100644 index 0000000..ca68afb --- /dev/null +++ b/lib/BH1750/BH1750.h @@ -0,0 +1,76 @@ +/* + + This is a library for the BH1750FVI Digital Light Sensor + breakout board. + + The BH1750 board uses I2C for communication. Two pins are required to + interface to the device. Configuring the I2C bus is expected to be done + in user code. The BH1750 library doesn't do this automatically. + + Datasheet: http://rohmfs.rohm.com/en/products/databook/datasheet/ic/sensor/light/bh1750fvi-e.pdf + + Written by Christopher Laws, March, 2013. + + Modified by Dan Ogorchock on 2018-07-04 for ST_Anything compatability +*/ + +#ifndef BH1750_h +#define BH1750_h + +#if (ARDUINO >= 100) + #include +#else + #include +#endif + +#include "Wire.h" + +// Uncomment, to enable debug messages +// #define BH1750_DEBUG + +// No active state +#define BH1750_POWER_DOWN 0x00 + +// Wating for measurement command +#define BH1750_POWER_ON 0x01 + +// Reset data register value - not accepted in POWER_DOWN mode +#define BH1750_RESET 0x07 + +//I2C Addresses +#define BH1750_ADDR_LOW 0x23 +#define BH1750_ADDR_HIGH 0x5C + +class BH1750 { + + public: + + enum Mode + { + UNCONFIGURED = 0, + // Measurement at 1lx resolution. Measurement time is approx 120ms. + CONTINUOUS_HIGH_RES_MODE = 0x10, + // Measurement at 0.5lx resolution. Measurement time is approx 120ms. + CONTINUOUS_HIGH_RES_MODE_2 = 0x11, + // Measurement at 4lx resolution. Measurement time is approx 16ms. + CONTINUOUS_LOW_RES_MODE = 0x13, + // Measurement at 1lx resolution. Measurement time is approx 120ms. + ONE_TIME_HIGH_RES_MODE = 0x20, + // Measurement at 0.5lx resolution. Measurement time is approx 120ms. + ONE_TIME_HIGH_RES_MODE_2 = 0x21, + // Measurement at 1lx resolution. Measurement time is approx 120ms. + ONE_TIME_LOW_RES_MODE = 0x23 + }; + + BH1750(byte addr = BH1750_ADDR_LOW); + bool begin(Mode mode = CONTINUOUS_HIGH_RES_MODE); + bool configure(Mode mode); + uint16_t readLightLevel(bool maxWait = false); + + private: + int BH1750_I2CADDR; + Mode BH1750_MODE = UNCONFIGURED; + +}; + +#endif diff --git a/lib/BH1750/LICENSE b/lib/BH1750/LICENSE new file mode 100644 index 0000000..604d838 --- /dev/null +++ b/lib/BH1750/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 claws + +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. diff --git a/lib/BH1750/README.md b/lib/BH1750/README.md new file mode 100644 index 0000000..3ec4327 --- /dev/null +++ b/lib/BH1750/README.md @@ -0,0 +1,142 @@ +# BH1750 + +[![Build Status](https://travis-ci.org/claws/BH1750.svg?branch=master)](https://travis-ci.org/claws/BH1750)
+ +This package contains an Arduino library for digital light sensor breakout boards containing the +BH1750FVI IC. + +The BH1750 board uses I2C for communication which requires two pins to +communicate with the device. Configuring the I2C bus must be done in user code +(not library code). This approach has been adopted so it can be done once and +will better support the various options for different platforms. + +A common module containing the BH1750 component is the GY-30 shown below. + +![GY-30 Module image](resources/gy30-module.jpg) + + +## Overview + +The BH1750 has six different measurement modes which are divided in two groups; +continuous and one-time measurements. In continuous mode the sensor +continuously measures lightness value. In one-time mode, the sensor makes only +one measurement and then goes into Power Down mode. + +Each mode has three different precisions: + + - Low Resolution Mode - (4 lx precision, 16ms measurement time) + - High Resolution Mode - (1 lx precision, 120ms measurement time) + - High Resolution Mode 2 - (0.5 lx precision, 120ms measurement time) + +By default, this library uses Continuous High Resolution Mode, but you can +change this to a different mode by passing the mode argument to +BH1750.begin(). + +When the One-Time mode is used your sensor will go into Power Down mode when +it completes the measurement and you've read it. When the sensor is powered up +again it returns to the default mode which means it needs to be reconfigured +back into One-Time mode. This library has been implemented to automatically +reconfigure the sensor when you next attempt a measurement so you should not +have to worry about such low level details. + +The datasheet for the BH1750 chip can be obtained [here](http://www.elechouse.com/elechouse/images/product/Digital%20light%20Sensor/bh1750fvi-e.pdf) + + +## Installation + +Click "Clone or download" -> "Download ZIP" button. + + - **(For Arduino >= 1.5.x)** Use the way above, or Library Manager. Open Arduino + IDE, click `Sketch -> Include library -> Add .ZIP library ` and select the + downloaded archive. + + - **(For Arduino < 1.5.x)** Extract the archive to + ``/My Documents/Arduino/libraries/`` folder and rename it + to `BH1750`. Restart IDE. + +The following YouTube [video](https://youtu.be/ACTMQvPVMLs) (specifically from +7:20 onwards) provides a good overview of installing this library and loading +an example using the Arduino IDE. + +[![BH1750 Video Tutorial](https://img.youtube.com/vi/ACTMQvPVMLs/0.jpg)](https://youtu.be/ACTMQvPVMLs?t=437) + +Additional info, about library installation process - https://www.arduino.cc/en/Guide/Libraries + + +## Example + +An example using the BH1750 library in conjunction with the GY-30 board +(which contains the BH1750 component) is presented below. The example +code uses the BH1750 library in the default continuous high precision +mode when making light measurements. + +### Wiring + +Connections: + + - VCC -> 3V3 or 5V + - GND -> GND + - SCL -> SCL (A5 on Arduino Nano, Uno, Leonardo, etc or 21 on Mega and Due, on esp8266 free selectable) + - SDA -> SDA (A4 on Arduino Nano, Uno, Leonardo, etc or 20 on Mega and Due, on esp8266 free selectable) + - ADD -> NC/GND or VCC (see below) + +The ADD pin is used to set the sensor I2C address. By default (if ADD voltage +less than 0.7 * VCC) the sensor address will be 0x23. If it has voltage +greater or equal to 0.7VCC voltage (e.g. you've connected it to VCC) the +sensor address will be 0x5C. + +Wiring up the GY-30 sensor board to an Arduino is shown in the diagram below. + +![Example wiring diagram image](resources/wiring-diagram-gy30-module.png) + +*The image above was created using [Fritzing](http://fritzing.org/home/) and +the GY-30 module was obtained from [here](http://omnigatherum.ca/wp/?p=6)*. + +### Code + +Upload the BH1750 test code to your Arduino. + +``` c++ +#include +#include + +BH1750 lightMeter; + +void setup(){ + + Serial.begin(9600); + + // Initialize the I2C bus (BH1750 library doesn't do this automatically) + // On esp8266 devices you can select SCL and SDA pins using Wire.begin(D4, D3); + Wire.begin(); + + lightMeter.begin(); + Serial.println(F("BH1750 Test")); + +} + +void loop() { + + uint16_t lux = lightMeter.readLightLevel(); + Serial.print("Light: "); + Serial.print(lux); + Serial.println(" lx"); + delay(1000); + +} +``` + +### Output + +Moving the sensor to face more light results in the lux measurements increasing. +``` +BH1750 Test +Light: 70 lx +Light: 70 lx +Light: 59 lx +Light: 328 lx +Light: 333 lx +Light: 335 lx +Light: 332 lx +``` +There are more examples in the examples directory. diff --git a/lib/BH1750/build-examples.bash b/lib/BH1750/build-examples.bash new file mode 100644 index 0000000..5ec70f0 --- /dev/null +++ b/lib/BH1750/build-examples.bash @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +# +# A simple script to automate building BH1750 examples. +# +# Example (MacOSX): +# $ ARDUINO_IDE_PATH=/Applications/Arduino.app/Contents/Java ./build-examples.bash +# + +# Path to script directory. +SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )" +LIBNAME="$(basename "$SCRIPTPATH")" + +if [[ -z "${ARDUINO_IDE_PATH}" ]]; then + echo "ARDUINO_IDE_PATH env var is not set" + exit 1 +fi + +# Link BH1750 library into Arduino libraries directory +ln -s $SCRIPTPATH $ARDUINO_IDE_PATH/libraries/ + +cd $ARDUINO_IDE_PATH + +for sketch in `find $SCRIPTPATH/examples -name '*.ino'` +do + echo "Compiling $sketch" + ./arduino-builder -hardware ./hardware -tools ./hardware/tools/avr -tools ./tools-builder -libraries ./libraries -fqbn arduino:avr:uno $sketch + # ./arduino-builder -hardware ./hardware -tools ./hardware/tools/avr -tools ./tools-builder -libraries ./libraries -fqbn esp8266:esp8266:generic $sketch +done + +# Unlink BH1750 library from Arduino libraries directory +unlink $ARDUINO_IDE_PATH/libraries/$LIBNAME diff --git a/lib/BH1750/component.mk b/lib/BH1750/component.mk new file mode 100644 index 0000000..27ad11a --- /dev/null +++ b/lib/BH1750/component.mk @@ -0,0 +1 @@ +COMPONENT_ADD_INCLUDEDIRS := . diff --git a/lib/BH1750/examples/BH1750advanced/BH1750advanced.ino b/lib/BH1750/examples/BH1750advanced/BH1750advanced.ino new file mode 100644 index 0000000..811ee75 --- /dev/null +++ b/lib/BH1750/examples/BH1750advanced/BH1750advanced.ino @@ -0,0 +1,96 @@ +/* + + Advanced BH1750 library usage example + + This example has some comments about advanced usage features. + + Connection: + + VCC -> 3V3 or 5V + GND -> GND + SCL -> SCL (A5 on Arduino Uno, Leonardo, etc or 21 on Mega and Due, on esp8266 free selectable) + SDA -> SDA (A4 on Arduino Uno, Leonardo, etc or 20 on Mega and Due, on esp8266 free selectable) + ADD -> (not connected) or GND + + ADD pin is used to set sensor I2C address. If it has voltage greater or equal to + 0.7VCC voltage (e.g. you've connected it to VCC) the sensor address will be + 0x5C. In other case (if ADD voltage less than 0.7 * VCC) the sensor address will + be 0x23 (by default). + +*/ + +#include +#include + +/* + + BH1750 can be physically configured to use two I2C addresses: + - 0x23 (most common) (if ADD pin had < 0.7VCC voltage) + - 0x5C (if ADD pin had > 0.7VCC voltage) + + Library uses 0x23 address as default, but you can define any other address. + If you had troubles with default value - try to change it to 0x5C. + +*/ +BH1750 lightMeter(0x23); + +void setup(){ + + Serial.begin(9600); + + // Initialize the I2C bus (BH1750 library doesn't do this automatically) + Wire.begin(); + // On esp8266 you can select SCL and SDA pins using Wire.begin(D4, D3); + + /* + + BH1750 has six different measurement modes. They are divided in two groups; + continuous and one-time measurements. In continuous mode, sensor continuously + measures lightness value. In one-time mode the sensor makes only one + measurement and then goes into Power Down mode. + + Each mode, has three different precisions: + + - Low Resolution Mode - (4 lx precision, 16ms measurement time) + - High Resolution Mode - (1 lx precision, 120ms measurement time) + - High Resolution Mode 2 - (0.5 lx precision, 120ms measurement time) + + By default, the library uses Continuous High Resolution Mode, but you can + set any other mode, by passing it to BH1750.begin() or BH1750.configure() + functions. + + [!] Remember, if you use One-Time mode, your sensor will go to Power Down + mode each time, when it completes a measurement and you've read it. + + Full mode list: + + BH1750_CONTINUOUS_LOW_RES_MODE + BH1750_CONTINUOUS_HIGH_RES_MODE (default) + BH1750_CONTINUOUS_HIGH_RES_MODE_2 + + BH1750_ONE_TIME_LOW_RES_MODE + BH1750_ONE_TIME_HIGH_RES_MODE + BH1750_ONE_TIME_HIGH_RES_MODE_2 + + */ + + // begin returns a boolean that can be used to detect setup problems. + if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) { + Serial.println(F("BH1750 Advanced begin")); + } + else { + Serial.println(F("Error initialising BH1750")); + } + +} + + +void loop() { + + uint16_t lux = lightMeter.readLightLevel(); + Serial.print("Light: "); + Serial.print(lux); + Serial.println(" lx"); + delay(1000); + +} diff --git a/lib/BH1750/examples/BH1750onetime/BH1750onetime.ino b/lib/BH1750/examples/BH1750onetime/BH1750onetime.ino new file mode 100644 index 0000000..116f5d8 --- /dev/null +++ b/lib/BH1750/examples/BH1750onetime/BH1750onetime.ino @@ -0,0 +1,42 @@ +/* + + Example of BH1750 library usage. + + This example initialises the BH1750 object using the high resolution + one-time mode and then makes a light level reading every second. + + The BH1750 component starts up in default mode when it next powers up. + The BH1750 library automatically reconfigures the one-time mode in + preparation for the next measurement. + +*/ + +#include +#include + +BH1750 lightMeter; + +void setup(){ + + Serial.begin(9600); + + // Initialize the I2C bus (BH1750 library doesn't do this automatically) + Wire.begin(); + // On esp8266 you can select SCL and SDA pins using Wire.begin(D4, D3); + + lightMeter.begin(BH1750::ONE_TIME_HIGH_RES_MODE); + + Serial.println(F("BH1750 One-Time Test")); + +} + + +void loop() { + + uint16_t lux = lightMeter.readLightLevel(); + Serial.print("Light: "); + Serial.print(lux); + Serial.println(" lx"); + delay(1000); + +} diff --git a/lib/BH1750/examples/BH1750test/BH1750test.ino b/lib/BH1750/examples/BH1750test/BH1750test.ino new file mode 100644 index 0000000..a47e99e --- /dev/null +++ b/lib/BH1750/examples/BH1750test/BH1750test.ino @@ -0,0 +1,52 @@ +/* + + Example of BH1750 library usage. + + This example initialises the BH1750 object using the default high resolution + continuous mode and then makes a light level reading every second. + + Connection: + + VCC -> 3V3 or 5V + GND -> GND + SCL -> SCL (A5 on Arduino Uno, Leonardo, etc or 21 on Mega and Due, on esp8266 free selectable) + SDA -> SDA (A4 on Arduino Uno, Leonardo, etc or 20 on Mega and Due, on esp8266 free selectable) + ADD -> (not connected) or GND + + ADD pin is used to set sensor I2C address. If it has voltage greater or equal to + 0.7VCC voltage (e.g. you've connected it to VCC) the sensor address will be + 0x5C. In other case (if ADD voltage less than 0.7 * VCC) the sensor address will + be 0x23 (by default). + +*/ + +#include +#include + +BH1750 lightMeter; + + +void setup(){ + + Serial.begin(9600); + + // Initialize the I2C bus (BH1750 library doesn't do this automatically) + Wire.begin(); + // On esp8266 you can select SCL and SDA pins using Wire.begin(D4, D3); + + lightMeter.begin(); + + Serial.println(F("BH1750 Test begin")); + +} + + +void loop() { + + uint16_t lux = lightMeter.readLightLevel(); + Serial.print("Light: "); + Serial.print(lux); + Serial.println(" lx"); + delay(1000); + +} diff --git a/lib/BH1750/keywords.txt b/lib/BH1750/keywords.txt new file mode 100644 index 0000000..2813d17 --- /dev/null +++ b/lib/BH1750/keywords.txt @@ -0,0 +1,33 @@ +####################################### +# Syntax Coloring Map For BH1750 +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +BH1750 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +configure KEYWORD2 +readLightLevel KEYWORD2 + + +####################################### +# Instances (KEYWORD2) +####################################### + + +####################################### +# Constants (LITERAL1) +####################################### +BH1750_CONTINUOUS_HIGH_RES_MODE LITERAL1 +BH1750_CONTINUOUS_HIGH_RES_MODE_2 LITERAL1 +BH1750_CONTINUOUS_LOW_RES_MODE LITERAL1 +BH1750_ONE_TIME_HIGH_RES_MODE LITERAL1 +BH1750_ONE_TIME_HIGH_RES_MODE_2 LITERAL1 +BH1750_ONE_TIME_LOW_RES_MODE LITERAL1 diff --git a/lib/BH1750/library.json b/lib/BH1750/library.json new file mode 100644 index 0000000..aba1d2e --- /dev/null +++ b/lib/BH1750/library.json @@ -0,0 +1,11 @@ +{ + "name": "BH1750", + "keywords": "light, sensor", + "description": "Digital light sensor breakout boards containing the BH1750FVI IC", + "repository": { + "type": "git", + "url": "https://github.com/claws/BH1750.git" + }, + "frameworks": "arduino", + "platforms": ["atmelavr", "atmelsam", "espressif8266"] +} diff --git a/lib/BH1750/library.properties b/lib/BH1750/library.properties new file mode 100644 index 0000000..ef0d140 --- /dev/null +++ b/lib/BH1750/library.properties @@ -0,0 +1,10 @@ +name=BH1750 +version=1.1.3 +author=Christopher Laws +maintainer=Christopher Laws +sentence=Digital light sensor breakout boards containing the BH1750FVI IC +paragraph=Pretty simple and robust BH1750 library +category=Sensors +url=https://github.com/claws/BH1750 +architectures=* +includes=BH1750.h diff --git a/lib/BH1750/resources/gy30-module.jpg b/lib/BH1750/resources/gy30-module.jpg new file mode 100644 index 0000000..15cf099 Binary files /dev/null and b/lib/BH1750/resources/gy30-module.jpg differ diff --git a/lib/BH1750/resources/wiring-diagram-gy30-module.png b/lib/BH1750/resources/wiring-diagram-gy30-module.png new file mode 100644 index 0000000..f8efe5c Binary files /dev/null and b/lib/BH1750/resources/wiring-diagram-gy30-module.png differ diff --git a/lib/DHT/dht.cpp b/lib/DHT/dht.cpp new file mode 100644 index 0000000..d195106 --- /dev/null +++ b/lib/DHT/dht.cpp @@ -0,0 +1,169 @@ +// +// FILE: dht.cpp +// AUTHOR: Rob Tillaart +// VERSION: 0.2.0 +// PURPOSE: DHT Temperature & Humidity Sensor library for Arduino +// URL: https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTstable +// +// HISTORY: +// 0.2.1 2017-09-20 fix https://github.com/RobTillaart/Arduino/issues/80 +// 0.2.0 2017-07-24 fix https://github.com/RobTillaart/Arduino/issues/31 + 33 +// 0.1.13 fix negative temperature +// 0.1.12 support DHT33 and DHT44 initial version +// 0.1.11 renamed DHTLIB_TIMEOUT +// 0.1.10 optimized faster WAKEUP + TIMEOUT +// 0.1.09 optimize size: timeout check + use of mask +// 0.1.08 added formula for timeout based upon clockspeed +// 0.1.07 added support for DHT21 +// 0.1.06 minimize footprint (2012-12-27) +// 0.1.05 fixed negative temperature bug (thanks to Roseman) +// 0.1.04 improved readability of code using DHTLIB_OK in code +// 0.1.03 added error values for temp and humidity when read failed +// 0.1.02 added error codes +// 0.1.01 added support for Arduino 1.0, fixed typos (31/12/2011) +// 0.1.0 by Rob Tillaart (01/04/2011) +// +// inspired by DHT11 library +// +// Released to the public domain +// + +#include "dht.h" + +///////////////////////////////////////////////////// +// +// PUBLIC +// + +// return values: +// DHTLIB_OK +// DHTLIB_ERROR_CHECKSUM +// DHTLIB_ERROR_TIMEOUT +int dht::read11(uint8_t pin) +{ + // READ VALUES + int rv = _readSensor(pin, DHTLIB_DHT11_WAKEUP); + if (rv != DHTLIB_OK) + { + humidity = DHTLIB_INVALID_VALUE; // invalid value, or is NaN prefered? + temperature = DHTLIB_INVALID_VALUE; // invalid value + return rv; + } + + // CONVERT AND STORE + humidity = bits[0]; // bits[1] == 0; + temperature = bits[2]; // bits[3] == 0; + + // TEST CHECKSUM + uint8_t sum = bits[0] + bits[1] + bits[2] + bits[3]; + if (bits[4] != sum) + { + return DHTLIB_ERROR_CHECKSUM; + } + return DHTLIB_OK; +} + + +// return values: +// DHTLIB_OK +// DHTLIB_ERROR_CHECKSUM +// DHTLIB_ERROR_TIMEOUT +int dht::read(uint8_t pin) +{ + // READ VALUES + int rv = _readSensor(pin, DHTLIB_DHT_WAKEUP); + if (rv != DHTLIB_OK) + { + humidity = DHTLIB_INVALID_VALUE; // invalid value, or is NaN prefered? + temperature = DHTLIB_INVALID_VALUE; // invalid value + return rv; // propagate error value + } + + // CONVERT AND STORE + humidity = word(bits[0], bits[1]) * 0.1; + temperature = word(bits[2] & 0x7F, bits[3]) * 0.1; + if (bits[2] & 0x80) // negative temperature + { + temperature = -temperature; + } + + // TEST CHECKSUM + uint8_t sum = bits[0] + bits[1] + bits[2] + bits[3]; + if (bits[4] != sum) + { + return DHTLIB_ERROR_CHECKSUM; + } + return DHTLIB_OK; +} + +///////////////////////////////////////////////////// +// +// PRIVATE +// + +// return values: +// DHTLIB_OK +// DHTLIB_ERROR_TIMEOUT +int dht::_readSensor(uint8_t pin, uint8_t wakeupDelay) +{ + // INIT BUFFERVAR TO RECEIVE DATA + uint8_t mask = 128; + uint8_t idx = 0; + + // EMPTY BUFFER + for (uint8_t i = 0; i < 5; i++) bits[i] = 0; + + // REQUEST SAMPLE + pinMode(pin, OUTPUT); + digitalWrite(pin, LOW); + delay(wakeupDelay); + pinMode(pin, INPUT); + delayMicroseconds(40); + + // GET ACKNOWLEDGE or TIMEOUT + uint16_t loopCnt = DHTLIB_TIMEOUT; + while(digitalRead(pin) == LOW) + { + if (--loopCnt == 0) return DHTLIB_ERROR_TIMEOUT; + } + + loopCnt = DHTLIB_TIMEOUT; + while(digitalRead(pin) == HIGH) + { + if (--loopCnt == 0) return DHTLIB_ERROR_TIMEOUT; + } + + // READ THE OUTPUT - 40 BITS => 5 BYTES + for (uint8_t i = 40; i != 0; i--) + { + loopCnt = DHTLIB_TIMEOUT; + while(digitalRead(pin) == LOW) + { + if (--loopCnt == 0) return DHTLIB_ERROR_TIMEOUT; + } + + uint32_t t = micros(); + + loopCnt = DHTLIB_TIMEOUT; + while(digitalRead(pin) == HIGH) + { + if (--loopCnt == 0) return DHTLIB_ERROR_TIMEOUT; + } + + if ((micros() - t) > 40) + { + bits[idx] |= mask; + } + mask >>= 1; + if (mask == 0) // next byte? + { + mask = 128; + idx++; + } + } + + return DHTLIB_OK; +} +// +// END OF FILE +// \ No newline at end of file diff --git a/lib/DHT/dht.h b/lib/DHT/dht.h new file mode 100644 index 0000000..855daac --- /dev/null +++ b/lib/DHT/dht.h @@ -0,0 +1,63 @@ +// +// FILE: dht.h +// AUTHOR: Rob Tillaart +// VERSION: 0.2.1 +// PURPOSE: DHT Temperature & Humidity Sensor library for Arduino +// URL: https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTstable +// +// HISTORY: +// see dht.cpp file +// + +#ifndef dht_h +#define dht_h + +#if ARDUINO < 100 +#include +#else +#include +#endif + +#define DHT_LIB_VERSION "0.2.1 - dhtstable" + +#define DHTLIB_OK 0 +#define DHTLIB_ERROR_CHECKSUM -1 +#define DHTLIB_ERROR_TIMEOUT -2 +#define DHTLIB_INVALID_VALUE -999 + +#define DHTLIB_DHT11_WAKEUP 18 +#define DHTLIB_DHT_WAKEUP 1 + +// max timeout is 100usec. +// For a 16Mhz proc that is max 1600 clock cycles +// loops using TIMEOUT use at least 4 clock cycli +// so 100 us takes max 400 loops +// so by dividing F_CPU by 40000 we "fail" as fast as possible +#define DHTLIB_TIMEOUT (F_CPU/40000) + +class dht +{ +public: + // return values: + // DHTLIB_OK + // DHTLIB_ERROR_CHECKSUM + // DHTLIB_ERROR_TIMEOUT + int read11(uint8_t pin); + int read(uint8_t pin); + + inline int read21(uint8_t pin) { return read(pin); }; + inline int read22(uint8_t pin) { return read(pin); }; + inline int read33(uint8_t pin) { return read(pin); }; + inline int read44(uint8_t pin) { return read(pin); }; + + float humidity; + float temperature; + +private: + uint8_t bits[5]; // buffer to receive data + int _readSensor(uint8_t pin, uint8_t wakeupDelay); +}; +#endif +// +// END OF FILE +// \ No newline at end of file diff --git a/lib/DHT/examples/dht11_test/dht11_test.ino b/lib/DHT/examples/dht11_test/dht11_test.ino new file mode 100644 index 0000000..9308139 --- /dev/null +++ b/lib/DHT/examples/dht11_test/dht11_test.ino @@ -0,0 +1,56 @@ +// +// FILE: dht11_test.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.01 +// PURPOSE: DHT library test sketch for DHT11 && Arduino +// URL: +// +// Released to the public domain +// + +#include + +dht DHT; + +#define DHT11_PIN 5 + +void setup() +{ + Serial.begin(115200); + Serial.println("DHT TEST PROGRAM "); + Serial.print("LIBRARY VERSION: "); + Serial.println(DHT_LIB_VERSION); + Serial.println(); + Serial.println("Type,\tstatus,\tHumidity (%),\tTemperature (C)"); +} + +void loop() +{ + // READ DATA + Serial.print("DHT11, \t"); + int chk = DHT.read11(DHT11_PIN); + switch (chk) + { + case DHTLIB_OK: + Serial.print("OK,\t"); + break; + case DHTLIB_ERROR_CHECKSUM: + Serial.print("Checksum error,\t"); + break; + case DHTLIB_ERROR_TIMEOUT: + Serial.print("Time out error,\t"); + break; + default: + Serial.print("Unknown error,\t"); + break; + } + // DISPLAY DATA + Serial.print(DHT.humidity, 1); + Serial.print(",\t"); + Serial.println(DHT.temperature, 1); + + delay(2000); +} +// +// END OF FILE +// \ No newline at end of file diff --git a/lib/DHT/examples/dht22_test/dht22_test.ino b/lib/DHT/examples/dht22_test/dht22_test.ino new file mode 100644 index 0000000..0c7cbfa --- /dev/null +++ b/lib/DHT/examples/dht22_test/dht22_test.ino @@ -0,0 +1,105 @@ +// +// FILE: dht22_test.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.03 +// PURPOSE: DHT library test sketch for DHT22 && Arduino +// URL: +// HISTORY: +// 0.1.03 extended stats for all errors +// 0.1.02 added counters for error-regression testing. +// 0.1.01 +// 0.1.00 initial version +// +// Released to the public domain +// + +#include + +dht DHT; + +#define DHT22_PIN 5 + +struct +{ + uint32_t total; + uint32_t ok; + uint32_t crc_error; + uint32_t time_out; + uint32_t connect; + uint32_t ack_l; + uint32_t ack_h; + uint32_t unknown; +} stat = { 0,0,0,0,0,0,0,0}; + +void setup() +{ + Serial.begin(115200); + Serial.println("dht22_test.ino"); + Serial.print("LIBRARY VERSION: "); + Serial.println(DHT_LIB_VERSION); + Serial.println(); + Serial.println("Type,\tstatus,\tHumidity (%),\tTemperature (C)\tTime (us)"); +} + +void loop() +{ + // READ DATA + Serial.print("DHT22, \t"); + + uint32_t start = micros(); + int chk = DHT.read22(DHT22_PIN); + uint32_t stop = micros(); + + stat.total++; + switch (chk) + { + case DHTLIB_OK: + stat.ok++; + Serial.print("OK,\t"); + break; + case DHTLIB_ERROR_CHECKSUM: + stat.crc_error++; + Serial.print("Checksum error,\t"); + break; + case DHTLIB_ERROR_TIMEOUT: + stat.time_out++; + Serial.print("Time out error,\t"); + break; + default: + stat.unknown++; + Serial.print("Unknown error,\t"); + break; + } + // DISPLAY DATA + Serial.print(DHT.humidity, 1); + Serial.print(",\t"); + Serial.print(DHT.temperature, 1); + Serial.print(",\t"); + Serial.print(stop - start); + Serial.println(); + + if (stat.total % 20 == 0) + { + Serial.println("\nTOT\tOK\tCRC\tTO\tUNK"); + Serial.print(stat.total); + Serial.print("\t"); + Serial.print(stat.ok); + Serial.print("\t"); + Serial.print(stat.crc_error); + Serial.print("\t"); + Serial.print(stat.time_out); + Serial.print("\t"); + Serial.print(stat.connect); + Serial.print("\t"); + Serial.print(stat.ack_l); + Serial.print("\t"); + Serial.print(stat.ack_h); + Serial.print("\t"); + Serial.print(stat.unknown); + Serial.println("\n"); + } + delay(2000); +} +// +// END OF FILE +// \ No newline at end of file diff --git a/lib/DHT/examples/readme.txt b/lib/DHT/examples/readme.txt new file mode 100644 index 0000000..deb168c --- /dev/null +++ b/lib/DHT/examples/readme.txt @@ -0,0 +1,2 @@ +2015-08-20 these examples are retrofitted from version 0.1.20 which supports more errors. + diff --git a/lib/DHT/keywords.txt b/lib/DHT/keywords.txt new file mode 100644 index 0000000..e5f552a --- /dev/null +++ b/lib/DHT/keywords.txt @@ -0,0 +1,32 @@ +####################################### +# Syntax Coloring Map For DHT +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +DHT KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +read KEYWORD2 +read11 KEYWORD2 +read21 KEYWORD2 +read22 KEYWORD2 +read33 KEYWORD2 +read44 KEYWORD2 +humidity KEYWORD2 +temperature KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/lib/DHT/library.json b/lib/DHT/library.json new file mode 100644 index 0000000..d04d56b --- /dev/null +++ b/lib/DHT/library.json @@ -0,0 +1,23 @@ +{ + "name": "DHTStable", + "keywords": "DHT11 DHT22 DHT33 DHT44 AM2301 AM2302 AM2303", + "description": "Stable version of the library for DHT Temperature & Humidity Sensor.", + "authors": + [ + { + "name": "Rob Tillaart", + "email": "Rob.Tillaart@gmail.com", + "maintainer": true + } + ], + "repository": + { + "type": "git", + "url": "https://github.com/RobTillaart/Arduino.git" + }, + "frameworks": "arduino", + "platforms": "atmelavr", + "export": { + "include": "libraries/DHTstable" + } +} diff --git a/lib/DHT/library.properties b/lib/DHT/library.properties new file mode 100644 index 0000000..560f6e0 --- /dev/null +++ b/lib/DHT/library.properties @@ -0,0 +1,9 @@ +name=DHTStable +version=0.2.1 +author=Rob Tillaart +maintainer=Rob Tillaart +sentence=Stable version of library for DHT Temperature & Humidity Sensor +paragraph= +category=Sensors +url=https://github.com/RobTillaart/Arduino/tree/master/libraries/ +architectures=* \ No newline at end of file diff --git a/lib/DHT/readme.md b/lib/DHT/readme.md new file mode 100644 index 0000000..8872bd7 --- /dev/null +++ b/lib/DHT/readme.md @@ -0,0 +1,13 @@ + +This is the 0.2.1 version of the DHTlib. +This version is stable for both ARM and AVR. + +You can use most examples from https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTlib/examples + +update 2015-10-12: +For multithreading environments for Arduino one could replace + delay(wakeupDelay); +with + delayMicroseconds(wakeupDelay * 1000UL); +see also - https://github.com/RobTillaart/Arduino/pull/25 - + diff --git a/lib/DHT/readme.txt b/lib/DHT/readme.txt new file mode 100644 index 0000000..a6de886 --- /dev/null +++ b/lib/DHT/readme.txt @@ -0,0 +1,13 @@ + +This is the 0.1.13 version of the DHTlib. +This version is stable for both ARM and AVR. + +You can use most examples from https://github.com/RobTillaart/Arduino/tree/master/libraries/DHTlib/examples + +update 2015-10-12: +For multithreading environments for Arduino one could replace + delay(wakeupDelay); +with + delayMicroseconds(wakeupDelay * 1000UL); +see also - https://github.com/RobTillaart/Arduino/pull/25 - + diff --git a/lib/DallasTemperature/DallasTemperature.cpp b/lib/DallasTemperature/DallasTemperature.cpp new file mode 100644 index 0000000..cf97598 --- /dev/null +++ b/lib/DallasTemperature/DallasTemperature.cpp @@ -0,0 +1,885 @@ +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. + +#include "DallasTemperature.h" + +#if ARDUINO >= 100 +#include "Arduino.h" +#else +extern "C" { +#include "WConstants.h" +} +#endif + +// OneWire commands +#define STARTCONVO 0x44 // Tells device to take a temperature reading and put it on the scratchpad +#define COPYSCRATCH 0x48 // Copy EEPROM +#define READSCRATCH 0xBE // Read EEPROM +#define WRITESCRATCH 0x4E // Write to EEPROM +#define RECALLSCRATCH 0xB8 // Reload from last known +#define READPOWERSUPPLY 0xB4 // Determine if device needs parasite power +#define ALARMSEARCH 0xEC // Query bus for devices with an alarm condition + +// Scratchpad locations +#define TEMP_LSB 0 +#define TEMP_MSB 1 +#define HIGH_ALARM_TEMP 2 +#define LOW_ALARM_TEMP 3 +#define CONFIGURATION 4 +#define INTERNAL_BYTE 5 +#define COUNT_REMAIN 6 +#define COUNT_PER_C 7 +#define SCRATCHPAD_CRC 8 + +// Device resolution +#define TEMP_9_BIT 0x1F // 9 bit +#define TEMP_10_BIT 0x3F // 10 bit +#define TEMP_11_BIT 0x5F // 11 bit +#define TEMP_12_BIT 0x7F // 12 bit + +#define NO_ALARM_HANDLER ((AlarmHandler *)0) + +DallasTemperature::DallasTemperature() +{ +#if REQUIRESALARMS + setAlarmHandler(NO_ALARM_HANDLER); +#endif +} +DallasTemperature::DallasTemperature(OneWire* _oneWire) +{ + setOneWire(_oneWire); +#if REQUIRESALARMS + setAlarmHandler(NO_ALARM_HANDLER); +#endif +} + +bool DallasTemperature::validFamily(const uint8_t* deviceAddress) { + switch (deviceAddress[0]) { + case DS18S20MODEL: + case DS18B20MODEL: + case DS1822MODEL: + case DS1825MODEL: + case DS28EA00MODEL: + return true; + default: + return false; + } +} + +void DallasTemperature::setOneWire(OneWire* _oneWire) { + + _wire = _oneWire; + devices = 0; + ds18Count = 0; + parasite = false; + bitResolution = 9; + waitForConversion = true; + checkForConversion = true; + +} + +// initialise the bus +void DallasTemperature::begin(void) { + + DeviceAddress deviceAddress; + + _wire->reset_search(); + devices = 0; // Reset the number of devices when we enumerate wire devices + ds18Count = 0; // Reset number of DS18xxx Family devices + + while (_wire->search(deviceAddress)) { + + if (validAddress(deviceAddress)) { + + if (!parasite && readPowerSupply(deviceAddress)) + parasite = true; + + bitResolution = max(bitResolution, getResolution(deviceAddress)); + + devices++; + if (validFamily(deviceAddress)) { + ds18Count++; + } + } + } + +} + +// returns the number of devices found on the bus +uint8_t DallasTemperature::getDeviceCount(void) { + return devices; +} + +uint8_t DallasTemperature::getDS18Count(void) { + return ds18Count; +} + +// returns true if address is valid +bool DallasTemperature::validAddress(const uint8_t* deviceAddress) { + return (_wire->crc8(deviceAddress, 7) == deviceAddress[7]); +} + +// finds an address at a given index on the bus +// returns true if the device was found +bool DallasTemperature::getAddress(uint8_t* deviceAddress, uint8_t index) { + + uint8_t depth = 0; + + _wire->reset_search(); + + while (depth <= index && _wire->search(deviceAddress)) { + if (depth == index && validAddress(deviceAddress)) + return true; + depth++; + } + + return false; + +} + +// attempt to determine if the device at the given address is connected to the bus +bool DallasTemperature::isConnected(const uint8_t* deviceAddress) { + + ScratchPad scratchPad; + return isConnected(deviceAddress, scratchPad); + +} + +// attempt to determine if the device at the given address is connected to the bus +// also allows for updating the read scratchpad +bool DallasTemperature::isConnected(const uint8_t* deviceAddress, + uint8_t* scratchPad) { + bool b = readScratchPad(deviceAddress, scratchPad); + return b && (_wire->crc8(scratchPad, 8) == scratchPad[SCRATCHPAD_CRC]); +} + +bool DallasTemperature::readScratchPad(const uint8_t* deviceAddress, + uint8_t* scratchPad) { + + // send the reset command and fail fast + int b = _wire->reset(); + if (b == 0) + return false; + + _wire->select(deviceAddress); + _wire->write(READSCRATCH); + + // Read all registers in a simple loop + // byte 0: temperature LSB + // byte 1: temperature MSB + // byte 2: high alarm temp + // byte 3: low alarm temp + // byte 4: DS18S20: store for crc + // DS18B20 & DS1822: configuration register + // byte 5: internal use & crc + // byte 6: DS18S20: COUNT_REMAIN + // DS18B20 & DS1822: store for crc + // byte 7: DS18S20: COUNT_PER_C + // DS18B20 & DS1822: store for crc + // byte 8: SCRATCHPAD_CRC + for (uint8_t i = 0; i < 9; i++) { + scratchPad[i] = _wire->read(); + } + + b = _wire->reset(); + return (b == 1); +} + +void DallasTemperature::writeScratchPad(const uint8_t* deviceAddress, + const uint8_t* scratchPad) { + + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(WRITESCRATCH); + _wire->write(scratchPad[HIGH_ALARM_TEMP]); // high alarm temp + _wire->write(scratchPad[LOW_ALARM_TEMP]); // low alarm temp + + // DS1820 and DS18S20 have no configuration register + if (deviceAddress[0] != DS18S20MODEL) + _wire->write(scratchPad[CONFIGURATION]); + + _wire->reset(); + + // save the newly written values to eeprom + _wire->select(deviceAddress); + _wire->write(COPYSCRATCH, parasite); + delay(20); // <--- added 20ms delay to allow 10ms long EEPROM write operation (as specified by datasheet) + + if (parasite) + delay(10); // 10ms delay + _wire->reset(); + +} + +bool DallasTemperature::readPowerSupply(const uint8_t* deviceAddress) { + + bool ret = false; + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(READPOWERSUPPLY); + if (_wire->read_bit() == 0) + ret = true; + _wire->reset(); + return ret; + +} + +// set resolution of all devices to 9, 10, 11, or 12 bits +// if new resolution is out of range, it is constrained. +void DallasTemperature::setResolution(uint8_t newResolution) { + + bitResolution = constrain(newResolution, 9, 12); + DeviceAddress deviceAddress; + for (int i = 0; i < devices; i++) { + getAddress(deviceAddress, i); + setResolution(deviceAddress, bitResolution, true); + } + +} + +// set resolution of a device to 9, 10, 11, or 12 bits +// if new resolution is out of range, 9 bits is used. +bool DallasTemperature::setResolution(const uint8_t* deviceAddress, + uint8_t newResolution, bool skipGlobalBitResolutionCalculation) { + + // ensure same behavior as setResolution(uint8_t newResolution) + newResolution = constrain(newResolution, 9, 12); + + // return when stored value == new value + if (getResolution(deviceAddress) == newResolution) + return true; + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) { + + // DS1820 and DS18S20 have no resolution configuration register + if (deviceAddress[0] != DS18S20MODEL) { + + switch (newResolution) { + case 12: + scratchPad[CONFIGURATION] = TEMP_12_BIT; + break; + case 11: + scratchPad[CONFIGURATION] = TEMP_11_BIT; + break; + case 10: + scratchPad[CONFIGURATION] = TEMP_10_BIT; + break; + case 9: + default: + scratchPad[CONFIGURATION] = TEMP_9_BIT; + break; + } + writeScratchPad(deviceAddress, scratchPad); + + // without calculation we can always set it to max + bitResolution = max(bitResolution, newResolution); + + if (!skipGlobalBitResolutionCalculation + && (bitResolution > newResolution)) { + bitResolution = newResolution; + DeviceAddress deviceAddr; + for (int i = 0; i < devices; i++) { + getAddress(deviceAddr, i); + bitResolution = max(bitResolution, + getResolution(deviceAddr)); + } + } + } + return true; // new value set + } + + return false; + +} + +// returns the global resolution +uint8_t DallasTemperature::getResolution() { + return bitResolution; +} + +// returns the current resolution of the device, 9-12 +// returns 0 if device not found +uint8_t DallasTemperature::getResolution(const uint8_t* deviceAddress) { + + // DS1820 and DS18S20 have no resolution configuration register + if (deviceAddress[0] == DS18S20MODEL) + return 12; + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) { + switch (scratchPad[CONFIGURATION]) { + case TEMP_12_BIT: + return 12; + + case TEMP_11_BIT: + return 11; + + case TEMP_10_BIT: + return 10; + + case TEMP_9_BIT: + return 9; + } + } + return 0; + +} + +// sets the value of the waitForConversion flag +// TRUE : function requestTemperature() etc returns when conversion is ready +// FALSE: function requestTemperature() etc returns immediately (USE WITH CARE!!) +// (1) programmer has to check if the needed delay has passed +// (2) but the application can do meaningful things in that time +void DallasTemperature::setWaitForConversion(bool flag) { + waitForConversion = flag; +} + +// gets the value of the waitForConversion flag +bool DallasTemperature::getWaitForConversion() { + return waitForConversion; +} + +// sets the value of the checkForConversion flag +// TRUE : function requestTemperature() etc will 'listen' to an IC to determine whether a conversion is complete +// FALSE: function requestTemperature() etc will wait a set time (worst case scenario) for a conversion to complete +void DallasTemperature::setCheckForConversion(bool flag) { + checkForConversion = flag; +} + +// gets the value of the waitForConversion flag +bool DallasTemperature::getCheckForConversion() { + return checkForConversion; +} + +bool DallasTemperature::isConversionComplete() { + uint8_t b = _wire->read_bit(); + return (b == 1); +} + +// sends command for all devices on the bus to perform a temperature conversion +void DallasTemperature::requestTemperatures() { + + _wire->reset(); + _wire->skip(); + _wire->write(STARTCONVO, parasite); + + // ASYNC mode? + if (!waitForConversion) + return; + blockTillConversionComplete(bitResolution); + +} + +// sends command for one device to perform a temperature by address +// returns FALSE if device is disconnected +// returns TRUE otherwise +bool DallasTemperature::requestTemperaturesByAddress( + const uint8_t* deviceAddress) { + + uint8_t bitResolution = getResolution(deviceAddress); + if (bitResolution == 0) { + return false; //Device disconnected + } + + _wire->reset(); + _wire->select(deviceAddress); + _wire->write(STARTCONVO, parasite); + + // ASYNC mode? + if (!waitForConversion) + return true; + + blockTillConversionComplete(bitResolution); + + return true; + +} + +// Continue to check if the IC has responded with a temperature +void DallasTemperature::blockTillConversionComplete(uint8_t bitResolution) { + + int delms = millisToWaitForConversion(bitResolution); + if (checkForConversion && !parasite) { + unsigned long now = millis(); + while (!isConversionComplete() && (millis() - delms < now)) + ; + } else { + delay(delms); + } + +} + +// returns number of milliseconds to wait till conversion is complete (based on IC datasheet) +int16_t DallasTemperature::millisToWaitForConversion(uint8_t bitResolution) { + + switch (bitResolution) { + case 9: + return 94; + case 10: + return 188; + case 11: + return 375; + default: + return 750; + } + +} + +// sends command for one device to perform a temp conversion by index +bool DallasTemperature::requestTemperaturesByIndex(uint8_t deviceIndex) { + + DeviceAddress deviceAddress; + getAddress(deviceAddress, deviceIndex); + + return requestTemperaturesByAddress(deviceAddress); + +} + +// Fetch temperature for device index +float DallasTemperature::getTempCByIndex(uint8_t deviceIndex) { + + DeviceAddress deviceAddress; + if (!getAddress(deviceAddress, deviceIndex)) { + return DEVICE_DISCONNECTED_C; + } + + return getTempC((uint8_t*) deviceAddress); + +} + +// Fetch temperature for device index +float DallasTemperature::getTempFByIndex(uint8_t deviceIndex) { + + DeviceAddress deviceAddress; + + if (!getAddress(deviceAddress, deviceIndex)) { + return DEVICE_DISCONNECTED_F; + } + + return getTempF((uint8_t*) deviceAddress); + +} + +// reads scratchpad and returns fixed-point temperature, scaling factor 2^-7 +int16_t DallasTemperature::calculateTemperature(const uint8_t* deviceAddress, + uint8_t* scratchPad) { + + int16_t fpTemperature = (((int16_t) scratchPad[TEMP_MSB]) << 11) + | (((int16_t) scratchPad[TEMP_LSB]) << 3); + + /* + DS1820 and DS18S20 have a 9-bit temperature register. + + Resolutions greater than 9-bit can be calculated using the data from + the temperature, and COUNT REMAIN and COUNT PER °C registers in the + scratchpad. The resolution of the calculation depends on the model. + + While the COUNT PER °C register is hard-wired to 16 (10h) in a + DS18S20, it changes with temperature in DS1820. + + After reading the scratchpad, the TEMP_READ value is obtained by + truncating the 0.5°C bit (bit 0) from the temperature data. The + extended resolution temperature can then be calculated using the + following equation: + + COUNT_PER_C - COUNT_REMAIN + TEMPERATURE = TEMP_READ - 0.25 + -------------------------- + COUNT_PER_C + + Hagai Shatz simplified this to integer arithmetic for a 12 bits + value for a DS18S20, and James Cameron added legacy DS1820 support. + + See - http://myarduinotoy.blogspot.co.uk/2013/02/12bit-result-from-ds18s20.html + */ + + if (deviceAddress[0] == DS18S20MODEL) { + fpTemperature = ((fpTemperature & 0xfff0) << 3) - 16 + + (((scratchPad[COUNT_PER_C] - scratchPad[COUNT_REMAIN]) << 7) + / scratchPad[COUNT_PER_C]); + } + + return fpTemperature; +} + +// returns temperature in 1/128 degrees C or DEVICE_DISCONNECTED_RAW if the +// device's scratch pad cannot be read successfully. +// the numeric value of DEVICE_DISCONNECTED_RAW is defined in +// DallasTemperature.h. It is a large negative number outside the +// operating range of the device +int16_t DallasTemperature::getTemp(const uint8_t* deviceAddress) { + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + return calculateTemperature(deviceAddress, scratchPad); + return DEVICE_DISCONNECTED_RAW; + +} + +// returns temperature in degrees C or DEVICE_DISCONNECTED_C if the +// device's scratch pad cannot be read successfully. +// the numeric value of DEVICE_DISCONNECTED_C is defined in +// DallasTemperature.h. It is a large negative number outside the +// operating range of the device +float DallasTemperature::getTempC(const uint8_t* deviceAddress) { + return rawToCelsius(getTemp(deviceAddress)); +} + +// returns temperature in degrees F or DEVICE_DISCONNECTED_F if the +// device's scratch pad cannot be read successfully. +// the numeric value of DEVICE_DISCONNECTED_F is defined in +// DallasTemperature.h. It is a large negative number outside the +// operating range of the device +float DallasTemperature::getTempF(const uint8_t* deviceAddress) { + return rawToFahrenheit(getTemp(deviceAddress)); +} + +// returns true if the bus requires parasite power +bool DallasTemperature::isParasitePowerMode(void) { + return parasite; +} + +// IF alarm is not used one can store a 16 bit int of userdata in the alarm +// registers. E.g. an ID of the sensor. +// See github issue #29 + +// note if device is not connected it will fail writing the data. +void DallasTemperature::setUserData(const uint8_t* deviceAddress, + int16_t data) { + // return when stored value == new value + if (getUserData(deviceAddress) == data) + return; + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) { + scratchPad[HIGH_ALARM_TEMP] = data >> 8; + scratchPad[LOW_ALARM_TEMP] = data & 255; + writeScratchPad(deviceAddress, scratchPad); + } +} + +int16_t DallasTemperature::getUserData(const uint8_t* deviceAddress) { + int16_t data = 0; + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) { + data = scratchPad[HIGH_ALARM_TEMP] << 8; + data += scratchPad[LOW_ALARM_TEMP]; + } + return data; +} + +// note If address cannot be found no error will be reported. +int16_t DallasTemperature::getUserDataByIndex(uint8_t deviceIndex) { + DeviceAddress deviceAddress; + getAddress(deviceAddress, deviceIndex); + return getUserData((uint8_t*) deviceAddress); +} + +void DallasTemperature::setUserDataByIndex(uint8_t deviceIndex, int16_t data) { + DeviceAddress deviceAddress; + getAddress(deviceAddress, deviceIndex); + setUserData((uint8_t*) deviceAddress, data); +} + +// Convert float Celsius to Fahrenheit +float DallasTemperature::toFahrenheit(float celsius) { + return (celsius * 1.8) + 32; +} + +// Convert float Fahrenheit to Celsius +float DallasTemperature::toCelsius(float fahrenheit) { + return (fahrenheit - 32) * 0.555555556; +} + +// convert from raw to Celsius +float DallasTemperature::rawToCelsius(int16_t raw) { + + if (raw <= DEVICE_DISCONNECTED_RAW) + return DEVICE_DISCONNECTED_C; + // C = RAW/128 + return (float) raw * 0.0078125; + +} + +// convert from raw to Fahrenheit +float DallasTemperature::rawToFahrenheit(int16_t raw) { + + if (raw <= DEVICE_DISCONNECTED_RAW) + return DEVICE_DISCONNECTED_F; + // C = RAW/128 + // F = (C*1.8)+32 = (RAW/128*1.8)+32 = (RAW*0.0140625)+32 + return ((float) raw * 0.0140625) + 32; + +} + +#if REQUIRESALARMS + +/* + + ALARMS: + + TH and TL Register Format + + BIT 7 BIT 6 BIT 5 BIT 4 BIT 3 BIT 2 BIT 1 BIT 0 + S 2^6 2^5 2^4 2^3 2^2 2^1 2^0 + + Only bits 11 through 4 of the temperature register are used + in the TH and TL comparison since TH and TL are 8-bit + registers. If the measured temperature is lower than or equal + to TL or higher than or equal to TH, an alarm condition exists + and an alarm flag is set inside the DS18B20. This flag is + updated after every temperature measurement; therefore, if the + alarm condition goes away, the flag will be turned off after + the next temperature conversion. + + */ + +// sets the high alarm temperature for a device in degrees Celsius +// accepts a float, but the alarm resolution will ignore anything +// after a decimal point. valid range is -55C - 125C +void DallasTemperature::setHighAlarmTemp(const uint8_t* deviceAddress, + int8_t celsius) { + + // return when stored value == new value + if (getHighAlarmTemp(deviceAddress) == celsius) + return; + + // make sure the alarm temperature is within the device's range + if (celsius > 125) + celsius = 125; + else if (celsius < -55) + celsius = -55; + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) { + scratchPad[HIGH_ALARM_TEMP] = (uint8_t) celsius; + writeScratchPad(deviceAddress, scratchPad); + } + +} + +// sets the low alarm temperature for a device in degrees Celsius +// accepts a float, but the alarm resolution will ignore anything +// after a decimal point. valid range is -55C - 125C +void DallasTemperature::setLowAlarmTemp(const uint8_t* deviceAddress, + int8_t celsius) { + + // return when stored value == new value + if (getLowAlarmTemp(deviceAddress) == celsius) + return; + + // make sure the alarm temperature is within the device's range + if (celsius > 125) + celsius = 125; + else if (celsius < -55) + celsius = -55; + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) { + scratchPad[LOW_ALARM_TEMP] = (uint8_t) celsius; + writeScratchPad(deviceAddress, scratchPad); + } + +} + +// returns a int8_t with the current high alarm temperature or +// DEVICE_DISCONNECTED for an address +int8_t DallasTemperature::getHighAlarmTemp(const uint8_t* deviceAddress) { + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + return (int8_t) scratchPad[HIGH_ALARM_TEMP]; + return DEVICE_DISCONNECTED_C; + +} + +// returns a int8_t with the current low alarm temperature or +// DEVICE_DISCONNECTED for an address +int8_t DallasTemperature::getLowAlarmTemp(const uint8_t* deviceAddress) { + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) + return (int8_t) scratchPad[LOW_ALARM_TEMP]; + return DEVICE_DISCONNECTED_C; + +} + +// resets internal variables used for the alarm search +void DallasTemperature::resetAlarmSearch() { + + alarmSearchJunction = -1; + alarmSearchExhausted = 0; + for (uint8_t i = 0; i < 7; i++) { + alarmSearchAddress[i] = 0; + } + +} + +// This is a modified version of the OneWire::search method. +// +// Also added the OneWire search fix documented here: +// http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295 +// +// Perform an alarm search. If this function returns a '1' then it has +// enumerated the next device and you may retrieve the ROM from the +// OneWire::address variable. If there are no devices, no further +// devices, or something horrible happens in the middle of the +// enumeration then a 0 is returned. If a new device is found then +// its address is copied to newAddr. Use +// DallasTemperature::resetAlarmSearch() to start over. +bool DallasTemperature::alarmSearch(uint8_t* newAddr) { + + uint8_t i; + int8_t lastJunction = -1; + uint8_t done = 1; + + if (alarmSearchExhausted) + return false; + if (!_wire->reset()) + return false; + + // send the alarm search command + _wire->write(0xEC, 0); + + for (i = 0; i < 64; i++) { + + uint8_t a = _wire->read_bit(); + uint8_t nota = _wire->read_bit(); + uint8_t ibyte = i / 8; + uint8_t ibit = 1 << (i & 7); + + // I don't think this should happen, this means nothing responded, but maybe if + // something vanishes during the search it will come up. + if (a && nota) + return false; + + if (!a && !nota) { + if (i == alarmSearchJunction) { + // this is our time to decide differently, we went zero last time, go one. + a = 1; + alarmSearchJunction = lastJunction; + } else if (i < alarmSearchJunction) { + + // take whatever we took last time, look in address + if (alarmSearchAddress[ibyte] & ibit) { + a = 1; + } else { + // Only 0s count as pending junctions, we've already exhausted the 0 side of 1s + a = 0; + done = 0; + lastJunction = i; + } + } else { + // we are blazing new tree, take the 0 + a = 0; + alarmSearchJunction = i; + done = 0; + } + // OneWire search fix + // See: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295 + } + + if (a) + alarmSearchAddress[ibyte] |= ibit; + else + alarmSearchAddress[ibyte] &= ~ibit; + + _wire->write_bit(a); + } + + if (done) + alarmSearchExhausted = 1; + for (i = 0; i < 8; i++) + newAddr[i] = alarmSearchAddress[i]; + return true; + +} + +// returns true if device address might have an alarm condition +// (only an alarm search can verify this) +bool DallasTemperature::hasAlarm(const uint8_t* deviceAddress) { + + ScratchPad scratchPad; + if (isConnected(deviceAddress, scratchPad)) { + + int8_t temp = calculateTemperature(deviceAddress, scratchPad) >> 7; + + // check low alarm + if (temp <= (int8_t) scratchPad[LOW_ALARM_TEMP]) + return true; + + // check high alarm + if (temp >= (int8_t) scratchPad[HIGH_ALARM_TEMP]) + return true; + } + + // no alarm + return false; + +} + +// returns true if any device is reporting an alarm condition on the bus +bool DallasTemperature::hasAlarm(void) { + + DeviceAddress deviceAddress; + resetAlarmSearch(); + return alarmSearch(deviceAddress); +} + +// runs the alarm handler for all devices returned by alarmSearch() +// unless there no _AlarmHandler exist. +void DallasTemperature::processAlarms(void) { + +if (!hasAlarmHandler()) +{ + return; +} + + resetAlarmSearch(); + DeviceAddress alarmAddr; + + while (alarmSearch(alarmAddr)) { + if (validAddress(alarmAddr)) { + _AlarmHandler(alarmAddr); + } + } +} + +// sets the alarm handler +void DallasTemperature::setAlarmHandler(const AlarmHandler *handler) { + _AlarmHandler = handler; +} + +// checks if AlarmHandler has been set. +bool DallasTemperature::hasAlarmHandler() +{ + return _AlarmHandler != NO_ALARM_HANDLER; +} + +#endif + +#if REQUIRESNEW + +// MnetCS - Allocates memory for DallasTemperature. Allows us to instance a new object +void* DallasTemperature::operator new(unsigned int size) { // Implicit NSS obj size + + void * p;// void pointer + p = malloc(size);// Allocate memory + memset((DallasTemperature*)p,0,size);// Initialise memory + + //!!! CANT EXPLICITLY CALL CONSTRUCTOR - workaround by using an init() methodR - workaround by using an init() method + return (DallasTemperature*) p;// Cast blank region to NSS pointer +} + +// MnetCS 2009 - Free the memory used by this instance +void DallasTemperature::operator delete(void* p) { + + DallasTemperature* pNss = (DallasTemperature*) p; // Cast to NSS pointer + pNss->~DallasTemperature();// Destruct the object + + free(p);// Free the memory +} + +#endif diff --git a/lib/DallasTemperature/DallasTemperature.h b/lib/DallasTemperature/DallasTemperature.h new file mode 100644 index 0000000..dc58af3 --- /dev/null +++ b/lib/DallasTemperature/DallasTemperature.h @@ -0,0 +1,251 @@ +#ifndef DallasTemperature_h +#define DallasTemperature_h + +#define DALLASTEMPLIBVERSION "3.7.9" // To be deprecated + +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. + +// set to true to include code for new and delete operators +#ifndef REQUIRESNEW +#define REQUIRESNEW false +#endif + +// set to true to include code implementing alarm search functions +#ifndef REQUIRESALARMS +#define REQUIRESALARMS true +#endif + +#include +#include + +// Model IDs +#define DS18S20MODEL 0x10 // also DS1820 +#define DS18B20MODEL 0x28 +#define DS1822MODEL 0x22 +#define DS1825MODEL 0x3B +#define DS28EA00MODEL 0x42 + +// Error Codes +#define DEVICE_DISCONNECTED_C -127 +#define DEVICE_DISCONNECTED_F -196.6 +#define DEVICE_DISCONNECTED_RAW -7040 + +typedef uint8_t DeviceAddress[8]; + +class DallasTemperature { +public: + + DallasTemperature(); + DallasTemperature(OneWire*); + + void setOneWire(OneWire*); + + // initialise bus + void begin(void); + + // returns the number of devices found on the bus + uint8_t getDeviceCount(void); + + // returns the number of DS18xxx Family devices on bus + uint8_t getDS18Count(void); + + // returns true if address is valid + bool validAddress(const uint8_t*); + + // returns true if address is of the family of sensors the lib supports. + bool validFamily(const uint8_t* deviceAddress); + + // finds an address at a given index on the bus + bool getAddress(uint8_t*, uint8_t); + + // attempt to determine if the device at the given address is connected to the bus + bool isConnected(const uint8_t*); + + // attempt to determine if the device at the given address is connected to the bus + // also allows for updating the read scratchpad + bool isConnected(const uint8_t*, uint8_t*); + + // read device's scratchpad + bool readScratchPad(const uint8_t*, uint8_t*); + + // write device's scratchpad + void writeScratchPad(const uint8_t*, const uint8_t*); + + // read device's power requirements + bool readPowerSupply(const uint8_t*); + + // get global resolution + uint8_t getResolution(); + + // set global resolution to 9, 10, 11, or 12 bits + void setResolution(uint8_t); + + // returns the device resolution: 9, 10, 11, or 12 bits + uint8_t getResolution(const uint8_t*); + + // set resolution of a device to 9, 10, 11, or 12 bits + bool setResolution(const uint8_t*, uint8_t, + bool skipGlobalBitResolutionCalculation = false); + + // sets/gets the waitForConversion flag + void setWaitForConversion(bool); + bool getWaitForConversion(void); + + // sets/gets the checkForConversion flag + void setCheckForConversion(bool); + bool getCheckForConversion(void); + + // sends command for all devices on the bus to perform a temperature conversion + void requestTemperatures(void); + + // sends command for one device to perform a temperature conversion by address + bool requestTemperaturesByAddress(const uint8_t*); + + // sends command for one device to perform a temperature conversion by index + bool requestTemperaturesByIndex(uint8_t); + + // returns temperature raw value (12 bit integer of 1/128 degrees C) + int16_t getTemp(const uint8_t*); + + // returns temperature in degrees C + float getTempC(const uint8_t*); + + // returns temperature in degrees F + float getTempF(const uint8_t*); + + // Get temperature for device index (slow) + float getTempCByIndex(uint8_t); + + // Get temperature for device index (slow) + float getTempFByIndex(uint8_t); + + // returns true if the bus requires parasite power + bool isParasitePowerMode(void); + + // Is a conversion complete on the wire? Only applies to the first sensor on the wire. + bool isConversionComplete(void); + + int16_t millisToWaitForConversion(uint8_t); + +#if REQUIRESALARMS + + typedef void AlarmHandler(const uint8_t*); + + // sets the high alarm temperature for a device + // accepts a int8_t. valid range is -55C - 125C + void setHighAlarmTemp(const uint8_t*, int8_t); + + // sets the low alarm temperature for a device + // accepts a int8_t. valid range is -55C - 125C + void setLowAlarmTemp(const uint8_t*, int8_t); + + // returns a int8_t with the current high alarm temperature for a device + // in the range -55C - 125C + int8_t getHighAlarmTemp(const uint8_t*); + + // returns a int8_t with the current low alarm temperature for a device + // in the range -55C - 125C + int8_t getLowAlarmTemp(const uint8_t*); + + // resets internal variables used for the alarm search + void resetAlarmSearch(void); + + // search the wire for devices with active alarms + bool alarmSearch(uint8_t*); + + // returns true if ia specific device has an alarm + bool hasAlarm(const uint8_t*); + + // returns true if any device is reporting an alarm on the bus + bool hasAlarm(void); + + // runs the alarm handler for all devices returned by alarmSearch() + void processAlarms(void); + + // sets the alarm handler + void setAlarmHandler(const AlarmHandler *); + + // returns true if an AlarmHandler has been set + bool hasAlarmHandler(); + +#endif + + // if no alarm handler is used the two bytes can be used as user data + // example of such usage is an ID. + // note if device is not connected it will fail writing the data. + // note if address cannot be found no error will be reported. + // in short use carefully + void setUserData(const uint8_t*, int16_t); + void setUserDataByIndex(uint8_t, int16_t); + int16_t getUserData(const uint8_t*); + int16_t getUserDataByIndex(uint8_t); + + // convert from Celsius to Fahrenheit + static float toFahrenheit(float); + + // convert from Fahrenheit to Celsius + static float toCelsius(float); + + // convert from raw to Celsius + static float rawToCelsius(int16_t); + + // convert from raw to Fahrenheit + static float rawToFahrenheit(int16_t); + +#if REQUIRESNEW + + // initialize memory area + void* operator new (unsigned int); + + // delete memory reference + void operator delete(void*); + +#endif + +private: + typedef uint8_t ScratchPad[9]; + + // parasite power on or off + bool parasite; + + // used to determine the delay amount needed to allow for the + // temperature conversion to take place + uint8_t bitResolution; + + // used to requestTemperature with or without delay + bool waitForConversion; + + // used to requestTemperature to dynamically check if a conversion is complete + bool checkForConversion; + + // count of devices on the bus + uint8_t devices; + + // count of DS18xxx Family devices on bus + uint8_t ds18Count; + + // Take a pointer to one wire instance + OneWire* _wire; + + // reads scratchpad and returns the raw temperature + int16_t calculateTemperature(const uint8_t*, uint8_t*); + + void blockTillConversionComplete(uint8_t); + +#if REQUIRESALARMS + + // required for alarmSearch + uint8_t alarmSearchAddress[8]; + int8_t alarmSearchJunction; + uint8_t alarmSearchExhausted; + + // the alarm handler function pointer + AlarmHandler *_AlarmHandler; + +#endif + +}; +#endif diff --git a/lib/DallasTemperature/README.md b/lib/DallasTemperature/README.md new file mode 100644 index 0000000..2595b0f --- /dev/null +++ b/lib/DallasTemperature/README.md @@ -0,0 +1,67 @@ +# Arduino Library for Maxim Temperature Integrated Circuits + +## Usage + +This library supports the following devices : + + +* DS18B20 +* DS18S20 - Please note there appears to be an issue with this series. +* DS1822 +* DS1820 +* MAX31820 + + +You will need a pull-up resistor of about 5 KOhm between the 1-Wire data line +and your 5V power. If you are using the DS18B20, ground pins 1 and 3. The +centre pin is the data line '1-wire'. + +We have included a "REQUIRESNEW" and "REQUIRESALARMS" definition. If you +want to slim down the code feel free to use either of these by including + + + + #define REQUIRESNEW + +or + + #define REQUIRESALARMS + + +at the top of DallasTemperature.h + +Finally, please include OneWire from Paul Stoffregen in the library manager before you begin. + +## Credits + +The OneWire code has been derived from +http://www.arduino.cc/playground/Learning/OneWire. +Miles Burton originally developed this library. +Tim Newsome added support for multiple sensors on +the same bus. +Guil Barros [gfbarros@bappos.com] added getTempByAddress (v3.5) + Note: these are implemented as getTempC(address) and getTempF(address) +Rob Tillaart [rob.tillaart@gmail.com] added async modus (v3.7.0) + + +## Website + + +You can find the latest version of the library at +https://www.milesburton.com/Dallas_Temperature_Control_Library + +# License + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/lib/DallasTemperature/examples/Alarm/Alarm.pde b/lib/DallasTemperature/examples/Alarm/Alarm.pde new file mode 100644 index 0000000..2aab5f5 --- /dev/null +++ b/lib/DallasTemperature/examples/Alarm/Alarm.pde @@ -0,0 +1,162 @@ +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +// arrays to hold device addresses +DeviceAddress insideThermometer, outsideThermometer; + +void setup(void) +{ + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature IC Control Library Demo"); + + // Start up the library + sensors.begin(); + + // locate devices on the bus + Serial.print("Found "); + Serial.print(sensors.getDeviceCount(), DEC); + Serial.println(" devices."); + + // search for devices on the bus and assign based on an index. + if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); + if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1"); + + // show the addresses we found on the bus + Serial.print("Device 0 Address: "); + printAddress(insideThermometer); + Serial.println(); + + Serial.print("Device 0 Alarms: "); + printAlarms(insideThermometer); + Serial.println(); + + Serial.print("Device 1 Address: "); + printAddress(outsideThermometer); + Serial.println(); + + Serial.print("Device 1 Alarms: "); + printAlarms(outsideThermometer); + Serial.println(); + + Serial.println("Setting alarm temps..."); + + // alarm when temp is higher than 30C + sensors.setHighAlarmTemp(insideThermometer, 30); + + // alarm when temp is lower than -10C + sensors.setLowAlarmTemp(insideThermometer, -10); + + // alarm when temp is higher than 31C + sensors.setHighAlarmTemp(outsideThermometer, 31); + + // alarn when temp is lower than 27C + sensors.setLowAlarmTemp(outsideThermometer, 27); + + Serial.print("New Device 0 Alarms: "); + printAlarms(insideThermometer); + Serial.println(); + + Serial.print("New Device 1 Alarms: "); + printAlarms(outsideThermometer); + Serial.println(); +} + +// function to print a device address +void printAddress(DeviceAddress deviceAddress) +{ + for (uint8_t i = 0; i < 8; i++) + { + if (deviceAddress[i] < 16) Serial.print("0"); + Serial.print(deviceAddress[i], HEX); + } +} + +// function to print the temperature for a device +void printTemperature(DeviceAddress deviceAddress) +{ + float tempC = sensors.getTempC(deviceAddress); + Serial.print("Temp C: "); + Serial.print(tempC); + Serial.print(" Temp F: "); + Serial.print(DallasTemperature::toFahrenheit(tempC)); +} + +void printAlarms(uint8_t deviceAddress[]) +{ + char temp; + temp = sensors.getHighAlarmTemp(deviceAddress); + Serial.print("High Alarm: "); + Serial.print(temp, DEC); + Serial.print("C/"); + Serial.print(DallasTemperature::toFahrenheit(temp)); + Serial.print("F | Low Alarm: "); + temp = sensors.getLowAlarmTemp(deviceAddress); + Serial.print(temp, DEC); + Serial.print("C/"); + Serial.print(DallasTemperature::toFahrenheit(temp)); + Serial.print("F"); +} + +// main function to print information about a device +void printData(DeviceAddress deviceAddress) +{ + Serial.print("Device Address: "); + printAddress(deviceAddress); + Serial.print(" "); + printTemperature(deviceAddress); + Serial.println(); +} + +void checkAlarm(DeviceAddress deviceAddress) +{ + if (sensors.hasAlarm(deviceAddress)) + { + Serial.print("ALARM: "); + printData(deviceAddress); + } +} + +void loop(void) +{ + // call sensors.requestTemperatures() to issue a global temperature + // request to all devices on the bus + Serial.print("Requesting temperatures..."); + sensors.requestTemperatures(); + Serial.println("DONE"); + + // Method 1: + // check each address individually for an alarm condition + checkAlarm(insideThermometer); + checkAlarm(outsideThermometer); +/* + // Alternate method: + // Search the bus and iterate through addresses of devices with alarms + + // space for the alarm device's address + DeviceAddress alarmAddr; + + Serial.println("Searching for alarms..."); + + // resetAlarmSearch() must be called before calling alarmSearch() + sensors.resetAlarmSearch(); + + // alarmSearch() returns 0 when there are no devices with alarms + while (sensors.alarmSearch(alarmAddr)) + { + Serial.print("ALARM: "); + printData(alarmAddr); + } +*/ + +} + diff --git a/lib/DallasTemperature/examples/AlarmHandler/AlarmHandler.pde b/lib/DallasTemperature/examples/AlarmHandler/AlarmHandler.pde new file mode 100644 index 0000000..fc4655a --- /dev/null +++ b/lib/DallasTemperature/examples/AlarmHandler/AlarmHandler.pde @@ -0,0 +1,144 @@ +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +// arrays to hold device addresses +DeviceAddress insideThermometer, outsideThermometer; + +// function that will be called when an alarm condition exists during DallasTemperatures::processAlarms(); +void newAlarmHandler(uint8_t* deviceAddress) +{ + Serial.println("Alarm Handler Start"); + printAlarmInfo(deviceAddress); + printTemp(deviceAddress); + Serial.println(); + Serial.println("Alarm Handler Finish"); +} + +void printCurrentTemp(DeviceAddress deviceAddress) +{ + printAddress(deviceAddress); + printTemp(deviceAddress); + Serial.println(); +} + +void printAddress(DeviceAddress deviceAddress) +{ + Serial.print("Address: "); + for (uint8_t i = 0; i < 8; i++) + { + if (deviceAddress[i] < 16) Serial.print("0"); + Serial.print(deviceAddress[i], HEX); + } + Serial.print(" "); +} + +void printTemp(DeviceAddress deviceAddress) +{ + float tempC = sensors.getTempC(deviceAddress); + if (tempC != DEVICE_DISCONNECTED_C) + { + Serial.print("Current Temp C: "); + Serial.print(tempC); + } + else Serial.print("DEVICE DISCONNECTED"); + Serial.print(" "); +} + +void printAlarmInfo(DeviceAddress deviceAddress) +{ + char temp; + printAddress(deviceAddress); + temp = sensors.getHighAlarmTemp(deviceAddress); + Serial.print("High Alarm: "); + Serial.print(temp, DEC); + Serial.print("C"); + Serial.print(" Low Alarm: "); + temp = sensors.getLowAlarmTemp(deviceAddress); + Serial.print(temp, DEC); + Serial.print("C"); + Serial.print(" "); +} + +void setup(void) +{ + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature IC Control Library Demo"); + + // Start up the library + sensors.begin(); + + // locate devices on the bus + Serial.print("Found "); + Serial.print(sensors.getDeviceCount(), DEC); + Serial.println(" devices."); + + // search for devices on the bus and assign based on an index + if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); + if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1"); + + Serial.print("Device insideThermometer "); + printAlarmInfo(insideThermometer); + Serial.println(); + + Serial.print("Device outsideThermometer "); + printAlarmInfo(outsideThermometer); + Serial.println(); + + // set alarm ranges + Serial.println("Setting alarm temps..."); + sensors.setHighAlarmTemp(insideThermometer, 26); + sensors.setLowAlarmTemp(insideThermometer, 22); + sensors.setHighAlarmTemp(outsideThermometer, 25); + sensors.setLowAlarmTemp(outsideThermometer, 21); + + Serial.print("New insideThermometer "); + printAlarmInfo(insideThermometer); + Serial.println(); + + Serial.print("New outsideThermometer "); + printAlarmInfo(outsideThermometer); + Serial.println(); + + // attach alarm handler + sensors.setAlarmHandler(&newAlarmHandler); + +} + +void loop(void) +{ + // ask the devices to measure the temperature + sensors.requestTemperatures(); + + // if an alarm condition exists as a result of the most recent + // requestTemperatures() request, it exists until the next time + // requestTemperatures() is called AND there isn't an alarm condition + // on the device + if (sensors.hasAlarm()) + { + Serial.println("Oh noes! There is at least one alarm on the bus."); + } + + // call alarm handler function defined by sensors.setAlarmHandler + // for each device reporting an alarm + sensors.processAlarms(); + + if (!sensors.hasAlarm()) + { + // just print out the current temperature + printCurrentTemp(insideThermometer); + printCurrentTemp(outsideThermometer); + } + + delay(1000); +} + diff --git a/lib/DallasTemperature/examples/Multibus_simple/Multibus_simple.ino b/lib/DallasTemperature/examples/Multibus_simple/Multibus_simple.ino new file mode 100644 index 0000000..1055579 --- /dev/null +++ b/lib/DallasTemperature/examples/Multibus_simple/Multibus_simple.ino @@ -0,0 +1,43 @@ +#include +#include + +OneWire ds18x20[] = { 3, 7 }; +const int oneWireCount = sizeof(ds18x20)/sizeof(OneWire); +DallasTemperature sensor[oneWireCount]; + +void setup(void) { + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature Multiple Bus Control Library Simple Demo"); + Serial.print("============Ready with "); + Serial.print(oneWireCount); + Serial.println(" Sensors================"); + + // Start up the library on all defined bus-wires + DeviceAddress deviceAddress; + for (int i = 0; i < oneWireCount; i++) {; + sensor[i].setOneWire(&ds18x20[i]); + sensor[i].begin(); + if (sensor[i].getAddress(deviceAddress, 0)) sensor[i].setResolution(deviceAddress, 12); + } +} + +void loop(void) { + // call sensors.requestTemperatures() to issue a global temperature + // request to all devices on the bus + Serial.print("Requesting temperatures..."); + for (int i = 0; i < oneWireCount; i++) { + sensor[i].requestTemperatures(); + } + Serial.println("DONE"); + + delay(1000); + for (int i = 0; i < oneWireCount; i++) { + float temperature = sensor[i].getTempCByIndex(0); + Serial.print("Temperature for the sensor "); + Serial.print(i); + Serial.print(" is "); + Serial.println(temperature); + } + Serial.println(); +} \ No newline at end of file diff --git a/lib/DallasTemperature/examples/Multiple/Multiple.pde b/lib/DallasTemperature/examples/Multiple/Multiple.pde new file mode 100644 index 0000000..7ccc7b1 --- /dev/null +++ b/lib/DallasTemperature/examples/Multiple/Multiple.pde @@ -0,0 +1,143 @@ +// Include the libraries we need +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 +#define TEMPERATURE_PRECISION 9 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +// arrays to hold device addresses +DeviceAddress insideThermometer, outsideThermometer; + +// Assign address manually. The addresses below will beed to be changed +// to valid device addresses on your bus. Device address can be retrieved +// by using either oneWire.search(deviceAddress) or individually via +// sensors.getAddress(deviceAddress, index) +// DeviceAddress insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 }; +// DeviceAddress outsideThermometer = { 0x28, 0x3F, 0x1C, 0x31, 0x2, 0x0, 0x0, 0x2 }; + +void setup(void) +{ + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature IC Control Library Demo"); + + // Start up the library + sensors.begin(); + + // locate devices on the bus + Serial.print("Locating devices..."); + Serial.print("Found "); + Serial.print(sensors.getDeviceCount(), DEC); + Serial.println(" devices."); + + // report parasite power requirements + Serial.print("Parasite power is: "); + if (sensors.isParasitePowerMode()) Serial.println("ON"); + else Serial.println("OFF"); + + // Search for devices on the bus and assign based on an index. Ideally, + // you would do this to initially discover addresses on the bus and then + // use those addresses and manually assign them (see above) once you know + // the devices on your bus (and assuming they don't change). + // + // method 1: by index + if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); + if (!sensors.getAddress(outsideThermometer, 1)) Serial.println("Unable to find address for Device 1"); + + // method 2: search() + // search() looks for the next device. Returns 1 if a new address has been + // returned. A zero might mean that the bus is shorted, there are no devices, + // or you have already retrieved all of them. It might be a good idea to + // check the CRC to make sure you didn't get garbage. The order is + // deterministic. You will always get the same devices in the same order + // + // Must be called before search() + //oneWire.reset_search(); + // assigns the first address found to insideThermometer + //if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer"); + // assigns the seconds address found to outsideThermometer + //if (!oneWire.search(outsideThermometer)) Serial.println("Unable to find address for outsideThermometer"); + + // show the addresses we found on the bus + Serial.print("Device 0 Address: "); + printAddress(insideThermometer); + Serial.println(); + + Serial.print("Device 1 Address: "); + printAddress(outsideThermometer); + Serial.println(); + + // set the resolution to 9 bit per device + sensors.setResolution(insideThermometer, TEMPERATURE_PRECISION); + sensors.setResolution(outsideThermometer, TEMPERATURE_PRECISION); + + Serial.print("Device 0 Resolution: "); + Serial.print(sensors.getResolution(insideThermometer), DEC); + Serial.println(); + + Serial.print("Device 1 Resolution: "); + Serial.print(sensors.getResolution(outsideThermometer), DEC); + Serial.println(); +} + +// function to print a device address +void printAddress(DeviceAddress deviceAddress) +{ + for (uint8_t i = 0; i < 8; i++) + { + // zero pad the address if necessary + if (deviceAddress[i] < 16) Serial.print("0"); + Serial.print(deviceAddress[i], HEX); + } +} + +// function to print the temperature for a device +void printTemperature(DeviceAddress deviceAddress) +{ + float tempC = sensors.getTempC(deviceAddress); + Serial.print("Temp C: "); + Serial.print(tempC); + Serial.print(" Temp F: "); + Serial.print(DallasTemperature::toFahrenheit(tempC)); +} + +// function to print a device's resolution +void printResolution(DeviceAddress deviceAddress) +{ + Serial.print("Resolution: "); + Serial.print(sensors.getResolution(deviceAddress)); + Serial.println(); +} + +// main function to print information about a device +void printData(DeviceAddress deviceAddress) +{ + Serial.print("Device Address: "); + printAddress(deviceAddress); + Serial.print(" "); + printTemperature(deviceAddress); + Serial.println(); +} + +/* + Main function, calls the temperatures in a loop. +*/ +void loop(void) +{ + // call sensors.requestTemperatures() to issue a global temperature + // request to all devices on the bus + Serial.print("Requesting temperatures..."); + sensors.requestTemperatures(); + Serial.println("DONE"); + + // print the device information + printData(insideThermometer); + printData(outsideThermometer); +} diff --git a/lib/DallasTemperature/examples/Simple/Simple.pde b/lib/DallasTemperature/examples/Simple/Simple.pde new file mode 100644 index 0000000..ea738da --- /dev/null +++ b/lib/DallasTemperature/examples/Simple/Simple.pde @@ -0,0 +1,41 @@ +// Include the libraries we need +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +/* + * The setup function. We only start the sensors here + */ +void setup(void) +{ + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature IC Control Library Demo"); + + // Start up the library + sensors.begin(); +} + +/* + * Main function, get and show the temperature + */ +void loop(void) +{ + // call sensors.requestTemperatures() to issue a global temperature + // request to all devices on the bus + Serial.print("Requesting temperatures..."); + sensors.requestTemperatures(); // Send the command to get temperatures + Serial.println("DONE"); + // After we got the temperatures, we can print them here. + // We use the function ByIndex, and as an example get the temperature from the first sensor only. + Serial.print("Temperature for the device 1 (index 0) is: "); + Serial.println(sensors.getTempCByIndex(0)); +} diff --git a/lib/DallasTemperature/examples/Single/Single.pde b/lib/DallasTemperature/examples/Single/Single.pde new file mode 100644 index 0000000..6f8b125 --- /dev/null +++ b/lib/DallasTemperature/examples/Single/Single.pde @@ -0,0 +1,116 @@ +// Include the libraries we need +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +// arrays to hold device address +DeviceAddress insideThermometer; + +/* + * Setup function. Here we do the basics + */ +void setup(void) +{ + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature IC Control Library Demo"); + + // locate devices on the bus + Serial.print("Locating devices..."); + sensors.begin(); + Serial.print("Found "); + Serial.print(sensors.getDeviceCount(), DEC); + Serial.println(" devices."); + + // report parasite power requirements + Serial.print("Parasite power is: "); + if (sensors.isParasitePowerMode()) Serial.println("ON"); + else Serial.println("OFF"); + + // Assign address manually. The addresses below will beed to be changed + // to valid device addresses on your bus. Device address can be retrieved + // by using either oneWire.search(deviceAddress) or individually via + // sensors.getAddress(deviceAddress, index) + // Note that you will need to use your specific address here + //insideThermometer = { 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 }; + + // Method 1: + // Search for devices on the bus and assign based on an index. Ideally, + // you would do this to initially discover addresses on the bus and then + // use those addresses and manually assign them (see above) once you know + // the devices on your bus (and assuming they don't change). + if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0"); + + // method 2: search() + // search() looks for the next device. Returns 1 if a new address has been + // returned. A zero might mean that the bus is shorted, there are no devices, + // or you have already retrieved all of them. It might be a good idea to + // check the CRC to make sure you didn't get garbage. The order is + // deterministic. You will always get the same devices in the same order + // + // Must be called before search() + //oneWire.reset_search(); + // assigns the first address found to insideThermometer + //if (!oneWire.search(insideThermometer)) Serial.println("Unable to find address for insideThermometer"); + + // show the addresses we found on the bus + Serial.print("Device 0 Address: "); + printAddress(insideThermometer); + Serial.println(); + + // set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions) + sensors.setResolution(insideThermometer, 9); + + Serial.print("Device 0 Resolution: "); + Serial.print(sensors.getResolution(insideThermometer), DEC); + Serial.println(); +} + +// function to print the temperature for a device +void printTemperature(DeviceAddress deviceAddress) +{ + // method 1 - slower + //Serial.print("Temp C: "); + //Serial.print(sensors.getTempC(deviceAddress)); + //Serial.print(" Temp F: "); + //Serial.print(sensors.getTempF(deviceAddress)); // Makes a second call to getTempC and then converts to Fahrenheit + + // method 2 - faster + float tempC = sensors.getTempC(deviceAddress); + Serial.print("Temp C: "); + Serial.print(tempC); + Serial.print(" Temp F: "); + Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit +} +/* + * Main function. It will request the tempC from the sensors and display on Serial. + */ +void loop(void) +{ + // call sensors.requestTemperatures() to issue a global temperature + // request to all devices on the bus + Serial.print("Requesting temperatures..."); + sensors.requestTemperatures(); // Send the command to get temperatures + Serial.println("DONE"); + + // It responds almost immediately. Let's print out the data + printTemperature(insideThermometer); // Use a simple function to print out the data +} + +// function to print a device address +void printAddress(DeviceAddress deviceAddress) +{ + for (uint8_t i = 0; i < 8; i++) + { + if (deviceAddress[i] < 16) Serial.print("0"); + Serial.print(deviceAddress[i], HEX); + } +} diff --git a/lib/DallasTemperature/examples/Tester/Tester.pde b/lib/DallasTemperature/examples/Tester/Tester.pde new file mode 100644 index 0000000..309743d --- /dev/null +++ b/lib/DallasTemperature/examples/Tester/Tester.pde @@ -0,0 +1,124 @@ +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 +#define TEMPERATURE_PRECISION 9 // Lower resolution + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +int numberOfDevices; // Number of temperature devices found + +DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address + +void setup(void) +{ + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature IC Control Library Demo"); + + // Start up the library + sensors.begin(); + + // Grab a count of devices on the wire + numberOfDevices = sensors.getDeviceCount(); + + // locate devices on the bus + Serial.print("Locating devices..."); + + Serial.print("Found "); + Serial.print(numberOfDevices, DEC); + Serial.println(" devices."); + + // report parasite power requirements + Serial.print("Parasite power is: "); + if (sensors.isParasitePowerMode()) Serial.println("ON"); + else Serial.println("OFF"); + + // Loop through each device, print out address + for(int i=0;i +#include + +#define ONE_WIRE_BUS_1 2 +#define ONE_WIRE_BUS_2 4 + +OneWire oneWire_in(ONE_WIRE_BUS_1); +OneWire oneWire_out(ONE_WIRE_BUS_2); + +DallasTemperature sensor_inhouse(&oneWire_in); +DallasTemperature sensor_outhouse(&oneWire_out); + +void setup(void) +{ + Serial.begin(9600); + Serial.println("Dallas Temperature Control Library Demo - TwoPin_DS18B20"); + + sensor_inhouse.begin(); + sensor_outhouse.begin(); +} + +void loop(void) +{ + Serial.print("Requesting temperatures..."); + sensor_inhouse.requestTemperatures(); + sensor_outhouse.requestTemperatures(); + Serial.println(" done"); + + Serial.print("Inhouse: "); + Serial.println(sensor_inhouse.getTempCByIndex(0)); + + Serial.print("Outhouse: "); + Serial.println(sensor_outhouse.getTempCByIndex(0)); +} \ No newline at end of file diff --git a/lib/DallasTemperature/examples/UserDataDemo/UserDataDemo.ino b/lib/DallasTemperature/examples/UserDataDemo/UserDataDemo.ino new file mode 100644 index 0000000..4cd6d25 --- /dev/null +++ b/lib/DallasTemperature/examples/UserDataDemo/UserDataDemo.ino @@ -0,0 +1,115 @@ +// +// FILE: UserDataDemo.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.0 +// PURPOSE: use of alarm field as user identification demo +// DATE: 2019-12-23 +// URL: +// +// Released to the public domain +// + +#include +#include + +#define ONE_WIRE_BUS 2 + +OneWire oneWire(ONE_WIRE_BUS); +DallasTemperature sensors(&oneWire); + +uint8_t deviceCount = 0; + +// Add 4 prepared sensors to the bus +// use the UserDataWriteBatch demo to prepare 4 different labeled sensors +struct +{ + int id; + DeviceAddress addr; +} T[4]; + +float getTempByID(int id) +{ + for (uint8_t index = 0; index < deviceCount; index++) + { + if (T[index].id == id) + { + return sensors.getTempC(T[index].addr); + } + } + return -999; +} + +void printAddress(DeviceAddress deviceAddress) +{ + for (uint8_t i = 0; i < 8; i++) + { + // zero pad the address if necessary + if (deviceAddress[i] < 16) Serial.print("0"); + Serial.print(deviceAddress[i], HEX); + } +} + +void setup(void) +{ + Serial.begin(115200); + Serial.println(__FILE__); + Serial.println("Dallas Temperature Demo"); + + sensors.begin(); + + // count devices + deviceCount = sensors.getDeviceCount(); + Serial.print("#devices: "); + Serial.println(deviceCount); + + // Read ID's per sensor + // and put them in T array + for (uint8_t index = 0; index < deviceCount; index++) + { + // go through sensors + sensors.getAddress(T[index].addr, index); + T[index].id = sensors.getUserData(T[index].addr); + } + + // Check all 4 sensors are set + for (uint8_t index = 0; index < deviceCount; index++) + { + Serial.println(); + Serial.println(T[index].id); + printAddress(T[index].addr); + Serial.println(); + } + Serial.println(); + +} + + +void loop(void) +{ + Serial.println(); + Serial.print(millis()); + Serial.println("\treq temp"); + sensors.requestTemperatures(); + + Serial.print(millis()); + Serial.println("\tGet temp by address"); + for (int i = 0; i < 4; i++) + { + Serial.print(millis()); + Serial.print("\t temp:\t"); + Serial.println(sensors.getTempC(T[i].addr)); + } + + Serial.print(millis()); + Serial.println("\tGet temp by ID"); // assume ID = 0, 1, 2, 3 + for (int id = 0; id < 4; id++) + { + Serial.print(millis()); + Serial.print("\t temp:\t"); + Serial.println(getTempByID(id)); + } + + delay(1000); +} + +// END OF FILE \ No newline at end of file diff --git a/lib/DallasTemperature/examples/UserDataWriteBatch/UserDataWriteBatch.ino b/lib/DallasTemperature/examples/UserDataWriteBatch/UserDataWriteBatch.ino new file mode 100644 index 0000000..b59f33b --- /dev/null +++ b/lib/DallasTemperature/examples/UserDataWriteBatch/UserDataWriteBatch.ino @@ -0,0 +1,107 @@ +// +// FILE: UserDataWriteBatch.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.0 +// PURPOSE: use of alarm field as user identification demo +// DATE: 2019-12-23 +// URL: +// +// Released to the public domain +// + +#include +#include + +#define ONE_WIRE_BUS 2 + +OneWire oneWire(ONE_WIRE_BUS); +DallasTemperature sensors(&oneWire); + +uint8_t deviceCount = 0; + +void printAddress(DeviceAddress deviceAddress) +{ + for (uint8_t i = 0; i < 8; i++) + { + // zero pad the address if necessary + if (deviceAddress[i] < 16) Serial.print("0"); + Serial.print(deviceAddress[i], HEX); + } +} + + + +void setup(void) +{ + Serial.begin(115200); + Serial.println(__FILE__); + Serial.println("Write user ID to DS18B20\n"); + + sensors.begin(); + + // count devices + deviceCount = sensors.getDeviceCount(); + Serial.print("#devices: "); + Serial.println(deviceCount); + + Serial.println(); + Serial.println("current ID's"); + for (uint8_t index = 0; index < deviceCount; index++) + { + DeviceAddress t; + sensors.getAddress(t, index); + printAddress(t); + Serial.print("\t\tID: "); + int id = sensors.getUserData(t); + Serial.println(id); + } + + Serial.println(); + Serial.print("Enter ID for batch: "); + int c = 0; + int id = 0; + while (c != '\n' && c != '\r') + { + c = Serial.read(); + switch(c) + { + case '0'...'9': + id *= 10; + id += (c - '0'); + break; + default: + break; + } + } + Serial.println(); + Serial.println(id); + Serial.println(); + + Serial.println("Start labeling ..."); + for (uint8_t index = 0; index < deviceCount; index++) + { + Serial.print("."); + DeviceAddress t; + sensors.getAddress(t, index); + sensors.setUserData(t, id); + } + Serial.println(); + + Serial.println(); + Serial.println("Show results ..."); + for (uint8_t index = 0; index < deviceCount; index++) + { + DeviceAddress t; + sensors.getAddress(t, index); + printAddress(t); + Serial.print("\t\tID: "); + int id = sensors.getUserData(t); + Serial.println(id); + } + Serial.println("Done ..."); + +} + +void loop(void) {} + +// END OF FILE \ No newline at end of file diff --git a/lib/DallasTemperature/examples/WaitForConversion/WaitForConversion.pde b/lib/DallasTemperature/examples/WaitForConversion/WaitForConversion.pde new file mode 100644 index 0000000..52c30be --- /dev/null +++ b/lib/DallasTemperature/examples/WaitForConversion/WaitForConversion.pde @@ -0,0 +1,66 @@ +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +void setup(void) +{ + // start serial port + Serial.begin(115200); + Serial.println("Dallas Temperature Control Library - Async Demo"); + Serial.println("\nDemo shows the difference in length of the call\n\n"); + + // Start up the library + sensors.begin(); +} + +void loop(void) +{ + // Request temperature conversion (traditional) + Serial.println("Before blocking requestForConversion"); + unsigned long start = millis(); + + sensors.requestTemperatures(); + + unsigned long stop = millis(); + Serial.println("After blocking requestForConversion"); + Serial.print("Time used: "); + Serial.println(stop - start); + + // get temperature + Serial.print("Temperature: "); + Serial.println(sensors.getTempCByIndex(0)); + Serial.println("\n"); + + // Request temperature conversion - non-blocking / async + Serial.println("Before NON-blocking/async requestForConversion"); + start = millis(); + sensors.setWaitForConversion(false); // makes it async + sensors.requestTemperatures(); + sensors.setWaitForConversion(true); + stop = millis(); + Serial.println("After NON-blocking/async requestForConversion"); + Serial.print("Time used: "); + Serial.println(stop - start); + + + // 9 bit resolution by default + // Note the programmer is responsible for the right delay + // we could do something usefull here instead of the delay + int resolution = 9; + delay(750/ (1 << (12-resolution))); + + // get temperature + Serial.print("Temperature: "); + Serial.println(sensors.getTempCByIndex(0)); + Serial.println("\n\n\n\n"); + + delay(5000); +} diff --git a/lib/DallasTemperature/examples/WaitForConversion2/WaitForConversion2.pde b/lib/DallasTemperature/examples/WaitForConversion2/WaitForConversion2.pde new file mode 100644 index 0000000..f8e7700 --- /dev/null +++ b/lib/DallasTemperature/examples/WaitForConversion2/WaitForConversion2.pde @@ -0,0 +1,80 @@ +// +// Sample of using Async reading of Dallas Temperature Sensors +// +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +DeviceAddress tempDeviceAddress; + +int resolution = 12; +unsigned long lastTempRequest = 0; +int delayInMillis = 0; +float temperature = 0.0; +int idle = 0; +// +// SETUP +// +void setup(void) +{ + Serial.begin(115200); + Serial.println("Dallas Temperature Control Library - Async Demo"); + Serial.print("Library Version: "); + Serial.println(DALLASTEMPLIBVERSION); + Serial.println("\n"); + + sensors.begin(); + sensors.getAddress(tempDeviceAddress, 0); + sensors.setResolution(tempDeviceAddress, resolution); + + sensors.setWaitForConversion(false); + sensors.requestTemperatures(); + delayInMillis = 750 / (1 << (12 - resolution)); + lastTempRequest = millis(); + + pinMode(13, OUTPUT); +} + +void loop(void) +{ + + if (millis() - lastTempRequest >= delayInMillis) // waited long enough?? + { + digitalWrite(13, LOW); + Serial.print(" Temperature: "); + temperature = sensors.getTempCByIndex(0); + Serial.println(temperature, resolution - 8); + Serial.print(" Resolution: "); + Serial.println(resolution); + Serial.print("Idle counter: "); + Serial.println(idle); + Serial.println(); + + idle = 0; + + // immediately after fetching the temperature we request a new sample + // in the async modus + // for the demo we let the resolution change to show differences + resolution++; + if (resolution > 12) resolution = 9; + + sensors.setResolution(tempDeviceAddress, resolution); + sensors.requestTemperatures(); + delayInMillis = 750 / (1 << (12 - resolution)); + lastTempRequest = millis(); + } + + digitalWrite(13, HIGH); + // we can do usefull things here + // for the demo we just count the idle time in millis + delay(1); + idle++; +} diff --git a/lib/DallasTemperature/examples/oneWireSearch/oneWireSearch.ino b/lib/DallasTemperature/examples/oneWireSearch/oneWireSearch.ino new file mode 100644 index 0000000..44da619 --- /dev/null +++ b/lib/DallasTemperature/examples/oneWireSearch/oneWireSearch.ino @@ -0,0 +1,67 @@ +// +// FILE: oneWireSearch.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.02 +// PURPOSE: scan for 1-Wire devices + code snippet generator +// DATE: 2015-june-30 +// URL: http://forum.arduino.cc/index.php?topic=333923 +// +// inspired by http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html +// +// Released to the public domain +// +// 0.1.00 initial version +// 0.1.01 first published version +// 0.1.02 small output changes + +#include + +void setup() +{ + Serial.begin(115200); + Serial.println("//\n// Start oneWireSearch.ino \n//"); + + for (uint8_t pin = 2; pin < 13; pin++) + { + findDevices(pin); + } + Serial.println("\n//\n// End oneWireSearch.ino \n//"); +} + +void loop() +{ +} + +uint8_t findDevices(int pin) +{ + OneWire ow(pin); + + uint8_t address[8]; + uint8_t count = 0; + + + if (ow.search(address)) + { + Serial.print("\nuint8_t pin"); + Serial.print(pin, DEC); + Serial.println("[][8] = {"); + do { + count++; + Serial.println(" {"); + for (uint8_t i = 0; i < 8; i++) + { + Serial.print("0x"); + if (address[i] < 0x10) Serial.print("0"); + Serial.print(address[i], HEX); + if (i < 7) Serial.print(", "); + } + Serial.println(" },"); + } while (ow.search(address)); + + Serial.println("};"); + Serial.print("// nr devices found: "); + Serial.println(count); + } + + return count; +} diff --git a/lib/DallasTemperature/examples/setUserData/SetUserData.ino b/lib/DallasTemperature/examples/setUserData/SetUserData.ino new file mode 100644 index 0000000..44bd797 --- /dev/null +++ b/lib/DallasTemperature/examples/setUserData/SetUserData.ino @@ -0,0 +1,47 @@ +// +// This sketch does not use the ALARM registers and uses those 2 bytes as a counter +// these 2 bytes can be used for other purposes as well e.g. last temperature or +// a specific ID. +// + +#include +#include + +// Data wire is plugged into port 2 on the Arduino +#define ONE_WIRE_BUS 2 + +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature sensors(&oneWire); + +int count = 0; + +void setup(void) +{ + // start serial port + Serial.begin(9600); + Serial.println("Dallas Temperature IC Control Library Demo"); + + // Start up the library + sensors.begin(); + +} + +void loop(void) +{ + // call sensors.requestTemperatures() to issue a global temperature + // request to all devices on the bus + Serial.print("Requesting temperatures..."); + sensors.requestTemperatures(); // Send the command to get temperatures + Serial.println("DONE"); + + Serial.print("Temperature for the device 1 (index 0) is: "); + Serial.println(sensors.getTempCByIndex(0)); + + count++; + sensors.setUserDataByIndex(0, count); + int x = sensors.getUserDataByIndex(0); + Serial.println(count); +} diff --git a/lib/DallasTemperature/keywords.txt b/lib/DallasTemperature/keywords.txt new file mode 100644 index 0000000..37df467 --- /dev/null +++ b/lib/DallasTemperature/keywords.txt @@ -0,0 +1,54 @@ +####################################### +# Syntax Coloring Map For DallasTemperature +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### +DallasTemperature KEYWORD1 +OneWire KEYWORD1 +AlarmHandler KEYWORD1 +DeviceAddress KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +setResolution KEYWORD2 +getResolution KEYWORD2 +getTempC KEYWORD2 +toFahrenheit KEYWORD2 +getTempF KEYWORD2 +getTempCByIndex KEYWORD2 +getTempFByIndex KEYWORD2 +setWaitForConversion KEYWORD2 +getWaitForConversion KEYWORD2 +requestTemperatures KEYWORD2 +requestTemperaturesByAddress KEYWORD2 +requestTemperaturesByIndex KEYWORD2 +isParasitePowerMode KEYWORD2 +begin KEYWORD2 +getDeviceCount KEYWORD2 +getAddress KEYWORD2 +validAddress KEYWORD2 +isConnected KEYWORD2 +readScratchPad KEYWORD2 +writeScratchPad KEYWORD2 +readPowerSupply KEYWORD2 +setHighAlarmTemp KEYWORD2 +setLowAlarmTemp KEYWORD2 +getHighAlarmTemp KEYWORD2 +getLowAlarmTemp KEYWORD2 +resetAlarmSearch KEYWORD2 +alarmSearch KEYWORD2 +hasAlarm KEYWORD2 +toCelsius KEYWORD2 +processAlarmss KEYWORD2 +setAlarmHandlers KEYWORD2 +defaultAlarmHandler KEYWORD2 +calculateTemperature KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/lib/DallasTemperature/library.json b/lib/DallasTemperature/library.json new file mode 100644 index 0000000..a43aefe --- /dev/null +++ b/lib/DallasTemperature/library.json @@ -0,0 +1,40 @@ +{ + "name": "DallasTemperature", + "keywords": "onewire, 1-wire, bus, sensor, temperature", + "description": "Arduino Library for Dallas Temperature ICs (DS18B20, DS18S20, DS1822, DS1820)", + "repository": + { + "type": "git", + "url": "https://github.com/milesburton/Arduino-Temperature-Control-Library.git" + }, + "authors": + [ + { + "name": "Miles Burton", + "email": "miles@mnetcs.com", + "url": "http://www.milesburton.com", + "maintainer": true + }, + { + "name": "Tim Newsome", + "email": "nuisance@casualhacker.net" + }, + { + "name": "Guil Barros", + "email": "gfbarros@bappos.com" + }, + { + "name": "Rob Tillaart", + "email": "rob.tillaart@gmail.com" + } + ], + "dependencies": + { + "name": "OneWire", + "authors": "Paul Stoffregen", + "frameworks": "arduino" + }, + "version": "3.8.0", + "frameworks": "arduino", + "platforms": "*" +} diff --git a/lib/DallasTemperature/library.properties b/lib/DallasTemperature/library.properties new file mode 100644 index 0000000..969e560 --- /dev/null +++ b/lib/DallasTemperature/library.properties @@ -0,0 +1,9 @@ +name=DallasTemperature +version=3.8.0 +author=Miles Burton , Tim Newsome , Guil Barros , Rob Tillaart +maintainer=Miles Burton +sentence=Arduino Library for Dallas Temperature ICs +paragraph=Supports DS18B20, DS18S20, DS1822, DS1820 +category=Sensors +url=https://github.com/milesburton/Arduino-Temperature-Control-Library +architectures=* diff --git a/lib/EmonLib/EmonLib.cpp b/lib/EmonLib/EmonLib.cpp new file mode 100644 index 0000000..eb04dc8 --- /dev/null +++ b/lib/EmonLib/EmonLib.cpp @@ -0,0 +1,263 @@ +/* + Emon.cpp - Library for openenergymonitor + Created by Trystan Lea, April 27 2010 + GNU GPL + modified to use up to 12 bits ADC resolution (ex. Arduino Due) + by boredman@boredomprojects.net 26.12.2013 + Low Pass filter for offset removal replaces HP filter 1/1/2015 - RW +*/ + +// Proboscide99 10/08/2016 - Added ADMUX settings for ATmega1284 e 1284P (644 / 644P also, but not tested) in readVcc function + +//#include "WProgram.h" un-comment for use on older versions of Arduino IDE +#include "EmonLib.h" + +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#endif + + +//-------------------------------------------------------------------------------------- +// Sets the pins to be used for voltage and current sensors +//-------------------------------------------------------------------------------------- +void EnergyMonitor::voltage(unsigned int _inPinV, double _VCAL, double _PHASECAL) +{ + inPinV = _inPinV; + VCAL = _VCAL; + PHASECAL = _PHASECAL; + offsetV = ADC_COUNTS>>1; +} + +void EnergyMonitor::current(unsigned int _inPinI, double _ICAL) +{ + inPinI = _inPinI; + ICAL = _ICAL; + offsetI = ADC_COUNTS>>1; +} + +//-------------------------------------------------------------------------------------- +// Sets the pins to be used for voltage and current sensors based on emontx pin map +//-------------------------------------------------------------------------------------- +void EnergyMonitor::voltageTX(double _VCAL, double _PHASECAL) +{ + inPinV = 2; + VCAL = _VCAL; + PHASECAL = _PHASECAL; + offsetV = ADC_COUNTS>>1; +} + +void EnergyMonitor::currentTX(unsigned int _channel, double _ICAL) +{ + if (_channel == 1) inPinI = 3; + if (_channel == 2) inPinI = 0; + if (_channel == 3) inPinI = 1; + ICAL = _ICAL; + offsetI = ADC_COUNTS>>1; +} + +//-------------------------------------------------------------------------------------- +// emon_calc procedure +// Calculates realPower,apparentPower,powerFactor,Vrms,Irms,kWh increment +// From a sample window of the mains AC voltage and current. +// The Sample window length is defined by the number of half wavelengths or crossings we choose to measure. +//-------------------------------------------------------------------------------------- +void EnergyMonitor::calcVI(unsigned int crossings, unsigned int timeout) +{ + #if defined emonTxV3 + int SupplyVoltage=3300; + #else + int SupplyVoltage = readVcc(); + #endif + + unsigned int crossCount = 0; //Used to measure number of times threshold is crossed. + unsigned int numberOfSamples = 0; //This is now incremented + + //------------------------------------------------------------------------------------------------------------------------- + // 1) Waits for the waveform to be close to 'zero' (mid-scale adc) part in sin curve. + //------------------------------------------------------------------------------------------------------------------------- + unsigned long start = millis(); //millis()-start makes sure it doesnt get stuck in the loop if there is an error. + + while(1) //the while loop... + { + startV = analogRead(inPinV); //using the voltage waveform + if ((startV < (ADC_COUNTS*0.55)) && (startV > (ADC_COUNTS*0.45))) break; //check its within range + if ((millis()-start)>timeout) break; + } + + //------------------------------------------------------------------------------------------------------------------------- + // 2) Main measurement loop + //------------------------------------------------------------------------------------------------------------------------- + start = millis(); + + while ((crossCount < crossings) && ((millis()-start) startV) checkVCross = true; + else checkVCross = false; + if (numberOfSamples==1) lastVCross = checkVCross; + + if (lastVCross != checkVCross) crossCount++; + } + + //------------------------------------------------------------------------------------------------------------------------- + // 3) Post loop calculations + //------------------------------------------------------------------------------------------------------------------------- + //Calculation of the root of the mean of the voltage and current squared (rms) + //Calibration coefficients applied. + + double V_RATIO = VCAL *((SupplyVoltage/1000.0) / (ADC_COUNTS)); + Vrms = V_RATIO * sqrt(sumV / numberOfSamples); + + double I_RATIO = ICAL *((SupplyVoltage/1000.0) / (ADC_COUNTS)); + Irms = I_RATIO * sqrt(sumI / numberOfSamples); + + //Calculation power values + realPower = V_RATIO * I_RATIO * sumP / numberOfSamples; + apparentPower = Vrms * Irms; + powerFactor=realPower / apparentPower; + + //Reset accumulators + sumV = 0; + sumI = 0; + sumP = 0; +//-------------------------------------------------------------------------------------- +} + +//-------------------------------------------------------------------------------------- +double EnergyMonitor::calcIrms(unsigned int Number_of_Samples) +{ + + #if defined emonTxV3 + int SupplyVoltage=3300; + #else + int SupplyVoltage = readVcc(); + #endif + + + for (unsigned int n = 0; n < Number_of_Samples; n++) + { + sampleI = analogRead(inPinI); + + // Digital low pass filter extracts the 2.5 V or 1.65 V dc offset, + // then subtract this - signal is now centered on 0 counts. + offsetI = (offsetI + (sampleI-offsetI)/1024); + filteredI = sampleI - offsetI; + + // Root-mean-square method current + // 1) square current values + sqI = filteredI * filteredI; + // 2) sum + sumI += sqI; + } + + double I_RATIO = ICAL *((SupplyVoltage/1000.0) / (ADC_COUNTS)); + Irms = I_RATIO * sqrt(sumI / Number_of_Samples); + + //Reset accumulators + sumI = 0; + //-------------------------------------------------------------------------------------- + + return Irms; +} + +void EnergyMonitor::serialprint() +{ + Serial.print(realPower); + Serial.print(' '); + Serial.print(apparentPower); + Serial.print(' '); + Serial.print(Vrms); + Serial.print(' '); + Serial.print(Irms); + Serial.print(' '); + Serial.print(powerFactor); + Serial.println(' '); + delay(100); +} + +//thanks to http://hacking.majenko.co.uk/making-accurate-adc-readings-on-arduino +//and Jérôme who alerted us to http://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/ + +long EnergyMonitor::readVcc() { + long result; + + //not used on emonTx V3 - as Vcc is always 3.3V - eliminates bandgap error and need for calibration http://harizanov.com/2013/09/thoughts-on-avr-adc-accuracy/ + + #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined (__AVR_ATmega328P__) + ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); + #elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) + ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); + #elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB1286__) + ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); + ADCSRB &= ~_BV(MUX5); // Without this the function always returns -1 on the ATmega2560 http://openenergymonitor.org/emon/node/2253#comment-11432 + #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) + ADMUX = _BV(MUX5) | _BV(MUX0); + #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) + ADMUX = _BV(MUX3) | _BV(MUX2); + + #endif + + + #if defined(__AVR__) + delay(2); // Wait for Vref to settle + ADCSRA |= _BV(ADSC); // Convert + while (bit_is_set(ADCSRA,ADSC)); + result = ADCL; + result |= ADCH<<8; + result = READVCC_CALIBRATION_CONST / result; //1100mV*1024 ADC steps http://openenergymonitor.org/emon/node/1186 + return result; + #elif defined(__arm__) + return (3300); //Arduino Due + #else + return (3300); //Guess that other un-supported architectures will be running a 3.3V! + #endif +} + diff --git a/lib/EmonLib/EmonLib.h b/lib/EmonLib/EmonLib.h new file mode 100644 index 0000000..99a2b43 --- /dev/null +++ b/lib/EmonLib/EmonLib.h @@ -0,0 +1,100 @@ +/* + Emon.h - Library for openenergymonitor + Created by Trystan Lea, April 27 2010 + GNU GPL + modified to use up to 12 bits ADC resolution (ex. Arduino Due) + by boredman@boredomprojects.net 26.12.2013 + Low Pass filter for offset removal replaces HP filter 1/1/2015 - RW +*/ + +#ifndef EmonLib_h +#define EmonLib_h + +#if defined(ARDUINO) && ARDUINO >= 100 + +#include "Arduino.h" + +#else + +#include "WProgram.h" + +#endif + +// define theoretical vref calibration constant for use in readvcc() +// 1100mV*1024 ADC steps http://openenergymonitor.org/emon/node/1186 +// override in your code with value for your specific AVR chip +// determined by procedure described under "Calibrating the internal reference voltage" at +// http://openenergymonitor.org/emon/buildingblocks/calibration +#ifndef READVCC_CALIBRATION_CONST +#define READVCC_CALIBRATION_CONST 1126400L +#endif + +// to enable 12-bit ADC resolution on Arduino Due, +// include the following line in main sketch inside setup() function: +// analogReadResolution(ADC_BITS); +// otherwise will default to 10 bits, as in regular Arduino-based boards. +#if defined(__arm__) +#define ADC_BITS 12 +#else +#define ADC_BITS 10 +#endif + +#define ADC_COUNTS (1< + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS diff --git a/lib/EmonLib/Readme.txt b/lib/EmonLib/Readme.txt new file mode 100644 index 0000000..c2484fb --- /dev/null +++ b/lib/EmonLib/Readme.txt @@ -0,0 +1,25 @@ + _ _ _ + | | (_) | + ___ _ __ ___ ___ _ __ | | _| |__ + / _ \ '_ ` _ \ / _ \| '_ \| | | | '_ \ + | __/ | | | | | (_) | | | | |____| | |_) | + \___|_| |_| |_|\___/|_| |_|______|_|_.__/ + +Arduino Energy Monitoring Library - compatible with Arduino 1.0 +***************************************************************** + +Designed for use with emonTx: http://openenergymonitor.org/emon/Modules + +Download to Arduino IDE 'libraries' folder. Restart of IDE required. + +Git Clone and Git Pull can be easily used to keep the library up-to-date and manage changes. +JeeLabs has done a good post on the topic: http://jeelabs.org/2011/12/29/out-with-the-old-in-with-the-new/ + + + +Update: 5th January 2014: Support Added for Arduino Due (ARM Cortex-M3, 12-bit ADC) by icboredman. + +To enable this feature on Arduino Due, add the following statement to setup() function in main sketch: +analogReadResolution(ADC_BITS); This will set ADC_BITS to 12 (Arduino Due), EmonLib will otherwise default to 10 analogReadResolution(ADC_BITS);. +See blog post on using Arduino Due as energy monitor: http://boredomprojects.net/index.php/projects/home-energy-monitor + diff --git a/lib/EmonLib/examples/current_only/current_only.ino b/lib/EmonLib/examples/current_only/current_only.ino new file mode 100644 index 0000000..387a189 --- /dev/null +++ b/lib/EmonLib/examples/current_only/current_only.ino @@ -0,0 +1,20 @@ +// EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3 + +#include "EmonLib.h" // Include Emon Library +EnergyMonitor emon1; // Create an instance + +void setup() +{ + Serial.begin(9600); + + emon1.current(1, 111.1); // Current: input pin, calibration. +} + +void loop() +{ + double Irms = emon1.calcIrms(1480); // Calculate Irms only + + Serial.print(Irms*230.0); // Apparent power + Serial.print(" "); + Serial.println(Irms); // Irms +} diff --git a/lib/EmonLib/examples/voltage_and_current/voltage_and_current.ino b/lib/EmonLib/examples/voltage_and_current/voltage_and_current.ino new file mode 100644 index 0000000..7e4a024 --- /dev/null +++ b/lib/EmonLib/examples/voltage_and_current/voltage_and_current.ino @@ -0,0 +1,24 @@ +// EmonLibrary examples openenergymonitor.org, Licence GNU GPL V3 + +#include "EmonLib.h" // Include Emon Library +EnergyMonitor emon1; // Create an instance + +void setup() +{ + Serial.begin(9600); + + emon1.voltage(2, 234.26, 1.7); // Voltage: input pin, calibration, phase_shift + emon1.current(1, 111.1); // Current: input pin, calibration. +} + +void loop() +{ + emon1.calcVI(20,2000); // Calculate all. No.of half wavelengths (crossings), time-out + emon1.serialprint(); // Print out all variables (realpower, apparent power, Vrms, Irms, power factor) + + float realPower = emon1.realPower; //extract Real Power into variable + float apparentPower = emon1.apparentPower; //extract Apparent Power into variable + float powerFActor = emon1.powerFactor; //extract Power Factor into Variable + float supplyVoltage = emon1.Vrms; //extract Vrms into Variable + float Irms = emon1.Irms; //extract Irms into Variable +} diff --git a/lib/EmonLib/library.json b/lib/EmonLib/library.json new file mode 100644 index 0000000..e265b63 --- /dev/null +++ b/lib/EmonLib/library.json @@ -0,0 +1,17 @@ +{ + "name": "EmonLib", + "keywords": "electricity, energy, monitoring", + "description": "Energy Monitoring Library", + "version": "1.1.0", + "repository": + { + "type": "git", + "url": "https://github.com/openenergymonitor/EmonLib.git" + }, + "frameworks": "arduino", + "platforms": + [ + "atmelavr", + "atmelsam" + ] +} diff --git a/lib/EmonLib/library.properties b/lib/EmonLib/library.properties new file mode 100644 index 0000000..d1a648f --- /dev/null +++ b/lib/EmonLib/library.properties @@ -0,0 +1,9 @@ +name=EmonLib +version=1.1.0 +author=OpenEnergyMonitor +maintainer=OpenEnergyMonitor +sentence=Energy Monitoring Library +paragraph=Energy Monitoring Library +category=Sensors +url=https://github.com/openenergymonitor/EmonLib.git +architectures=* \ No newline at end of file diff --git a/lib/Max44009/Max44009.h b/lib/Max44009/Max44009.h new file mode 100644 index 0000000..e240efd --- /dev/null +++ b/lib/Max44009/Max44009.h @@ -0,0 +1,98 @@ +#ifndef MAX44009_H +#define MAX44009_H +// +// FILE: Max44009.h +// AUTHOR: Rob dot Tillaart at gmail dot com +// VERSION: 0.1.9 +// PURPOSE: library for MAX44009 lux sensor Arduino +// HISTORY: See Max440099.cpp +// +// Released to the public domain +// + +#include "Wire.h" + +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#endif + +#define MAX44009_LIB_VERSION "0.1.9" + +// I2C ADDRESSES +#define MAX44009_A0_LOW 0x4A +#define MAX44009_A0_HIGH 0x4B + +// REGISTERS +#define MAX44009_INTERRUPT_STATUS 0x00 +#define MAX44009_INTERRUPT_ENABLE 0x01 +#define MAX44009_CONFIGURATION 0x02 +#define MAX44009_LUX_READING_HIGH 0x03 +#define MAX44009_LUX_READING_LOW 0x04 +#define MAX44009_THRESHOLD_HIGH 0x05 +#define MAX44009_THRESHOLD_LOW 0x06 +#define MAX44009_THRESHOLD_TIMER 0x07 + +// CONFIGURATION MASKS +#define MAX44009_CFG_CONTINUOUS 0x80 +#define MAX44009_CFG_MANUAL 0x40 +#define MAX44009_CFG_CDR 0x08 +#define MAX44009_CFG_TIMER 0x07 + + +class Max44009 +{ +public: + // dataPin and clockPin are only used by ESP8266 + // for UNO ignore these (and its warning) + Max44009(const uint8_t address, const uint8_t dataPin = 5, const uint8_t clockPin = 4); + Max44009(const uint8_t address, bool continuousMode); + + float getLux(); + int getError(); + + void setHighThreshold(const float); + float getHighThreshold(void); + void setLowThreshold(const float); + float getLowThreshold(void); + void setThresholdTimer(const uint8_t); + uint8_t getThresholdTimer(); + + void enableInterrupt() { write(MAX44009_INTERRUPT_ENABLE, 1); }; + void disableInterrupt() { write(MAX44009_INTERRUPT_ENABLE, 0); }; + bool interruptEnabled() { return read(MAX44009_INTERRUPT_ENABLE) & 0x01; }; + uint8_t getInterruptStatus() { return read(MAX44009_INTERRUPT_STATUS) & 0x01; }; + + // check datasheet for detailed behavior + void setConfiguration(uint8_t); + uint8_t getConfiguration(); + void setAutomaticMode(); + void setContinuousMode(); + // CDR = Current Divisor Ratio + // CDR = 1 ==> only 1/8th is measured + // TIM = Time Integration Measurement (table) + // 000 800ms + // 001 400ms + // 010 200ms + // 011 100ms + // 100 50ms + // 101 25ms + // 110 12.5ms + // 111 6.25ms + void setManualMode(uint8_t CDR, uint8_t TIM); + +private: + void setThreshold(uint8_t, float); + float getThreshold(uint8_t); + + uint8_t read(uint8_t reg); + void write(uint8_t, uint8_t); + + uint8_t _address; + uint8_t _data; + int _error; +}; +#endif + +// END OF FILE \ No newline at end of file diff --git a/lib/Max44009/examples/max44009_test01/max44009_test01.ino b/lib/Max44009/examples/max44009_test01/max44009_test01.ino new file mode 100644 index 0000000..ecdc808 --- /dev/null +++ b/lib/Max44009/examples/max44009_test01/max44009_test01.ino @@ -0,0 +1,47 @@ +// +// FILE: max44009_test01.ino +// AUTHOR: Rob Tillaart +// VERSION: 0.1.1 +// PURPOSE: demo of max44009 library +// DATE: 2015-08-06 +// URL: ? +// +// Released to the public domain +// + +#include "Wire.h" +#include "Max44009.h" + +Max44009 myLux(0xCB); // default addr + +uint32_t lastDisplay = 0; + +void setup() +{ + Serial.begin(115200); + Serial.print("Start max44009_test01 : "); + Serial.println(MAX44009_LIB_VERSION); +} + +void loop() +{ + if (millis() - lastDisplay >= 1000) + { + lastDisplay += 1000; + float lux = myLux.getLux(); + int err = myLux.getError(); + if (err != 0) + { + Serial.print("Error:\t"); + Serial.println(err); + } + else + { + Serial.print("lux:\t"); + Serial.println(lux); + } + } + +} + + diff --git a/lib/Max44009/keywords.txt b/lib/Max44009/keywords.txt new file mode 100644 index 0000000..c4449fc --- /dev/null +++ b/lib/Max44009/keywords.txt @@ -0,0 +1,36 @@ +####################################### +# Syntax Coloring Map For Max44009 +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Max44009 KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +getLux KEYWORD2 +getError KEYWORD2 +setHighThreshold KEYWORD2 +getHighThreshold KEYWORD2 +setLowThreshold KEYWORD2 +getLowThreshold KEYWORD2 +setThresholdTimer KEYWORD2 +getThresholdTimer KEYWORD2 +setConfiguration KEYWORD2 +getConfiguration KEYWORD2 +setAutomaticMode KEYWORD2 +setContinuousMode KEYWORD2 +setManualMode KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/lib/Max44009/library.json b/lib/Max44009/library.json new file mode 100644 index 0000000..0f10a75 --- /dev/null +++ b/lib/Max44009/library.json @@ -0,0 +1,24 @@ +{ + "name": "Max44009", + "keywords": "MAX44009,Lux,light", + "description": "library for MAX44009 Lux sensor Arduino.", + "authors": + [ + { + "name": "Rob Tillaart", + "email": "Rob.Tillaart@gmail.com", + "maintainer": true + } + ], + "repository": + { + "type": "git", + "url": "https://github.com/RobTillaart/Arduino.git" + }, + "version":"0.1.9", + "frameworks": "arduino", + "platforms": "*", + "export": { + "include": "libraries/Max44009" + } +} diff --git a/lib/Max44009/library.properties b/lib/Max44009/library.properties new file mode 100644 index 0000000..8899bd7 --- /dev/null +++ b/lib/Max44009/library.properties @@ -0,0 +1,9 @@ +name=Max44009 +version=0.1.9 +author=Rob Tillaart +maintainer=Rob Tillaart +sentence=Library for MAX44009 lux sensor Arduino. +paragraph= +category=Sensors +url=https://github.com/RobTillaart/Arduino/tree/master/libraries/ +architectures=* \ No newline at end of file diff --git a/lib/Max44009/max44009.cpp b/lib/Max44009/max44009.cpp new file mode 100644 index 0000000..b386ed0 --- /dev/null +++ b/lib/Max44009/max44009.cpp @@ -0,0 +1,201 @@ +// +// FILE: Max44009.cpp +// AUTHOR: Rob Tillaart +// VERSION: 0.1.9 +// PURPOSE: library for MAX44009 lux sensor Arduino +// URL: https://github.com/RobTillaart/Arduino/tree/master/libraries +// +// Released to the public domain +// +// 0.1.9 - 2018-07-01 issue #108 Fix shift math +// (thanks Roland vandecook) +// 0.1.8 - 2018-05-13 issue #105 Fix read register +// (thanks morxGrillmeister) +// 0.1.7 - 2018-04-02 issue #98 extend constructor for ESP8266 +// 0.1.6 - 2017-07-26 revert double to float +// 0.1.5 - updated history +// 0.1.4 - added setAutomaticMode() to max44009.h (thanks debsahu) +// 0.1.03 - added configuration +// 0.1.02 - added threshold code +// 0.1.01 - added interrupt code +// 0.1.00 - initial version + +#include "Max44009.h" + + +Max44009::Max44009(const uint8_t address, const uint8_t dataPin, const uint8_t clockPin) +{ + _address = address; +#ifdef ESP8266 + Wire.begin(dataPin, clockPin); +#else // other platforms + Wire.begin(); +#endif + // TWBR = 12; // Wire.setClock(400000); + _data = 0; + _error = 0; +} + +Max44009::Max44009(const uint8_t address, bool continuousMode) +{ + _address = address; + Wire.begin(); + // TWBR = 12; // Wire.setClock(400000); + _data = 0; + _error = 0; + if (continuousMode) + { + setContinuousMode(); + } + else + { + setAutomaticMode(); + } +} + +float Max44009::getLux(void) +{ + uint8_t dhi = read(MAX44009_LUX_READING_HIGH); + uint8_t dlo = read(MAX44009_LUX_READING_LOW); + uint8_t e = dhi >> 4; + uint32_t m = ((dhi & 0x0F) << 4) + (dlo & 0x0F); + m <<= e; + float val = m * 0.045; + return val; +} + +int Max44009::getError() +{ + int e = _error; + _error = 0; + return e; +} + +void Max44009::setHighThreshold(const float value) +{ + setThreshold(MAX44009_THRESHOLD_HIGH, value); +} + +float Max44009::getHighThreshold(void) +{ + return getThreshold(MAX44009_THRESHOLD_HIGH); +} + +void Max44009::setLowThreshold(const float value) +{ + setThreshold(MAX44009_THRESHOLD_LOW, value); +} + +float Max44009::getLowThreshold(void) +{ + return getThreshold(MAX44009_THRESHOLD_LOW); +} + +void Max44009::setThresholdTimer(const uint8_t value) +{ + write(MAX44009_THRESHOLD_TIMER, value); +} + +uint8_t Max44009::getThresholdTimer() +{ + return read(MAX44009_THRESHOLD_TIMER); +} + +void Max44009::setConfiguration(const uint8_t value) +{ + write(MAX44009_CONFIGURATION, value); +} + +uint8_t Max44009::getConfiguration() +{ + return read(MAX44009_CONFIGURATION); +} + +void Max44009::setAutomaticMode() +{ + uint8_t config = read(MAX44009_CONFIGURATION); + config &= ~MAX44009_CFG_CONTINUOUS; // off + config &= ~MAX44009_CFG_MANUAL; // off + write(MAX44009_CONFIGURATION, config); +} + +void Max44009::setContinuousMode() +{ + uint8_t config = read(MAX44009_CONFIGURATION); + config |= MAX44009_CFG_CONTINUOUS; // on + config &= ~MAX44009_CFG_MANUAL; // off + write(MAX44009_CONFIGURATION, config); +} + +void Max44009::setManualMode(uint8_t CDR, uint8_t TIM) +{ + if (CDR !=0) CDR = 1; + if (TIM > 7) TIM = 7; + uint8_t config = read(MAX44009_CONFIGURATION); + config &= ~MAX44009_CFG_CONTINUOUS; // off + config |= MAX44009_CFG_MANUAL; // on + config &= 0xF0; // clear CDR & TIM bits + config |= CDR << 3 | TIM; + write(MAX44009_CONFIGURATION, config); +} + +/////////////////////////////////////////////////////////// +// +// PRIVATE +// +void Max44009::setThreshold(const uint8_t reg, const float value) +{ + // TODO CHECK RANGE + uint32_t m = round(value / 0.045); // mulitply * 22.22222222 is faster. + uint8_t e = 0; + while (m > 255) + { + m >>= 1; + e++; + }; + m = (m >> 4) & 0x0F; + e <<= 4; + write(reg, e | m); +} + +float Max44009::getThreshold(uint8_t reg) +{ + uint8_t data = read(reg); + uint8_t e = (data & 0xF0) >> 4; + uint32_t m = ((data & 0x0F) << 4) + 0x0F; + m <<= e; + float val = m * 0.045; + return val; +} + +uint8_t Max44009::read(uint8_t reg) +{ + Wire.beginTransmission(_address); + Wire.write(reg); + _error = Wire.endTransmission(); + if (_error != 0) + { + return _data; // last value + } + if (Wire.requestFrom(_address, (uint8_t) 1) != 1) + { + _error = 10; + return _data; // last value + } +#if (ARDUINO < 100) + _data = Wire.receive(); +#else + _data = Wire.read(); +#endif + return _data; +} + +void Max44009::write(uint8_t reg, uint8_t value) +{ + Wire.beginTransmission(_address); + Wire.write(reg); + Wire.write(value); + _error = Wire.endTransmission(); +} + +// --- END OF FILE --- \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/COPYING b/lib/NeoPixelBus_by_Makuna/COPYING new file mode 100644 index 0000000..153d416 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/ReadMe.md b/lib/NeoPixelBus_by_Makuna/ReadMe.md new file mode 100644 index 0000000..7e76411 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/ReadMe.md @@ -0,0 +1,35 @@ +# NeoPixelBus + +[![Donate](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6AA97KE54UJR4) + +Arduino NeoPixel library + +A library to control one wire protocol RGB and RGBW leds like APA106, SK6812, WS2811, WS2812 and WS2813 that are commonly refered to as NeoPixels and two wire protocol RGB like Lpd8806, APA102 and SK9822 commonly refered to as DotStars. +Supports most Arduino platforms. + +Please read this best practices link before connecting your NeoPixels, it will save you a lot of time and effort. +[Adafruit NeoPixel Best Practices](https://learn.adafruit.com/adafruit-neopixel-uberguide/best-practices) + +For quick questions and support jump on Gitter and ask away. +[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Makuna/NeoPixelBus?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +For bugs, make sure there isn't an active issue and then create one. + +## Why this library and not FastLED or some other library? +See [Why this Library in the Wiki](https://github.com/Makuna/NeoPixelBus/wiki/Library-Comparisons). + +## Documentation +[See Wiki](https://github.com/Makuna/NeoPixelBus/wiki) + +## Installing This Library (prefered, you just want to use it) +Open the Library Manager and search for "NeoPixelBus by Makuna" and install + +## Installing This Library From GitHub (advanced, you want to contribute) +Create a directory in your Arduino\Library folder named "NeoPixelBus" +Clone (Git) this project into that folder. +It should now show up in the import list when you restart Arduino IDE. + + + + + diff --git a/lib/NeoPixelBus_by_Makuna/examples/DotStarTest/DotStarTest.ino b/lib/NeoPixelBus_by_Makuna/examples/DotStarTest/DotStarTest.ino new file mode 100644 index 0000000..45201ab --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/DotStarTest/DotStarTest.ino @@ -0,0 +1,88 @@ +// DotStarTest +// This example will cycle between showing four pixels as Red, Green, Blue, White +// and then showing those pixels as Black. +// +// There is serial output of the current state so you can confirm and follow along +// + +#include + +const uint16_t PixelCount = 4; // this example assumes 4 pixels, making it smaller will cause a failure + +// make sure to set this to the correct pins +const uint8_t DotClockPin = 2; +const uint8_t DotDataPin = 3; + +#define colorSaturation 128 + +// for software bit bang +NeoPixelBus strip(PixelCount, DotClockPin, DotDataPin); + +// for hardware SPI (best performance but must use hardware pins) +//NeoPixelBus strip(PixelCount); + +// DotStars that support RGB color and a overall luminance/brightness value +// NeoPixelBus strip(PixelCount, DotClockPin, DotDataPin); +// DotStars that support RGBW color with a seperate white element +//NeoPixelBus strip(PixelCount, DotClockPin, DotDataPin); + +RgbColor red(colorSaturation, 0, 0); +RgbColor green(0, colorSaturation, 0); +RgbColor blue(0, 0, colorSaturation); +RgbColor white(colorSaturation); +RgbColor black(0); + +// for use with RGB DotStars when using the luminance/brightness global value +// note that its range is only 0 - 31 (31 is full bright) and +// also note that it is not useful for POV displays as it will cause more flicker +RgbwColor redL(colorSaturation, 0, 0, 31); // use white value to store luminance +RgbwColor greenL(0, colorSaturation, 0, 31); // use white value to store luminance +RgbwColor blueL(0, 0, colorSaturation, 31); // use white value to store luminance +RgbwColor whiteL(255, 255, 255, colorSaturation / 8); // luminance is only 0-31 + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + Serial.println(); + Serial.println("Initializing..."); + Serial.flush(); + + // this resets all the neopixels to an off state + strip.Begin(); + strip.ClearTo(black); + strip.Show(); + + Serial.println(); + Serial.println("Running..."); +} + + +void loop() +{ + delay(5000); + + Serial.println("Colors R, G, B, W..."); + + // set the colors, + strip.SetPixelColor(0, red); + strip.SetPixelColor(1, green); + strip.SetPixelColor(2, blue); + strip.SetPixelColor(3, white); + strip.Show(); + + + delay(5000); + + Serial.println("Off ..."); + + // turn off the pixels + strip.SetPixelColor(0, black); + strip.SetPixelColor(1, black); + strip.SetPixelColor(2, black); + strip.SetPixelColor(3, black); + strip.Show(); + +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/NeoPixelBrightness/NeoPixelBrightness.ino b/lib/NeoPixelBus_by_Makuna/examples/NeoPixelBrightness/NeoPixelBrightness.ino new file mode 100644 index 0000000..01af6cb --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/NeoPixelBrightness/NeoPixelBrightness.ino @@ -0,0 +1,83 @@ +// NeoPixelBrightness +// This example will cycle brightness from high to low of +// three pixels colored Red, Green, Blue. +// This demonstrates the use of the NeoPixelBrightnessBus +// with integrated brightness support +// +// There is serial output of the current state so you can +// confirm and follow along +// + +#include // instead of NeoPixelBus.h + +const uint16_t PixelCount = 3; // this example assumes 3 pixels, making it smaller will cause a failure +const uint8_t PixelPin = 14; // make sure to set this to the correct pin, ignored for Esp8266 + +#define colorSaturation 255 // saturation of color constants +RgbColor red(colorSaturation, 0, 0); +RgbColor green(0, colorSaturation, 0); +RgbColor blue(0, 0, colorSaturation); + +// Make sure to provide the correct color order feature +// for your NeoPixels +NeoPixelBrightnessBus strip(PixelCount, PixelPin); + +// you loose the original color the lower the dim value used +// here due to quantization +const uint8_t c_MinBrightness = 8; +const uint8_t c_MaxBrightness = 255; + +int8_t direction; // current direction of dimming + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + Serial.println(); + Serial.println("Initializing..."); + Serial.flush(); + + // this resets all the neopixels to an off state + strip.Begin(); + strip.Show(); + + direction = -1; // default to dim first + + Serial.println(); + Serial.println("Running..."); + + // set our three original colors + strip.SetPixelColor(0, red); + strip.SetPixelColor(1, green); + strip.SetPixelColor(2, blue); + + strip.Show(); +} + + +void loop() +{ + uint8_t brightness = strip.GetBrightness(); + Serial.println(brightness); + + delay(100); + + // swap diection of dim when limits are reached + // + if (direction < 0 && brightness <= c_MinBrightness) + { + direction = 1; + } + else if (direction > 0 && brightness >= c_MaxBrightness) + { + direction = -1; + } + // apply dimming + brightness += direction; + strip.SetBrightness(brightness); + + // show the results + strip.Show(); +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/NeoPixelGamma/NeoPixelGamma.ino b/lib/NeoPixelBus_by_Makuna/examples/NeoPixelGamma/NeoPixelGamma.ino new file mode 100644 index 0000000..3ed9152 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/NeoPixelGamma/NeoPixelGamma.ino @@ -0,0 +1,95 @@ +// NeoPixelGamma +// This example will display a timed series of color gradiants with gamma correction +// and then without. +// If the last pixel is on, then the colors being shown are color corrected. +// It will show Red grandiant, Green grandiant, Blue grandiant, a White grandiant, and +// then repeat. +// +// This will demonstrate the use of the NeoGamma class +// +// + +#include +#include + +const uint16_t PixelCount = 16; // make sure to set this to the number of pixels in your strip +const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 + +NeoPixelBus strip(PixelCount, PixelPin); +// for esp8266 omit the pin +//NeoPixelBus strip(PixelCount); + +// uncomment only one of these to compare memory use or speed +// +// NeoGamma colorGamma; +NeoGamma colorGamma; + +void DrawPixels(bool corrected, HslColor startColor, HslColor stopColor) +{ + for (uint16_t index = 0; index < strip.PixelCount() - 1; index++) + { + float progress = index / static_cast(strip.PixelCount() - 2); + RgbColor color = HslColor::LinearBlend(startColor, stopColor, progress); + if (corrected) + { + color = colorGamma.Correct(color); + } + strip.SetPixelColor(index, color); + } + + // use the last pixel to indicate if we are showing corrected colors or not + if (corrected) + { + strip.SetPixelColor(strip.PixelCount() - 1, RgbColor(64)); + } + else + { + strip.SetPixelColor(strip.PixelCount() - 1, RgbColor(0)); + } + + strip.Show(); +} + +void setup() +{ + strip.Begin(); + strip.Show(); +} + +void loop() +{ + HslColor startColor; + HslColor stopColor; + + // red color + startColor = HslColor(0.0f, 1.0f, 0.0f); + stopColor = HslColor(0.0f, 1.0f, 0.5f); + DrawPixels(true, startColor, stopColor); + delay(5000); + DrawPixels(false, startColor, stopColor); + delay(5000); + + // green color + startColor = HslColor(0.33f, 1.0f, 0.0f); + stopColor = HslColor(0.33f, 1.0f, 0.5f); + DrawPixels(true, startColor, stopColor); + delay(5000); + DrawPixels(false, startColor, stopColor); + delay(5000); + + // blue color + startColor = HslColor(0.66f, 1.0f, 0.0f); + stopColor = HslColor(0.66f, 1.0f, 0.5f); + DrawPixels(true, startColor, stopColor); + delay(5000); + DrawPixels(false, startColor, stopColor); + delay(5000); + + // white color + startColor = HslColor(0.0f, 0.0f, 0.0f); + stopColor = HslColor(0.0f, 0.0f, 0.5f); + DrawPixels(true, startColor, stopColor); + delay(5000); + DrawPixels(false, startColor, stopColor); + delay(5000); +} \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/examples/NeoPixelTest/NeoPixelTest.ino b/lib/NeoPixelBus_by_Makuna/examples/NeoPixelTest/NeoPixelTest.ino new file mode 100644 index 0000000..415c853 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/NeoPixelTest/NeoPixelTest.ino @@ -0,0 +1,139 @@ +// NeoPixelTest +// This example will cycle between showing four pixels as Red, Green, Blue, White +// and then showing those pixels as Black. +// +// Included but commented out are examples of configuring a NeoPixelBus for +// different color order including an extra white channel, different data speeds, and +// for Esp8266 different methods to send the data. +// NOTE: You will need to make sure to pick the one for your platform +// +// +// There is serial output of the current state so you can confirm and follow along +// + +#include + +const uint16_t PixelCount = 4; // this example assumes 4 pixels, making it smaller will cause a failure +const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 + +#define colorSaturation 128 + +// three element pixels, in different order and speeds +NeoPixelBus strip(PixelCount, PixelPin); +//NeoPixelBus strip(PixelCount, PixelPin); + +// For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use. +// There are other Esp8266 alternative methods that provide more pin options, but also have +// other side effects. +// for details see wiki linked here https://github.com/Makuna/NeoPixelBus/wiki/ESP8266-NeoMethods + +// You can also use one of these for Esp8266, +// each having their own restrictions +// +// These two are the same as above as the DMA method is the default +// NOTE: These will ignore the PIN and use GPI03 pin +//NeoPixelBus strip(PixelCount, PixelPin); +//NeoPixelBus strip(PixelCount, PixelPin); + +// Uart method is good for the Esp-01 or other pin restricted modules +// for details see wiki linked here https://github.com/Makuna/NeoPixelBus/wiki/ESP8266-NeoMethods +// NOTE: These will ignore the PIN and use GPI02 pin +//NeoPixelBus strip(PixelCount, PixelPin); +//NeoPixelBus strip(PixelCount, PixelPin); + +// The bitbang method is really only good if you are not using WiFi features of the ESP +// It works with all but pin 16 +//NeoPixelBus strip(PixelCount, PixelPin); +//NeoPixelBus strip(PixelCount, PixelPin); + +// four element pixels, RGBW +//NeoPixelBus strip(PixelCount, PixelPin); + +RgbColor red(colorSaturation, 0, 0); +RgbColor green(0, colorSaturation, 0); +RgbColor blue(0, 0, colorSaturation); +RgbColor white(colorSaturation); +RgbColor black(0); + +HslColor hslRed(red); +HslColor hslGreen(green); +HslColor hslBlue(blue); +HslColor hslWhite(white); +HslColor hslBlack(black); + + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + Serial.println(); + Serial.println("Initializing..."); + Serial.flush(); + + // this resets all the neopixels to an off state + strip.Begin(); + strip.Show(); + + + Serial.println(); + Serial.println("Running..."); +} + + +void loop() +{ + delay(5000); + + Serial.println("Colors R, G, B, W..."); + + // set the colors, + // if they don't match in order, you need to use NeoGrbFeature feature + strip.SetPixelColor(0, red); + strip.SetPixelColor(1, green); + strip.SetPixelColor(2, blue); + strip.SetPixelColor(3, white); + // the following line demonstrates rgbw color support + // if the NeoPixels are rgbw types the following line will compile + // if the NeoPixels are anything else, the following line will give an error + //strip.SetPixelColor(3, RgbwColor(colorSaturation)); + strip.Show(); + + + delay(5000); + + Serial.println("Off ..."); + + // turn off the pixels + strip.SetPixelColor(0, black); + strip.SetPixelColor(1, black); + strip.SetPixelColor(2, black); + strip.SetPixelColor(3, black); + strip.Show(); + + delay(5000); + + Serial.println("HSL Colors R, G, B, W..."); + + // set the colors, + // if they don't match in order, you may need to use NeoGrbFeature feature + strip.SetPixelColor(0, hslRed); + strip.SetPixelColor(1, hslGreen); + strip.SetPixelColor(2, hslBlue); + strip.SetPixelColor(3, hslWhite); + strip.Show(); + + + delay(5000); + + Serial.println("Off again..."); + + // turn off the pixels + strip.SetPixelColor(0, hslBlack); + strip.SetPixelColor(1, hslBlack); + strip.SetPixelColor(2, hslBlack); + strip.SetPixelColor(3, hslBlack); + strip.Show(); + +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelAnimation/NeoPixelAnimation.ino b/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelAnimation/NeoPixelAnimation.ino new file mode 100644 index 0000000..fc3a372 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelAnimation/NeoPixelAnimation.ino @@ -0,0 +1,222 @@ +// NeoPixelAnimation +// This example will randomly pick a new color for each pixel and animate +// the current color to the new color over a random small amount of time, using +// a randomly selected animation curve. +// It will repeat this process once all pixels have finished the animation +// +// This will demonstrate the use of the NeoPixelAnimator extended time feature. +// This feature allows for different time scales to be used, allowing slow extended +// animations to be created. +// +// This will demonstrate the use of the NeoEase animation ease methods; that provide +// simulated acceleration to the animations. +// +// It also includes platform specific code for Esp8266 that demonstrates easy +// animation state and function definition inline. This is not available on AVR +// Arduinos; but the AVR compatible code is also included for comparison. +// +// The example includes some serial output that you can follow along with as it +// does the animation. +// + +#include +#include + +const uint16_t PixelCount = 4; // make sure to set this to the number of pixels in your strip +const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 + +NeoPixelBus strip(PixelCount, PixelPin); +// For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use. +// There are other Esp8266 alternative methods that provide more pin options, but also have +// other side effects. +// for details see wiki linked here https://github.com/Makuna/NeoPixelBus/wiki/ESP8266-NeoMethods + +// NeoPixel animation time management object +NeoPixelAnimator animations(PixelCount, NEO_CENTISECONDS); + +// create with enough animations to have one per pixel, depending on the animation +// effect, you may need more or less. +// +// since the normal animation time range is only about 65 seconds, by passing timescale value +// to the NeoPixelAnimator constructor we can increase the time range, but we also increase +// the time between the animation updates. +// NEO_CENTISECONDS will update the animations every 100th of a second rather than the default +// of a 1000th of a second, but the time range will now extend from about 65 seconds to about +// 10.9 minutes. But you must remember that the values passed to StartAnimations are now +// in centiseconds. +// +// Possible values from 1 to 32768, and there some helpful constants defined as... +// NEO_MILLISECONDS 1 // ~65 seconds max duration, ms updates +// NEO_CENTISECONDS 10 // ~10.9 minutes max duration, centisecond updates +// NEO_DECISECONDS 100 // ~1.8 hours max duration, decisecond updates +// NEO_SECONDS 1000 // ~18.2 hours max duration, second updates +// NEO_DECASECONDS 10000 // ~7.5 days, 10 second updates +// + +#if defined(NEOPIXEBUS_NO_STL) +// for AVR, you need to manage the state due to lack of STL/compiler support +// for Esp8266 you can define the function using a lambda and state is created for you +// see below for an example +struct MyAnimationState +{ + RgbColor StartingColor; // the color the animation starts at + RgbColor EndingColor; // the color the animation will end at + AnimEaseFunction Easeing; // the acceleration curve it will use +}; + +MyAnimationState animationState[PixelCount]; +// one entry per pixel to match the animation timing manager + +void AnimUpdate(const AnimationParam& param) +{ + // first apply an easing (curve) to the animation + // this simulates acceleration to the effect + float progress = animationState[param.index].Easeing(param.progress); + + // this gets called for each animation on every time step + // progress will start at 0.0 and end at 1.0 + // we use the blend function on the RgbColor to mix + // color based on the progress given to us in the animation + RgbColor updatedColor = RgbColor::LinearBlend( + animationState[param.index].StartingColor, + animationState[param.index].EndingColor, + progress); + // apply the color to the strip + strip.SetPixelColor(param.index, updatedColor); +} +#endif + +void SetRandomSeed() +{ + uint32_t seed; + + // random works best with a seed that can use 31 bits + // analogRead on a unconnected pin tends toward less than four bits + seed = analogRead(0); + delay(1); + + for (int shifts = 3; shifts < 31; shifts += 3) + { + seed ^= analogRead(0) << shifts; + delay(1); + } + + // Serial.println(seed); + randomSeed(seed); +} + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + strip.Begin(); + strip.Show(); + + SetRandomSeed(); + + // just pick some colors + for (uint16_t pixel = 0; pixel < PixelCount; pixel++) + { + RgbColor color = RgbColor(random(255), random(255), random(255)); + strip.SetPixelColor(pixel, color); + } + + Serial.println(); + Serial.println("Running..."); +} + + +void SetupAnimationSet() +{ + // setup some animations + for (uint16_t pixel = 0; pixel < PixelCount; pixel++) + { + const uint8_t peak = 128; + + // pick a random duration of the animation for this pixel + // since values are centiseconds, the range is 1 - 4 seconds + uint16_t time = random(100, 400); + + // each animation starts with the color that was present + RgbColor originalColor = strip.GetPixelColor(pixel); + // and ends with a random color + RgbColor targetColor = RgbColor(random(peak), random(peak), random(peak)); + // with the random ease function + AnimEaseFunction easing; + + switch (random(3)) + { + case 0: + easing = NeoEase::CubicIn; + break; + case 1: + easing = NeoEase::CubicOut; + break; + case 2: + easing = NeoEase::QuadraticInOut; + break; + } + +#if defined(NEOPIXEBUS_NO_STL) + // each animation starts with the color that was present + animationState[pixel].StartingColor = originalColor; + // and ends with a random color + animationState[pixel].EndingColor = targetColor; + // using the specific curve + animationState[pixel].Easeing = easing; + + // now use the animation state we just calculated and start the animation + // which will continue to run and call the update function until it completes + animations.StartAnimation(pixel, time, AnimUpdate); +#else + // we must supply a function that will define the animation, in this example + // we are using "lambda expression" to define the function inline, which gives + // us an easy way to "capture" the originalColor and targetColor for the call back. + // + // this function will get called back when ever the animation needs to change + // the state of the pixel, it will provide a animation progress value + // from 0.0 (start of animation) to 1.0 (end of animation) + // + // we use this progress value to define how we want to animate in this case + // we call RgbColor::LinearBlend which will return a color blended between + // the values given, by the amount passed, hich is also a float value from 0.0-1.0. + // then we set the color. + // + // There is no need for the MyAnimationState struct as the compiler takes care + // of those details for us + AnimUpdateCallback animUpdate = [=](const AnimationParam& param) + { + // progress will start at 0.0 and end at 1.0 + // we convert to the curve we want + float progress = easing(param.progress); + + // use the curve value to apply to the animation + RgbColor updatedColor = RgbColor::LinearBlend(originalColor, targetColor, progress); + strip.SetPixelColor(pixel, updatedColor); + }; + + // now use the animation properties we just calculated and start the animation + // which will continue to run and call the update function until it completes + animations.StartAnimation(pixel, time, animUpdate); +#endif + } +} + +void loop() +{ + if (animations.IsAnimating()) + { + // the normal loop just needs these two to run the active animations + animations.UpdateAnimations(); + strip.Show(); + } + else + { + Serial.println(); + Serial.println("Setup Next Set..."); + // example function that sets up some animations + SetupAnimationSet(); + } +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelCylon/NeoPixelCylon.ino b/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelCylon/NeoPixelCylon.ino new file mode 100644 index 0000000..4eec443 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelCylon/NeoPixelCylon.ino @@ -0,0 +1,123 @@ +// NeoPixelCylon +// This example will move a Cylon Red Eye back and forth across the +// the full collection of pixels on the strip. +// +// This will demonstrate the use of the NeoEase animation ease methods; that provide +// simulated acceleration to the animations. +// +// + +#include +#include + +const uint16_t PixelCount = 16; // make sure to set this to the number of pixels in your strip +const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 +const RgbColor CylonEyeColor(HtmlColor(0x7f0000)); + +NeoPixelBus strip(PixelCount, PixelPin); +// for esp8266 omit the pin +//NeoPixelBus strip(PixelCount); + +NeoPixelAnimator animations(2); // only ever need 2 animations + +uint16_t lastPixel = 0; // track the eye position +int8_t moveDir = 1; // track the direction of movement + +// uncomment one of the lines below to see the effects of +// changing the ease function on the movement animation +AnimEaseFunction moveEase = +// NeoEase::Linear; +// NeoEase::QuadraticInOut; +// NeoEase::CubicInOut; + NeoEase::QuarticInOut; +// NeoEase::QuinticInOut; +// NeoEase::SinusoidalInOut; +// NeoEase::ExponentialInOut; +// NeoEase::CircularInOut; + +void FadeAll(uint8_t darkenBy) +{ + RgbColor color; + for (uint16_t indexPixel = 0; indexPixel < strip.PixelCount(); indexPixel++) + { + color = strip.GetPixelColor(indexPixel); + color.Darken(darkenBy); + strip.SetPixelColor(indexPixel, color); + } +} + +void FadeAnimUpdate(const AnimationParam& param) +{ + if (param.state == AnimationState_Completed) + { + FadeAll(10); + animations.RestartAnimation(param.index); + } +} + +void MoveAnimUpdate(const AnimationParam& param) +{ + // apply the movement animation curve + float progress = moveEase(param.progress); + + // use the curved progress to calculate the pixel to effect + uint16_t nextPixel; + if (moveDir > 0) + { + nextPixel = progress * PixelCount; + } + else + { + nextPixel = (1.0f - progress) * PixelCount; + } + + // if progress moves fast enough, we may move more than + // one pixel, so we update all between the calculated and + // the last + if (lastPixel != nextPixel) + { + for (uint16_t i = lastPixel + moveDir; i != nextPixel; i += moveDir) + { + strip.SetPixelColor(i, CylonEyeColor); + } + } + strip.SetPixelColor(nextPixel, CylonEyeColor); + + lastPixel = nextPixel; + + if (param.state == AnimationState_Completed) + { + // reverse direction of movement + moveDir *= -1; + + // done, time to restart this position tracking animation/timer + animations.RestartAnimation(param.index); + } +} + +void SetupAnimations() +{ + // fade all pixels providing a tail that is longer the faster + // the pixel moves. + animations.StartAnimation(0, 5, FadeAnimUpdate); + + // take several seconds to move eye fron one side to the other + animations.StartAnimation(1, 2000, MoveAnimUpdate); +} + +void setup() +{ + strip.Begin(); + strip.Show(); + + SetupAnimations(); +} + +void loop() +{ + // this is all that is needed to keep it running + // and avoiding using delay() is always a good thing for + // any timing related routines + animations.UpdateAnimations(); + strip.Show(); +} diff --git a/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelFunFadeInOut/NeoPixelFunFadeInOut.ino b/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelFunFadeInOut/NeoPixelFunFadeInOut.ino new file mode 100644 index 0000000..f6c065c --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelFunFadeInOut/NeoPixelFunFadeInOut.ino @@ -0,0 +1,130 @@ +// NeoPixelFunFadeInOut +// This example will randomly pick a color and fade all pixels to that color, then +// it will fade them to black and restart over +// +// This example demonstrates the use of a single animation channel to animate all +// the pixels at once. +// +#include +#include + +const uint16_t PixelCount = 16; // make sure to set this to the number of pixels in your strip +const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 +const uint8_t AnimationChannels = 1; // we only need one as all the pixels are animated at once + +NeoPixelBus strip(PixelCount, PixelPin); +// For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use. +// There are other Esp8266 alternative methods that provide more pin options, but also have +// other side effects. +// for details see wiki linked here https://github.com/Makuna/NeoPixelBus/wiki/ESP8266-NeoMethods + +NeoPixelAnimator animations(AnimationChannels); // NeoPixel animation management object + +boolean fadeToColor = true; // general purpose variable used to store effect state + + +// what is stored for state is specific to the need, in this case, the colors. +// basically what ever you need inside the animation update function +struct MyAnimationState +{ + RgbColor StartingColor; + RgbColor EndingColor; +}; + +// one entry per pixel to match the animation timing manager +MyAnimationState animationState[AnimationChannels]; + +void SetRandomSeed() +{ + uint32_t seed; + + // random works best with a seed that can use 31 bits + // analogRead on a unconnected pin tends toward less than four bits + seed = analogRead(0); + delay(1); + + for (int shifts = 3; shifts < 31; shifts += 3) + { + seed ^= analogRead(0) << shifts; + delay(1); + } + + randomSeed(seed); +} + +// simple blend function +void BlendAnimUpdate(const AnimationParam& param) +{ + // this gets called for each animation on every time step + // progress will start at 0.0 and end at 1.0 + // we use the blend function on the RgbColor to mix + // color based on the progress given to us in the animation + RgbColor updatedColor = RgbColor::LinearBlend( + animationState[param.index].StartingColor, + animationState[param.index].EndingColor, + param.progress); + + // apply the color to the strip + for (uint16_t pixel = 0; pixel < PixelCount; pixel++) + { + strip.SetPixelColor(pixel, updatedColor); + } +} + +void FadeInFadeOutRinseRepeat(float luminance) +{ + if (fadeToColor) + { + // Fade upto a random color + // we use HslColor object as it allows us to easily pick a hue + // with the same saturation and luminance so the colors picked + // will have similiar overall brightness + RgbColor target = HslColor(random(360) / 360.0f, 1.0f, luminance); + uint16_t time = random(800, 2000); + + animationState[0].StartingColor = strip.GetPixelColor(0); + animationState[0].EndingColor = target; + + animations.StartAnimation(0, time, BlendAnimUpdate); + } + else + { + // fade to black + uint16_t time = random(600, 700); + + animationState[0].StartingColor = strip.GetPixelColor(0); + animationState[0].EndingColor = RgbColor(0); + + animations.StartAnimation(0, time, BlendAnimUpdate); + } + + // toggle to the next effect state + fadeToColor = !fadeToColor; +} + +void setup() +{ + strip.Begin(); + strip.Show(); + + SetRandomSeed(); +} + +void loop() +{ + if (animations.IsAnimating()) + { + // the normal loop just needs these two to run the active animations + animations.UpdateAnimations(); + strip.Show(); + } + else + { + // no animation runnning, start some + // + FadeInFadeOutRinseRepeat(0.2f); // 0.0 = black, 0.25 is normal, 0.5 is bright + } +} + + + diff --git a/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelFunLoop/NeoPixelFunLoop.ino b/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelFunLoop/NeoPixelFunLoop.ino new file mode 100644 index 0000000..c8a7788 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelFunLoop/NeoPixelFunLoop.ino @@ -0,0 +1,139 @@ +// NeoPixelFunLoop +// This example will move a trail of light around a series of pixels. +// A ring formation of pixels looks best. +// The trail will have a slowly fading tail. +// +// This will demonstrate the use of the NeoPixelAnimator. +// It shows the advanced use an animation to control the modification and +// starting of other animations. +// It also shows the normal use of animating colors. +// It also demonstrates the ability to share an animation channel rather than +// hard code them to pixels. +// + +#include +#include + + +const uint16_t PixelCount = 16; // make sure to set this to the number of pixels in your strip +const uint16_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 +const uint16_t AnimCount = PixelCount / 5 * 2 + 1; // we only need enough animations for the tail and one extra + +const uint16_t PixelFadeDuration = 300; // third of a second +// one second divide by the number of pixels = loop once a second +const uint16_t NextPixelMoveDuration = 1000 / PixelCount; // how fast we move through the pixels + +NeoGamma colorGamma; // for any fade animations, best to correct gamma + +NeoPixelBus strip(PixelCount, PixelPin); +// For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use. +// There are other Esp8266 alternative methods that provide more pin options, but also have +// other side effects. +// for details see wiki linked here https://github.com/Makuna/NeoPixelBus/wiki/ESP8266-NeoMethods + +// what is stored for state is specific to the need, in this case, the colors and +// the pixel to animate; +// basically what ever you need inside the animation update function +struct MyAnimationState +{ + RgbColor StartingColor; + RgbColor EndingColor; + uint16_t IndexPixel; // which pixel this animation is effecting +}; + +NeoPixelAnimator animations(AnimCount); // NeoPixel animation management object +MyAnimationState animationState[AnimCount]; +uint16_t frontPixel = 0; // the front of the loop +RgbColor frontColor; // the color at the front of the loop + +void SetRandomSeed() +{ + uint32_t seed; + + // random works best with a seed that can use 31 bits + // analogRead on a unconnected pin tends toward less than four bits + seed = analogRead(0); + delay(1); + + for (int shifts = 3; shifts < 31; shifts += 3) + { + seed ^= analogRead(0) << shifts; + delay(1); + } + + // Serial.println(seed); + randomSeed(seed); +} + +void FadeOutAnimUpdate(const AnimationParam& param) +{ + // this gets called for each animation on every time step + // progress will start at 0.0 and end at 1.0 + // we use the blend function on the RgbColor to mix + // color based on the progress given to us in the animation + RgbColor updatedColor = RgbColor::LinearBlend( + animationState[param.index].StartingColor, + animationState[param.index].EndingColor, + param.progress); + // apply the color to the strip + strip.SetPixelColor(animationState[param.index].IndexPixel, + colorGamma.Correct(updatedColor)); +} + +void LoopAnimUpdate(const AnimationParam& param) +{ + // wait for this animation to complete, + // we are using it as a timer of sorts + if (param.state == AnimationState_Completed) + { + // done, time to restart this position tracking animation/timer + animations.RestartAnimation(param.index); + + // pick the next pixel inline to start animating + // + frontPixel = (frontPixel + 1) % PixelCount; // increment and wrap + if (frontPixel == 0) + { + // we looped, lets pick a new front color + frontColor = HslColor(random(360) / 360.0f, 1.0f, 0.25f); + } + + uint16_t indexAnim; + // do we have an animation available to use to animate the next front pixel? + // if you see skipping, then either you are going to fast or need to increase + // the number of animation channels + if (animations.NextAvailableAnimation(&indexAnim, 1)) + { + animationState[indexAnim].StartingColor = frontColor; + animationState[indexAnim].EndingColor = RgbColor(0, 0, 0); + animationState[indexAnim].IndexPixel = frontPixel; + + animations.StartAnimation(indexAnim, PixelFadeDuration, FadeOutAnimUpdate); + } + } +} + +void setup() +{ + strip.Begin(); + strip.Show(); + + SetRandomSeed(); + + // we use the index 0 animation to time how often we move to the next + // pixel in the strip + animations.StartAnimation(0, NextPixelMoveDuration, LoopAnimUpdate); +} + + +void loop() +{ + // this is all that is needed to keep it running + // and avoiding using delay() is always a good thing for + // any timing related routines + animations.UpdateAnimations(); + strip.Show(); +} + + + diff --git a/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelFunRandomChange/NeoPixelFunRandomChange.ino b/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelFunRandomChange/NeoPixelFunRandomChange.ino new file mode 100644 index 0000000..8e88667 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelFunRandomChange/NeoPixelFunRandomChange.ino @@ -0,0 +1,114 @@ +// NeoPixelFunRandomChange +// This example will randomly select a number pixels and then +// start an animation to blend them from their current color to +// randomly selected a color +// + +#include +#include + +const uint16_t PixelCount = 16; // make sure to set this to the number of pixels in your strip +const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 + +NeoPixelBus strip(PixelCount, PixelPin); +// For Esp8266, the Pin is omitted and it uses GPIO3 due to DMA hardware use. +// There are other Esp8266 alternative methods that provide more pin options, but also have +// other side effects. +// for details see wiki linked here https://github.com/Makuna/NeoPixelBus/wiki/ESP8266-NeoMethods + +NeoPixelAnimator animations(PixelCount); // NeoPixel animation management object + +// what is stored for state is specific to the need, in this case, the colors. +// Basically what ever you need inside the animation update function +struct MyAnimationState +{ + RgbColor StartingColor; + RgbColor EndingColor; +}; + +// one entry per pixel to match the animation timing manager +MyAnimationState animationState[PixelCount]; + +void SetRandomSeed() +{ + uint32_t seed; + + // random works best with a seed that can use 31 bits + // analogRead on a unconnected pin tends toward less than four bits + seed = analogRead(0); + delay(1); + + for (int shifts = 3; shifts < 31; shifts += 3) + { + seed ^= analogRead(0) << shifts; + delay(1); + } + + // Serial.println(seed); + randomSeed(seed); +} + +// simple blend function +void BlendAnimUpdate(const AnimationParam& param) +{ + // this gets called for each animation on every time step + // progress will start at 0.0 and end at 1.0 + // we use the blend function on the RgbColor to mix + // color based on the progress given to us in the animation + RgbColor updatedColor = RgbColor::LinearBlend( + animationState[param.index].StartingColor, + animationState[param.index].EndingColor, + param.progress); + // apply the color to the strip + strip.SetPixelColor(param.index, updatedColor); +} + +void PickRandom(float luminance) +{ + // pick random count of pixels to animate + uint16_t count = random(PixelCount); + while (count > 0) + { + // pick a random pixel + uint16_t pixel = random(PixelCount); + + // pick random time and random color + // we use HslColor object as it allows us to easily pick a color + // with the same saturation and luminance + uint16_t time = random(100, 400); + animationState[pixel].StartingColor = strip.GetPixelColor(pixel); + animationState[pixel].EndingColor = HslColor(random(360) / 360.0f, 1.0f, luminance); + + animations.StartAnimation(pixel, time, BlendAnimUpdate); + + count--; + } +} + +void setup() +{ + strip.Begin(); + strip.Show(); + + SetRandomSeed(); +} + + +void loop() +{ + if (animations.IsAnimating()) + { + // the normal loop just needs these two to run the active animations + animations.UpdateAnimations(); + strip.Show(); + } + else + { + // no animations runnning, start some + // + PickRandom(0.2f); // 0.0 = black, 0.25 is normal, 0.5 is bright + } +} + + + diff --git a/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelRotateLoop/NeoPixelRotateLoop.ino b/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelRotateLoop/NeoPixelRotateLoop.ino new file mode 100644 index 0000000..bdc9af7 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/animations/NeoPixelRotateLoop/NeoPixelRotateLoop.ino @@ -0,0 +1,97 @@ +// NeoPixelFunLoop +// This example will move a trail of light around a series of pixels. +// A ring formation of pixels looks best. +// The trail will have a slowly fading tail. +// +// This will demonstrate the use of the RotateRight method. +// + +#include +#include + + +const uint16_t PixelCount = 16; // make sure to set this to the number of pixels in your strip +const uint16_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 +const uint16_t AnimCount = 1; // we only need one +const uint16_t TailLength = 6; // length of the tail, must be shorter than PixelCount +const float MaxLightness = 0.4f; // max lightness at the head of the tail (0.5f is full bright) + +NeoGamma colorGamma; // for any fade animations, best to correct gamma + +NeoPixelBus strip(PixelCount, PixelPin); +// for esp8266 omit the pin +//NeoPixelBus strip(PixelCount); + +NeoPixelAnimator animations(AnimCount); // NeoPixel animation management object + +void SetRandomSeed() +{ + uint32_t seed; + + // random works best with a seed that can use 31 bits + // analogRead on a unconnected pin tends toward less than four bits + seed = analogRead(0); + delay(1); + + for (int shifts = 3; shifts < 31; shifts += 3) + { + seed ^= analogRead(0) << shifts; + delay(1); + } + + // Serial.println(seed); + randomSeed(seed); +} + +void LoopAnimUpdate(const AnimationParam& param) +{ + // wait for this animation to complete, + // we are using it as a timer of sorts + if (param.state == AnimationState_Completed) + { + // done, time to restart this position tracking animation/timer + animations.RestartAnimation(param.index); + + // rotate the complete strip one pixel to the right on every update + strip.RotateRight(1); + } +} + +void DrawTailPixels() +{ + // using Hsl as it makes it easy to pick from similiar saturated colors + float hue = random(360) / 360.0f; + for (uint16_t index = 0; index < strip.PixelCount() && index <= TailLength; index++) + { + float lightness = index * MaxLightness / TailLength; + RgbColor color = HslColor(hue, 1.0f, lightness); + + strip.SetPixelColor(index, colorGamma.Correct(color)); + } +} + +void setup() +{ + strip.Begin(); + strip.Show(); + + SetRandomSeed(); + + // Draw the tail that will be rotated through all the rest of the pixels + DrawTailPixels(); + + // we use the index 0 animation to time how often we rotate all the pixels + animations.StartAnimation(0, 66, LoopAnimUpdate); +} + + +void loop() +{ + // this is all that is needed to keep it running + // and avoiding using delay() is always a good thing for + // any timing related routines + animations.UpdateAnimations(); + strip.Show(); +} + + diff --git a/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBitmap/NeoPixelBitmap.ino b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBitmap/NeoPixelBitmap.ino new file mode 100644 index 0000000..56071b2 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBitmap/NeoPixelBitmap.ino @@ -0,0 +1,98 @@ +// NeoPixelBuffer +// This example will animate pixels using a bitmap stored on a SD card +// +// +// This will demonstrate the use of the NeoBitmapFile object +// NOTE: The images provided in the example directory should be copied to +// the root of the SD card so the below code will find it. +// NOTE: This sample and the included images were built for a 144 pixel strip so +// running this with a smaller string may not look as interesting. Try providing +// your own 24 bit bitmap for better results. + +#include +#include +#include +#include + +const int chipSelect = D8; // make sure to set this to your SD carder reader CS + +//typedef NeoGrbFeature MyPixelColorFeature; +typedef NeoGrbwFeature MyPixelColorFeature; + +const uint16_t PixelCount = 144; // the sample images are meant for 144 pixels +const uint16_t PixelPin = 2; +const uint16_t AnimCount = 1; // we only need one + +NeoPixelBus strip(PixelCount, PixelPin); +// for esp8266 omit the pin +//NeoPixelBus strip(PixelCount); +NeoPixelAnimator animations(AnimCount); // NeoPixel animation management object + +// our NeoBitmapFile will use the same color feature as NeoPixelBus and +// we want it to use the SD File object +NeoBitmapFile image; + +uint16_t animState; + +void LoopAnimUpdate(const AnimationParam& param) +{ + // wait for this animation to complete, + // we are using it as a timer of sorts + if (param.state == AnimationState_Completed) + { + // done, time to restart this position tracking animation/timer + animations.RestartAnimation(param.index); + + // draw the complete row at animState to the complete strip + image.Blt(strip, 0, 0, animState, image.Width()); + animState = (animState + 1) % image.Height(); // increment and wrap + } +} + +void setup() { + Serial.begin(115200); + while (!Serial); // wait for serial attach + + strip.Begin(); + strip.Show(); + + Serial.print("Initializing SD card..."); + + // see if the card is present and can be initialized: + if (!SD.begin(chipSelect)) + { + Serial.println("Card failed, or not present"); + // don't do anything more: + return; + } + Serial.println("card initialized."); + + // open the file + File bitmapFile = SD.open("strings.bmp"); + if (!bitmapFile) + { + Serial.println("File open fail, or not present"); + // don't do anything more: + return; + } + + // initialize the image with the file + if (!image.Begin(bitmapFile)) + { + Serial.println("File format fail, not a supported bitmap"); + // don't do anything more: + return; + } + + animState = 0; + // we use the index 0 animation to time how often we rotate all the pixels + animations.StartAnimation(0, 30, LoopAnimUpdate); +} + +void loop() { + // this is all that is needed to keep it running + // and avoiding using delay() is always a good thing for + // any timing related routines + animations.UpdateAnimations(); + strip.Show(); +} \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBitmap/Strings.bmp b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBitmap/Strings.bmp new file mode 100644 index 0000000..0ee3be6 Binary files /dev/null and b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBitmap/Strings.bmp differ diff --git a/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBitmap/StringsW.bmp b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBitmap/StringsW.bmp new file mode 100644 index 0000000..8e45e13 Binary files /dev/null and b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBitmap/StringsW.bmp differ diff --git a/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferCylon/Cylon.pdn b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferCylon/Cylon.pdn new file mode 100644 index 0000000..e90048c Binary files /dev/null and b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferCylon/Cylon.pdn differ diff --git a/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferCylon/CylonGrb.h b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferCylon/CylonGrb.h new file mode 100644 index 0000000..852c209 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferCylon/CylonGrb.h @@ -0,0 +1,30 @@ +// To recreate the data below, use the Paint.Net plugin "Arduino Progmem NeoPixel FileType" +// to save as/export the included Cylon.pdn +// Paint.Net - http://www.getpaint.net/download.html#download +// Plugin - http://forums.getpaint.net/index.php?/topic/107921-arduino-neopixel-sketch-exporter/ +// This uses Flatten, GRB, Hexadecimal +// + +const uint16_t myImageWidth = 16; +const uint16_t myImageHeight = 20; +const uint8_t PROGMEM myImage[] = { // (16 x 20) GRB in Hexadecimal + 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x3f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferCylon/CylonGrbw.h b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferCylon/CylonGrbw.h new file mode 100644 index 0000000..9314f2f --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferCylon/CylonGrbw.h @@ -0,0 +1,30 @@ +// To recreate the data below, use the Paint.Net plugin "Arduino Progmem NeoPixel FileType" +// to save as/export the included Cylon.pdn +// Paint.Net - http://www.getpaint.net/download.html#download +// Plugin - http://forums.getpaint.net/index.php?/topic/107921-arduino-neopixel-sketch-exporter/ +// This uses Flatten, GRBW, Hexadecimal +// + +const uint16_t myImageWidth = 16; +const uint16_t myImageHeight = 20; +const uint8_t PROGMEM myImage[] = { // (16 x 20) GRBW in Hexadecimal + 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; diff --git a/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferCylon/NeoPixelBufferCylon.ino b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferCylon/NeoPixelBufferCylon.ino new file mode 100644 index 0000000..34b97f2 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferCylon/NeoPixelBufferCylon.ino @@ -0,0 +1,74 @@ +// NeoPixelBufferCylon +// This example will move a Cylon Red Eye back and forth across the +// the full collection of pixels on the strip. +// +// This will demonstrate the use of the NeoVerticalSpriteSheet +// + +#include +#include + +// The actual image is contained in the data structure in one of the Cylon*.h files +// You will need to use the one that has the same color feature as your NeoPixelBus +// There are two provided, but you can create your own easily enough using +// free versions of Paint.Net and the plugin +#include "CylonGrb.h" +typedef NeoGrbFeature MyPixelColorFeature; + +// #include "CylonGrbw.h" +// typedef NeoGrbwFeature MyPixelColorFeature; + +const uint16_t PixelCount = 16; // the sample images are meant for 16 pixels +const uint16_t PixelPin = 2; +const uint16_t AnimCount = 1; // we only need one + +NeoPixelBus strip(PixelCount, PixelPin); +// for esp8266 omit the pin +//NeoPixelBus strip(PixelCount); +NeoPixelAnimator animations(AnimCount); // NeoPixel animation management object + +// sprite sheet stored in progmem using the same pixel feature as the NeoPixelBus +NeoVerticalSpriteSheet> spriteSheet( + myImageWidth, // image width and sprite width since its vertical sprite sheet + myImageHeight, // image height + 1, // sprite is only one pixel high + myImage); + +uint16_t indexSprite; + +void LoopAnimUpdate(const AnimationParam& param) +{ + // wait for this animation to complete, + // we are using it as a timer of sorts + if (param.state == AnimationState_Completed) + { + // done, time to restart this position tracking animation/timer + animations.RestartAnimation(param.index); + + // draw the next frame in the sprite + spriteSheet.Blt(strip, 0, indexSprite); + indexSprite = (indexSprite + 1) % myImageHeight; // increment and wrap + } +} + +void setup() +{ + strip.Begin(); + strip.Show(); + + indexSprite = 0; + + // we use the index 0 animation to time how often we rotate all the pixels + animations.StartAnimation(0, 60, LoopAnimUpdate); +} + + +void loop() +{ + // this is all that is needed to keep it running + // and avoiding using delay() is always a good thing for + // any timing related routines + animations.UpdateAnimations(); + strip.Show(); +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferShader/NeoPixelBufferShader.ino b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferShader/NeoPixelBufferShader.ino new file mode 100644 index 0000000..c2c8e74 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelBufferShader/NeoPixelBufferShader.ino @@ -0,0 +1,167 @@ +// NeoPixelBufferShader +// This example will provide a shader class to the NeoPixelBuffer that will dim and brighten +// the pixels that are in the buffer (a device dependent bitmap) +// + +#include + +const uint16_t PixelCount = 64; // set this to the size of your strip +const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 + +// three element GRB pixels, change to your needs +NeoPixelBus strip(PixelCount, PixelPin); + +// the buffer object, +// defined to use memory with the same feature as the strip +// initialized with the same number of pixels as our strip +NeoBuffer> image(8,8,NULL); + +const RgbColor BrightRed(255, 0, 0); +const RgbColor BrightGreen(0, 255, 0); +const RgbColor BrightBlue(0, 0, 255); + +const RgbColor BrightYellow(255, 255, 0); +const RgbColor BrightCyan(0, 255, 255); +const RgbColor BrightPurple(255, 0, 255); + +const RgbColor DarkRed(32, 0, 0); +const RgbColor DarkGreen(0, 32, 0); +const RgbColor DarkBlue(0, 0, 32); + +const RgbColor DarkYellow(32, 32, 0); +const RgbColor DarkCyan(0, 32, 32); +const RgbColor DarkPurple(32, 0, 32); + +const RgbColor White(255); +const RgbColor Black(0); + +// define a custom shader object that provides brightness support +// based upon the NeoShaderBase +template class BrightnessShader : public NeoShaderBase +{ +public: + BrightnessShader(): + NeoShaderBase(), + _brightness(255) // default to full bright + {} + + // required for a shader object, it will be called for + // every pixel + void Apply(uint16_t index, uint8_t* pDest, uint8_t* pSrc) + { + // we don't care what the index is so we ignore it + // + // to apply our brightness shader, + // use the source color, modify, and apply to the destination + + // for every byte in the pixel, + // scale the source value by the brightness and + // store it in the destination byte + const uint8_t* pSrcEnd = pSrc + T_COLOR_FEATURE::PixelSize; + while (pSrc != pSrcEnd) + { + *pDest++ = (*pSrc++ * (uint16_t(_brightness) + 1)) >> 8; + } + } + + // provide an accessor to set brightness + void setBrightness(uint8_t brightness) + { + _brightness = brightness; + Dirty(); // must call dirty when a property changes + } + + // provide an accessor to get brightness + uint8_t getBrightness() + { + return _brightness; + } + +private: + uint8_t _brightness; +}; + +// create an instance of our shader object with the same feature as our buffer +BrightnessShader shader; + +// some dimming tracking variables and settings +int8_t delta; + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + Serial.println(); + Serial.println("Initializing..."); + Serial.flush(); + + // this resets all the neopixels to an off state + strip.Begin(); + strip.Show(); + + // dibs do not default to any color, + // so clear it to black if you aren't going to draw + // into every pixel + image.ClearTo(Black); + + // draw a pattern into the image + uint8_t x = 0; + uint8_t y = 0; + image.SetPixelColor(x++, y, DarkRed); + image.SetPixelColor(x++, y, DarkYellow); + image.SetPixelColor(x++, y, DarkGreen); + image.SetPixelColor(x++, y, DarkCyan); + image.SetPixelColor(x++, y, DarkBlue); + image.SetPixelColor(x++, y, DarkPurple); + + x = 0; + y = 1; + image.SetPixelColor(x++, y, BrightRed); + image.SetPixelColor(x++, y, BrightYellow); + image.SetPixelColor(x++, y, BrightGreen); + image.SetPixelColor(x++, y, BrightCyan); + image.SetPixelColor(x++, y, BrightBlue); + image.SetPixelColor(x++, y, BrightPurple); + + Serial.println(); + Serial.println("Running..."); + + delta = -1; // start by dimming downward +} + +void loop() +{ + // we increment by delta every 30ms + delay(30); + + // update the brightness in shader + // + uint8_t brightness = shader.getBrightness(); + // check if we flip directions + if (brightness == 0) + { + delta = 1; // increment + } + else if (brightness == 255) + { + delta = -1; // decrement + } + // modify and apply + brightness += delta; + shader.setBrightness(brightness); + + Serial.println(brightness); + + + // render the image using the shader and then call Show() + // these two should be called together in order + // + + // need to provide the type of color feature for the strip and + // the type of our custom shader + image.Render>(strip, shader); + strip.Show(); + +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelDibTest/NeoPixelDibTest.ino b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelDibTest/NeoPixelDibTest.ino new file mode 100644 index 0000000..1a13c13 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/bitmaps/NeoPixelDibTest/NeoPixelDibTest.ino @@ -0,0 +1,158 @@ +// NeoPixelDibTest +// This example will provide a shader class to the NeoPixelDib that will dim and brighten +// the pixels that are in the Dib (Device Independant Bitmap) +// + +#include + +const uint16_t PixelCount = 64; // set this to the size of your strip +const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 + +// three element GRB pixels, change to your needs +NeoPixelBus strip(PixelCount, PixelPin); + +// the DIB object, using RgbColor and initialized with the same number of pixels as our strip +NeoDib image(PixelCount); + +const RgbColor BrightRed(255, 0, 0); +const RgbColor BrightGreen(0, 255, 0); +const RgbColor BrightBlue(0, 0, 255); + +const RgbColor BrightYellow(255, 255, 0); +const RgbColor BrightCyan(0, 255, 255); +const RgbColor BrightPurple(255, 0, 255); + +const RgbColor DarkRed(32, 0, 0); +const RgbColor DarkGreen(0, 32, 0); +const RgbColor DarkBlue(0, 0, 32); + +const RgbColor DarkYellow(32, 32, 0); +const RgbColor DarkCyan(0, 32, 32); +const RgbColor DarkPurple(32, 0, 32); + +const RgbColor White(255); +const RgbColor Black(0); + +// define a custom shader object that provides brightness support +// based upon the NeoShaderBase +class BrightnessShader : public NeoShaderBase +{ +public: + BrightnessShader(): + NeoShaderBase(), + _brightness(255) // default to full bright + {} + + // required for a shader object, it will be called for + // every pixel + RgbColor Apply(uint16_t index, RgbColor original) + { + // we don't care what the index is so we ignore it + // + // to apply our brightness shader, modify the original color and return the color we want + // blend from black (_brightness == 0.0) to the original color (_brightness == 1.0) + + return RgbColor::LinearBlend(Black, original, (float)_brightness / 255.0f); + } + + // provide an accessor to set brightness + void setBrightness(uint8_t brightness) + { + _brightness = brightness; + Dirty(); // must call dirty when a property changes + } + + // provide an accessor to get brightness + uint8_t getBrightness() + { + return _brightness; + } + +private: + uint8_t _brightness; +}; + +// create an instance of our shader object +BrightnessShader shader; + +// some dimming tracking variables and settings +int8_t delta; + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + Serial.println(); + Serial.println("Initializing..."); + Serial.flush(); + + // this resets all the neopixels to an off state + strip.Begin(); + strip.Show(); + + // dibs do not default to any color, + // so clear it to black if you aren't going to draw + // into every pixel + image.ClearTo(Black); + + // draw a pattern into the image + uint8_t index = 0; + image.SetPixelColor(index++, DarkRed); + image.SetPixelColor(index++, DarkYellow); + image.SetPixelColor(index++, DarkGreen); + image.SetPixelColor(index++, DarkCyan); + image.SetPixelColor(index++, DarkBlue); + image.SetPixelColor(index++, DarkPurple); + + image.SetPixelColor(index++, Black); + image.SetPixelColor(index++, Black); + + image.SetPixelColor(index++, BrightRed); + image.SetPixelColor(index++, BrightYellow); + image.SetPixelColor(index++, BrightGreen); + image.SetPixelColor(index++, BrightCyan); + image.SetPixelColor(index++, BrightBlue); + image.SetPixelColor(index++, BrightPurple); + + Serial.println(); + Serial.println("Running..."); + + delta = -1; // start by dimming downward +} + +void loop() +{ + // we increment by delta every 30ms + delay(30); + + // update the brightness in shader + // + uint8_t brightness = shader.getBrightness(); + // check if we flip directions + if (brightness == 0) + { + delta = 1; // increment + } + else if (brightness == 255) + { + delta = -1; // decrement + } + // modify and apply + brightness += delta; + shader.setBrightness(brightness); + + Serial.println(brightness); + + + // render the image using the shader and then call Show() + // these two should be called together in order + // + + // need to provide the type of color feature for the strip and + // the type of our custom shader + image.Render(strip, shader); + strip.Show(); + +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/sevensegment/NeoSegmentBus/NeoSegmentBus.ino b/lib/NeoPixelBus_by_Makuna/examples/sevensegment/NeoSegmentBus/NeoSegmentBus.ino new file mode 100644 index 0000000..7ee1beb --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/sevensegment/NeoSegmentBus/NeoSegmentBus.ino @@ -0,0 +1,36 @@ +// NeoSegmentBus +// This example will demonstrate using the NeoSegmentBus which provides support for a +// seven segment LED digit driven by three WS2811; connected in series with other digits +// +// See https://shop.idlehandsdev.com/products/addressable-7-segment-display for a hardware example +// +// This example will print the string "3.14" and then rotate it through the available digits +// + +#include + +const uint16_t DigitCount = 4; // Max Digits, not segments, not pixels +const uint8_t BusPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 + +#define brightness 128 + +NeoPixelSegmentBus strip(DigitCount, BusPin); + +void setup() +{ + strip.Begin(); + strip.Show(); // clears all digits by default + + delay(500); + strip.SetString(0, "3.14", brightness); + strip.Show(); +} + +void loop() +{ + delay(2000); + + strip.RotateLeft(1); + strip.Show(); +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/sevensegment/NeoSegmentFade/NeoSegmentFade.ino b/lib/NeoPixelBus_by_Makuna/examples/sevensegment/NeoSegmentFade/NeoSegmentFade.ino new file mode 100644 index 0000000..98d9e59 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/sevensegment/NeoSegmentFade/NeoSegmentFade.ino @@ -0,0 +1,144 @@ +// NeoSegmentBus +// This example will demonstrate using the NeoSegmentBus which provides support for a +// seven segment LED digit driven by three WS2811; connected in series with other digits +// +// See https://shop.idlehandsdev.com/products/addressable-7-segment-display for a hardware example +// +// This example will print current seconds since start of the Arduino +// with a digit animating a circling path for each second +// + +#include +#include + +const uint16_t DigitCount = 5; // Max Digits, not segments, not pixels +const uint8_t BusPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 +const uint16_t CycleDigit = 0; +const uint16_t SecondsDigit = 1; + +#define brightness 128 + +NeoPixelSegmentBus strip(DigitCount, BusPin); + +enum Animation +{ + Animation_Cycle, // animation for the cycle indicator + Animation_Fade, // animation for fade of seconds + Animation_COUNT +}; + +NeoPixelAnimator animations(Animation_COUNT); + +void CycleAnimation(const AnimationParam& param) +{ + // calculate which segment should be on using the animation progress + uint8_t bitfield = 1 << (uint8_t)(param.progress * LedSegment_F); + // instant a digit with that segment on + SevenSegDigit digit(bitfield, brightness); + // apply it to the strip + strip.SetPixelColor(CycleDigit, digit); +} + +// for the animation of fading the new number in, we use +// two digit DIBs (Device Independant Bitmaps) of SevenSegDigit to blend with; +// each sized one less than the strip due to the first is a used for the cycle +// animation. +typedef NeoDib SevenSegDib; + +SevenSegDib StartingDigits(DigitCount - 1); +SevenSegDib EndingDigits(DigitCount - 1); + +// shader class that will do the "string" blending +// +class DigitBlendShader +{ +public: + // this shader always renders and doesn't track a dirty state + bool IsDirty() const + { + return true; + } + + void ResetDirty() + { + } + + SevenSegDigit Apply(uint16_t indexDigit, SevenSegDigit digit) + { + // since we call EndingDigits.Render below, the digit argument is + // from the EndingDigits so no need to call GetPixelColor to get it + // create a digit that is a blend between the last seconds + // value and the next seconds value using the BlendAmount + SevenSegDigit blendDigit = SevenSegDigit::LinearBlend( + StartingDigits.GetPixelColor(indexDigit), + digit, + BlendAmount); + + return blendDigit; + } + + float BlendAmount; +}; + +// the instance of our shader class +DigitBlendShader blendShader; + +void FadeAnimation(const AnimationParam& param) +{ + // set the shader property BlendAmount to the animation progress + blendShader.BlendAmount = param.progress; + // apply it to the strip at the SecondsDigit location + EndingDigits.Render(strip, + blendShader, + SecondsDigit); +} + +uint32_t lastSeconds; + +void setup() +{ + lastSeconds = millis() / 1000; + + strip.Begin(); + strip.Show(); + + // init animation Dibs as cleared + StartingDigits.ClearTo(0); + EndingDigits.ClearTo(0); +} + +void loop() +{ + uint32_t seconds = millis() / 1000; + + // when the seconds change, start animations for the update + // + if (seconds != lastSeconds) + { + // copy last animation ending digits as starting digits + StartingDigits = EndingDigits; + + // format and display new value in ending digits dib + String display(seconds); + SevenSegDigit::SetString(EndingDigits, + 0, + display.c_str(), + brightness); + + // start the seconds fade animation + animations.StartAnimation(Animation_Fade, 1000, FadeAnimation); + + // start the cycle animation for the next second + animations.StartAnimation(Animation_Cycle, 1000, CycleAnimation); + + lastSeconds = seconds; + } + + if (animations.IsAnimating()) + { + // the normal loop just needs these two to run the active animations + animations.UpdateAnimations(); + strip.Show(); + } +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelMosaicDump/NeoPixelMosaicDump.ino b/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelMosaicDump/NeoPixelMosaicDump.ino new file mode 100644 index 0000000..6b70b6f --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelMosaicDump/NeoPixelMosaicDump.ino @@ -0,0 +1,98 @@ +//---------------------------------------------------------------------- +// NeoPixelMosaicDump +// This will dump to the serial output a grid map of the defined mosaic +// The output is displayed as row column labeled grid with the NeoPixelBus +// index of the pixel at the intersection of the row and column. +// +// To help with physical layout, there maybe included a symbol following the index +// < means the index is the input index for the panel, the first on the panel +// > means the index is the output index for the panel, the last on the panel +// +// This is useful in visualising the mosaic layout of your panels to +// confirm you have them correctly wired together for this mosaic pattern +// +// It does not require that you have the actual panel connected +//---------------------------------------------------------------------- + +#include +#include + +// uncomment one of these that matches your panel pixel layouts +// rotation is ignored for mosaic as it applies a rotation for you +// that is specific to the location of the panel within the mosaic +// to reduce connection lengths + +typedef ColumnMajorAlternatingLayout MyPanelLayout; +// typedef ColumnMajorLayout MyPanelLayout; +// typedef RowMajorAlternatingLayout MyPanelLayout; +// typedef RowMajorLayout MyPanelLayout; + +// make sure to set these panel and tile layout to match your sizes +const uint8_t PanelWidth = 8; // a 8 pixel x 8 pixel matrix of leds on the panel +const uint8_t PanelHeight = 8; +const uint8_t TileWidth = 4; // laid out in 4 panels x 2 panels mosaic +const uint8_t TileHeight = 2; + +NeoMosaic mosaic( + PanelWidth, + PanelHeight, + TileWidth, + TileHeight); + +void DumpMosaic() +{ + Serial.println(); + + Serial.print("\t\t"); + for (int x = 0; x < mosaic.getWidth(); x++) + { + Serial.print(x); + Serial.print("\t"); + } + Serial.println(); + + Serial.print("\t---"); + for (int x = 0; x < mosaic.getWidth(); x++) + { + Serial.print("--------"); + } + Serial.println(); + + for (int y = 0; y < mosaic.getHeight(); y++) + { + Serial.print(" "); + Serial.print(y); + Serial.print("\t|\t"); + + for (int x = 0; x < mosaic.getWidth(); x++) + { + NeoTopologyHint hint = mosaic.TopologyHint(x, y); + + Serial.print(mosaic.Map(x, y)); + if (hint == NeoTopologyHint_FirstOnPanel) + { + Serial.print("<"); + } + else if (hint == NeoTopologyHint_LastOnPanel) + { + Serial.print(">"); + } + Serial.print("\t"); + } + Serial.println(); + } +} + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + DumpMosaic(); +} + +void loop() +{ + +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelMosaicTest/NeoPixelMosaicTest.ino b/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelMosaicTest/NeoPixelMosaicTest.ino new file mode 100644 index 0000000..2f6500c --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelMosaicTest/NeoPixelMosaicTest.ino @@ -0,0 +1,97 @@ +//---------------------------------------------------------------------- +// NeoPixelTopologyTest +// This will display specific colors in specific locations on the led panels +// +// This is useful in confirming the layout of your panels +// +// It does require that you have the actual panels connected +//---------------------------------------------------------------------- + +#include +#include + +// uncomment one of these that matches your panel pixel layouts +// rotation is ignored for mosaic as it applies a rotation for you +// that is specific to the location of the panel within the mosaic +// to reduce connection lengths + +typedef ColumnMajorAlternatingLayout MyPanelLayout; +// typedef ColumnMajorLayout MyPanelLayout; +// typedef RowMajorAlternatingLayout MyPanelLayout; +// typedef RowMajorLayout MyPanelLayout; + +// make sure to set these panel values to the sizes of yours +const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds +const uint8_t PanelHeight = 8; +const uint8_t TileWidth = 4; // laid out in 4 panels x 2 panels mosaic +const uint8_t TileHeight = 2; + +const uint16_t PixelCount = PanelWidth * PanelHeight * TileWidth * TileHeight; +const uint8_t PixelPin = 2; + +NeoMosaic mosaic( + PanelWidth, + PanelHeight, + TileWidth, + TileHeight); + +NeoPixelBus strip(PixelCount, PixelPin); +// for esp8266 omit the pin +//NeoPixelBus strip(PixelCount); + +RgbColor red(128, 0, 0); +RgbColor green(0, 128, 0); +RgbColor blue(0, 0, 128); +RgbColor white(128); +// if using NeoRgbwFeature above, use this white instead to use +// the correct white element of the LED +//RgbwColor white(128); +RgbColor black(0); + +const uint16_t left = 0; +const uint16_t right = PanelWidth - 1; +const uint16_t top = 0; +const uint16_t bottom = PanelHeight - 1; + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + Serial.println(); + Serial.println("Initializing..."); + + strip.Begin(); + strip.Show(); + + Serial.println(); + Serial.println("Running..."); +} + +void loop() +{ + delay(2500); + + Serial.println(); + Serial.println("If your panel is correctly defined, you should see ..."); + Serial.println("Upper left is white."); + Serial.println("Upper right is Red."); + Serial.println("Lower right is Green"); + Serial.println("Lower Left is Blue"); + + // use the topo to map the 2d cordinate to the pixel + // and use that to SetPixelColor + strip.SetPixelColor(mosaic.Map(left, top), white); + strip.SetPixelColor(mosaic.Map(right, top), red); + strip.SetPixelColor(mosaic.Map(right, bottom), green); + strip.SetPixelColor(mosaic.Map(left, bottom), blue); + strip.Show(); + + delay(5000); + + Serial.println(); + Serial.println("Cleared to black ..."); + strip.ClearTo(black); + strip.Show(); +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelRingTopologyTest/NeoPixelRingTopologyTest.ino b/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelRingTopologyTest/NeoPixelRingTopologyTest.ino new file mode 100644 index 0000000..64a1bcd --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelRingTopologyTest/NeoPixelRingTopologyTest.ino @@ -0,0 +1,100 @@ +//---------------------------------------------------------------------- +// NeoPixelRingTopologyTest +// This will display specific colors in specific locations on the led rings +// +// This is useful in confirming the layout of your rings +// +// It does require that you have the actual series of rings connected +//---------------------------------------------------------------------- + +#include + +const uint8_t PixelCount = 119; +const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 + +// define the layout of your series of rings +// +// This example is using all of Adafruits rings and a Jewel in the center. +// The center is the input and all the rings are connected in series going outward +// +// Rings: +// 0 - 1 (virtual ring, the center of the jewel) +// 1 - 6 (virtual ring, the outer ring of the jewel) +// 2 - 12 count ring +// 3 - 16 count ring +// 4 - 24 count ring +// 5 - 60 count ring comprised of four arc segments +// +// The values below in Rings[] are the index of the first pixel in each ring. +// An extra value is appended for a virtual ring start that also +// represents the total count of pixels in the complete series and this extra +// value is required. +// +class MyRingsLayout +{ +protected: + const uint16_t Rings[7] = {0, 1, 7, 19, 35, 59, PixelCount}; +}; + +// use the MyRingsLayout to declare the topo object +// +NeoRingTopology topo; + +// declare our strip +// +NeoPixelBus strip(PixelCount, PixelPin); + +// define some handy colors +// +RgbColor red(128, 0, 0); +RgbColor green(0, 128, 0); +RgbColor blue(0, 0, 128); +RgbColor black(0); + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + Serial.println(); + Serial.println("Initializing..."); + + strip.Begin(); + strip.Show(); + + Serial.println(); + Serial.println("Running..."); +} + +void loop() +{ + delay(2500); + + Serial.println(); + Serial.println("If your panel is correctly defined, you should see ..."); + Serial.println("First pixel in each ring is Red."); + Serial.println("Middle pixel in each ring is Green."); + Serial.println("Last Pixel in each ring is Blue."); + + + // use the topo to map the 2d polar cordinate to the pixel + // and use that to SetPixelColor + for (uint16_t ring = 0; ring < topo.getCountOfRings(); ring++) + { + // first pixel in each ring is red + strip.SetPixelColor(topo.Map(ring, 0), red); + // last pixel in each ring is blue + strip.SetPixelColor(topo.Map(ring, topo.getPixelCountAtRing(ring) - 1), blue); + // middle pixel in each ring is green + strip.SetPixelColor(topo.Map(ring, topo.getPixelCountAtRing(ring) / 2), green); + } + strip.Show(); + + delay(5000); + + Serial.println(); + Serial.println("Cleared to black ..."); + strip.ClearTo(black); + strip.Show(); +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelTilesDump/NeoPixelTilesDump.ino b/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelTilesDump/NeoPixelTilesDump.ino new file mode 100644 index 0000000..2849c56 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelTilesDump/NeoPixelTilesDump.ino @@ -0,0 +1,102 @@ +//---------------------------------------------------------------------- +// NeoPixelTileDump +// This will dump to the serial output a grid map of the defined tiles +// The output is displayed as row column labeled grid with the NeoPixelBus +// index of the pixel at the intersection of the row and column +// +// To help with physical layout, there maybe included a symbol following the index +// < means the index is the input index for the panel, the first on the panel +// > means the index is the output index for the panel, the last on the panel +// +// This is useful in visualising the tile layout of your panels to +// confirm you have them correctly wired together for the defined pattern +// +// It does not require that you have the actual panel connected +//---------------------------------------------------------------------- + +#include +#include + +// uncomment one of these that matches your panel pixel layouts and +// how you want them rotated. Not all the rotations are listed here +// but you can modifiy the name to include the rotation of 90,180, or 270. + +typedef ColumnMajorAlternatingLayout MyPanelLayout; +// typedef ColumnMajorLayout MyPanelLayout; +// typedef RowMajorAlternatingLayout MyPanelLayout; +// typedef RowMajorLayout MyPanelLayout; +// typedef RowMajor90Layout MyPanelLayout; // note rotation 90 was used + +// change this to be one of the layouts which will define the layout +// of the panels themselves +typedef ColumnMajorLayout MyTilesLayout; + +// make sure to set these panel and tile layout to match your sizes +const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds +const uint8_t PanelHeight = 8; +const uint8_t TileWidth = 4; // laid out in 4 panels x 2 panels mosaic +const uint8_t TileHeight = 2; + +NeoTiles tiles( + PanelWidth, + PanelHeight, + TileWidth, + TileHeight); + +void DumpTopo() +{ + Serial.println(); + + Serial.print("\t\t"); + for (int x = 0; x < tiles.getWidth(); x++) + { + Serial.print(x); + Serial.print("\t"); + } + Serial.println(); + + Serial.print("\t---"); + for (int x = 0; x < tiles.getWidth(); x++) + { + Serial.print("--------"); + } + Serial.println(); + + for (int y = 0; y < tiles.getHeight(); y++) + { + Serial.print(" "); + Serial.print(y); + Serial.print("\t|\t"); + + for (int x = 0; x < tiles.getWidth(); x++) + { + NeoTopologyHint hint = tiles.TopologyHint(x, y); + + Serial.print(tiles.Map(x, y)); + if (hint == NeoTopologyHint_FirstOnPanel) + { + Serial.print("<"); + } + else if (hint == NeoTopologyHint_LastOnPanel) + { + Serial.print(">"); + } + Serial.print("\t"); + } + Serial.println(); + } +} + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + DumpTopo(); +} + +void loop() +{ + +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelTilesTest/NeoPixelTilesTest.ino b/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelTilesTest/NeoPixelTilesTest.ino new file mode 100644 index 0000000..1dfc645 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelTilesTest/NeoPixelTilesTest.ino @@ -0,0 +1,103 @@ +//---------------------------------------------------------------------- +// NeoPixelTilesTest +// This will display specific colors in specific locations on the led panels +// +// This is useful in confirming the layout of your panels +// +// It does require that you have the actual panels connected +//---------------------------------------------------------------------- + +#include +#include + +// uncomment one of these that matches your panel pixel layouts and +// how you want them rotated. Not all the rotations are listed here +// but you can modifiy the name to include the rotation of 90,180, or 270. + +typedef ColumnMajorAlternatingLayout MyPanelLayout; +// typedef ColumnMajorLayout MyPanelLayout; +// typedef RowMajorAlternatingLayout MyPanelLayout; +// typedef RowMajorLayout MyPanelLayout; +// typedef RowMajor90Layout MyPanelLayout; // note rotation 90 was used + +// change this to be one of the layouts which will define the layout +// of the panels themselves +typedef ColumnMajorLayout MyTilesLayout; + +// make sure to set these panel values to the sizes of yours +const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds +const uint8_t PanelHeight = 8; +const uint8_t TileWidth = 4; // laid out in 4 panels x 2 panels mosaic +const uint8_t TileHeight = 2; + +const uint16_t PixelCount = PanelWidth * PanelHeight * TileWidth * TileHeight; +const uint8_t PixelPin = 2; + +NeoTiles tiles( + PanelWidth, + PanelHeight, + TileWidth, + TileHeight); + +NeoPixelBus strip(PixelCount, PixelPin); +//NeoPixelBus strip(PixelCount, PixelPin); +//NeoPixelBus strip(PixelCount, PixelPin); +// for esp8266 omit the pin +//NeoPixelBus strip(PixelCount); + +RgbColor red(128, 0, 0); +RgbColor green(0, 128, 0); +RgbColor blue(0, 0, 128); +RgbColor white(128); +// if using NeoRgbwFeature above, use this white instead to use +// the correct white element of the LED +//RgbwColor white(128); +RgbColor black(0); + +const uint16_t left = 0; +const uint16_t right = PanelWidth - 1; +const uint16_t top = 0; +const uint16_t bottom = PanelHeight - 1; + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + Serial.println(); + Serial.println("Initializing..."); + + strip.Begin(); + strip.Show(); + + Serial.println(); + Serial.println("Running..."); +} + +void loop() +{ + delay(2500); + + Serial.println(); + Serial.println("If your panel is correctly defined, you should see ..."); + Serial.println("Upper left is white."); + Serial.println("Upper right is Red."); + Serial.println("Lower right is Green"); + Serial.println("Lower Left is Blue"); + + // use the topo to map the 2d cordinate to the pixel + // and use that to SetPixelColor + strip.SetPixelColor(tiles.Map(left, top), white); + strip.SetPixelColor(tiles.Map(right, top), red); + strip.SetPixelColor(tiles.Map(right, bottom), green); + strip.SetPixelColor(tiles.Map(left, bottom), blue); + strip.Show(); + + delay(5000); + + Serial.println(); + Serial.println("Cleared to black ..."); + strip.ClearTo(black); + strip.Show(); +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelTopologyDump/NeoPixelTopologyDump.ino b/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelTopologyDump/NeoPixelTopologyDump.ino new file mode 100644 index 0000000..aa78a25 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelTopologyDump/NeoPixelTopologyDump.ino @@ -0,0 +1,78 @@ +//---------------------------------------------------------------------- +// NeoPixelTopologyDump +// This will dump to the serial output a grid map of the defined topology +// The output is displayed as row column labeled grid with the NeoPixelBus +// index of the pixel at the intersection of the row and column +// +// This is useful in visualising the layout of your panel so you can +// confirm you have the correct pattern +// +// It does not require that you have the actual panel connected +//---------------------------------------------------------------------- + +#include +#include + +// uncomment one of these that matches your panel pixel layouts and +// how you want them rotated. Not all the rotations are listed here +// but you can modifiy the name to include the rotation of 90,180, or 270. + +typedef ColumnMajorAlternatingLayout MyPanelLayout; +// typedef ColumnMajorLayout MyPanelLayout; +// typedef RowMajorAlternatingLayout MyPanelLayout; +// typedef RowMajorLayout MyPanelLayout; +// typedef RowMajor90Layout MyPanelLayout; // note rotation 90 was used + +// make sure to set these panel values to the sizes of yours +const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds +const uint8_t PanelHeight = 8; + +NeoTopology topo(PanelWidth, PanelHeight); + +void DumpTopo() +{ + Serial.println(); + + Serial.print("\t\t"); + for (int x = 0; x < topo.getWidth(); x++) + { + Serial.print(x); + Serial.print("\t"); + } + Serial.println(); + + Serial.print("\t--"); + for (int x = 0; x < topo.getWidth(); x++) + { + Serial.print("--------"); + } + Serial.println(); + + for (int y = 0; y < topo.getHeight(); y++) + { + Serial.print(" "); + Serial.print(y); + Serial.print("\t|\t"); + + for (int x = 0; x < topo.getWidth(); x++) + { + Serial.print(topo.Map(x, y)); + Serial.print("\t"); + } + Serial.println(); + } +} + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + DumpTopo(); +} + +void loop() +{ + +} + diff --git a/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelTopologyTest/NeoPixelTopologyTest.ino b/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelTopologyTest/NeoPixelTopologyTest.ino new file mode 100644 index 0000000..2071abb --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/examples/topologies/NeoPixelTopologyTest/NeoPixelTopologyTest.ino @@ -0,0 +1,92 @@ +//---------------------------------------------------------------------- +// NeoPixelTopologyTest +// This will display specific colors in specific locations on the led panel +// +// This is useful in confirming the layout of your panel +// +// It does require that you have the actual panel connected +//---------------------------------------------------------------------- + +#include +#include + +// uncomment one of these that matches your panel pixel layouts and +// how you want them rotated. Not all the rotations are listed here +// but you can modifiy the name to include the rotation of 90,180, or 270. + +typedef ColumnMajorAlternatingLayout MyPanelLayout; +// typedef ColumnMajorLayout MyPanelLayout; +// typedef RowMajorAlternatingLayout MyPanelLayout; +// typedef RowMajorLayout MyPanelLayout; +// typedef RowMajor90Layout MyPanelLayout; // note rotation 90 was used + +// make sure to set these panel values to the sizes of yours +const uint8_t PanelWidth = 8; // 8 pixel x 8 pixel matrix of leds +const uint8_t PanelHeight = 8; +const uint16_t PixelCount = PanelWidth * PanelHeight; +const uint8_t PixelPin = 2; // make sure to set this to the correct pin, ignored for Esp8266 + +NeoTopology topo(PanelWidth, PanelHeight); + +NeoPixelBus strip(PixelCount, PixelPin); +//NeoPixelBus strip(PixelCount, PixelPin); +//NeoPixelBus strip(PixelCount, PixelPin); +// for esp8266 omit the pin +//NeoPixelBus strip(PixelCount); + +RgbColor red(128, 0, 0); +RgbColor green(0, 128, 0); +RgbColor blue(0, 0, 128); +RgbColor white(128); +// if using NeoRgbwFeature above, use this white instead to use +// the correct white element of the LED +//RgbwColor white(128); +RgbColor black(0); + +const uint16_t left = 0; +const uint16_t right = PanelWidth - 1; +const uint16_t top = 0; +const uint16_t bottom = PanelHeight - 1; + +void setup() +{ + Serial.begin(115200); + while (!Serial); // wait for serial attach + + Serial.println(); + Serial.println("Initializing..."); + + strip.Begin(); + strip.Show(); + + Serial.println(); + Serial.println("Running..."); +} + +void loop() +{ + delay(2500); + + Serial.println(); + Serial.println("If your panel is correctly defined, you should see ..."); + Serial.println("Upper left is white."); + Serial.println("Upper right is Red."); + Serial.println("Lower right is Green"); + Serial.println("Lower Left is Blue"); + + // use the topo to map the 2d cordinate to the pixel + // and use that to SetPixelColor + strip.SetPixelColor(topo.Map(left, top), white); + strip.SetPixelColor(topo.Map(right, top), red); + strip.SetPixelColor(topo.Map(right, bottom), green); + strip.SetPixelColor(topo.Map(left, bottom), blue); + strip.Show(); + + delay(5000); + + Serial.println(); + Serial.println("Cleared to black ..."); + strip.ClearTo(black); + strip.Show(); +} + diff --git a/lib/NeoPixelBus_by_Makuna/extras/curves/circular.png b/lib/NeoPixelBus_by_Makuna/extras/curves/circular.png new file mode 100644 index 0000000..e4204db Binary files /dev/null and b/lib/NeoPixelBus_by_Makuna/extras/curves/circular.png differ diff --git a/lib/NeoPixelBus_by_Makuna/extras/curves/cubic.png b/lib/NeoPixelBus_by_Makuna/extras/curves/cubic.png new file mode 100644 index 0000000..a2d7c14 Binary files /dev/null and b/lib/NeoPixelBus_by_Makuna/extras/curves/cubic.png differ diff --git a/lib/NeoPixelBus_by_Makuna/extras/curves/different.png b/lib/NeoPixelBus_by_Makuna/extras/curves/different.png new file mode 100644 index 0000000..ae85ce2 Binary files /dev/null and b/lib/NeoPixelBus_by_Makuna/extras/curves/different.png differ diff --git a/lib/NeoPixelBus_by_Makuna/extras/curves/exponential.png b/lib/NeoPixelBus_by_Makuna/extras/curves/exponential.png new file mode 100644 index 0000000..2503171 Binary files /dev/null and b/lib/NeoPixelBus_by_Makuna/extras/curves/exponential.png differ diff --git a/lib/NeoPixelBus_by_Makuna/extras/curves/gamma.png b/lib/NeoPixelBus_by_Makuna/extras/curves/gamma.png new file mode 100644 index 0000000..33a84d6 Binary files /dev/null and b/lib/NeoPixelBus_by_Makuna/extras/curves/gamma.png differ diff --git a/lib/NeoPixelBus_by_Makuna/extras/curves/pronounced.png b/lib/NeoPixelBus_by_Makuna/extras/curves/pronounced.png new file mode 100644 index 0000000..0b78330 Binary files /dev/null and b/lib/NeoPixelBus_by_Makuna/extras/curves/pronounced.png differ diff --git a/lib/NeoPixelBus_by_Makuna/extras/curves/quadratic.png b/lib/NeoPixelBus_by_Makuna/extras/curves/quadratic.png new file mode 100644 index 0000000..33ab17c Binary files /dev/null and b/lib/NeoPixelBus_by_Makuna/extras/curves/quadratic.png differ diff --git a/lib/NeoPixelBus_by_Makuna/extras/curves/quintic.png b/lib/NeoPixelBus_by_Makuna/extras/curves/quintic.png new file mode 100644 index 0000000..30dab93 Binary files /dev/null and b/lib/NeoPixelBus_by_Makuna/extras/curves/quintic.png differ diff --git a/lib/NeoPixelBus_by_Makuna/extras/curves/sinusoidal.png b/lib/NeoPixelBus_by_Makuna/extras/curves/sinusoidal.png new file mode 100644 index 0000000..0b75338 Binary files /dev/null and b/lib/NeoPixelBus_by_Makuna/extras/curves/sinusoidal.png differ diff --git a/lib/NeoPixelBus_by_Makuna/keywords.txt b/lib/NeoPixelBus_by_Makuna/keywords.txt new file mode 100644 index 0000000..ca68e07 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/keywords.txt @@ -0,0 +1,539 @@ +####################################### +# Syntax Coloring Map NeoPixelBus +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +NeoPixelBus KEYWORD1 +NeoPixelSegmentBus KEYWORD1 +RgbwColor KEYWORD1 +RgbColor KEYWORD1 +HslColor KEYWORD1 +HsbColor KEYWORD1 +HtmlColor KEYWORD1 +NeoNoSettings KEYWORD1 +NeoTm1814Settings KEYWORD1 +NeoGrbFeature KEYWORD1 +NeoGrbwFeature KEYWORD1 +NeoRgbwFeature KEYWORD1 +NeoRgbFeature KEYWORD1 +NeoBrgFeature KEYWORD1 +NeoRbgFeature KEYWORD1 +NeoWrgbTm1814Feature KEYWORD1 +DotStarBgrFeature KEYWORD1 +DotStarLbgrFeature KEYWORD1 +Lpd8806GrbFeature KEYWORD1 +P9813BgrFeature KEYWORD1 +SevenSegmentFeature KEYWORD1 +Neo800KbpsMethod KEYWORD1 +Neo400KbpsMethod KEYWORD1 +NeoWs2813Method KEYWORD1 +NeoWs2812xMethod KEYWORD1 +NeoWs2812Method KEYWORD1 +NeoWs2811Method KEYWORD1 +NeoSk6812Method KEYWORD1 +NeoTm1814Method KEYWORD1 +NeoLc8812Method KEYWORD1 +NeoApa106Method KEYWORD1 +Neo800KbpsInvertedMethod KEYWORD1 +Neo400KbpsInvertedMethod KEYWORD1 +NeoWs2813InvertedMethod KEYWORD1 +NeoWs2812xInvertedMethod KEYWORD1 +NeoWs2812InvertedMethod KEYWORD1 +NeoWs2811InvertedMethod KEYWORD1 +NeoSk6812InvertedMethod KEYWORD1 +NeoTm1814InvertedMethod KEYWORD1 +NeoLc8812InvertedMethod KEYWORD1 +NeoApa106InvertedMethod KEYWORD1 +NeoEsp8266DmaWs2812xMethod KEYWORD1 +NeoEsp8266DmaSk6812Method KEYWORD1 +NeoEsp8266DmaTm1814Method KEYWORD1 +NeoEsp8266DmaApa106Method KEYWORD1 +NeoEsp8266Dma800KbpsMethod KEYWORD1 +NeoEsp8266Dma400KbpsMethod KEYWORD1 +NeoEsp8266DmaInvertedWs2812xMethod KEYWORD1 +NeoEsp8266DmaInvertedSk6812Method KEYWORD1 +NeoEsp8266DmaInvertedTm1814Method KEYWORD1 +NeoEsp8266DmaInvertedApa106Method KEYWORD1 +NeoEsp8266DmaInverted800KbpsMethod KEYWORD1 +NeoEsp8266DmaInverted400KbpsMethod KEYWORD1 +NeoEsp8266Uart0Ws2813Method KEYWORD1 +NeoEsp8266Uart0Ws2812xMethod KEYWORD1 +NeoEsp8266Uart0Ws2812Method KEYWORD1 +NeoEsp8266Uart0Ws2811Method KEYWORD1 +NeoEsp8266Uart0Sk6812Method KEYWORD1 +NeoEsp8266Uart0Tm1814Method KEYWORD1 +NeoEsp8266Uart0Lc8812Method KEYWORD1 +NeoEsp8266Uart0Apa106Method KEYWORD1 +NeoEsp8266Uart0800KbpsMethod KEYWORD1 +NeoEsp8266Uart0400KbpsMethod KEYWORD1 +NeoEsp8266AsyncUart0Ws2813Method KEYWORD1 +NeoEsp8266AsyncUart0Ws2812xMethod KEYWORD1 +NeoEsp8266AsyncUart0Ws2812Method KEYWORD1 +NeoEsp8266AsyncUart0Ws2811Method KEYWORD1 +NeoEsp8266AsyncUart0Sk6812Method KEYWORD1 +NeoEsp8266AsyncUart0Tm1814Method KEYWORD1 +NeoEsp8266AsyncUart0Lc8812Method KEYWORD1 +NeoEsp8266AsyncUart0Apa106Method KEYWORD1 +NeoEsp8266AsyncUart0800KbpsMethod KEYWORD1 +NeoEsp8266AsyncUart0400KbpsMethod KEYWORD1 +NeoEsp8266Uart1Ws2813Method KEYWORD1 +NeoEsp8266Uart1Ws2812xMethod KEYWORD1 +NeoEsp8266Uart1Ws2812Method KEYWORD1 +NeoEsp8266Uart1Ws2811Method KEYWORD1 +NeoEsp8266Uart1Sk6812Method KEYWORD1 +NeoEsp8266Uart1Tm1814 KEYWORD1 +NeoEsp8266Uart1Lc8812Method KEYWORD1 +NeoEsp8266Uart1Apa106Method KEYWORD1 +NeoEsp8266Uart1800KbpsMethod KEYWORD1 +NeoEsp8266Uart1400KbpsMethod KEYWORD1 +NeoEsp8266AsyncUart1Ws2813Method KEYWORD1 +NeoEsp8266AsyncUart1Ws2812xMethod KEYWORD1 +NeoEsp8266AsyncUart1Ws2812Method KEYWORD1 +NeoEsp8266AsyncUart1Ws2811Method KEYWORD1 +NeoEsp8266AsyncUart1Sk6812Method KEYWORD1 +NeoEsp8266AsyncUart1Tm1814 KEYWORD1 +NeoEsp8266AsyncUart1Lc8812Method KEYWORD1 +NeoEsp8266AsyncUart1Apa106Method KEYWORD1 +NeoEsp8266AsyncUart1800KbpsMethod KEYWORD1 +NeoEsp8266AsyncUart1400KbpsMethod KEYWORD1 +NeoEsp8266Uart0Ws2813InvertedMethod KEYWORD1 +NeoEsp8266Uart0Ws2812xInvertedMethod KEYWORD1 +NeoEsp8266Uart0Ws2812InvertedMethod KEYWORD1 +NeoEsp8266Uart0Ws2811InvertedMethod KEYWORD1 +NeoEsp8266Uart0Sk6812InvertedMethod KEYWORD1 +NeoEsp8266Uart0Tm1814InvertedMethod KEYWORD1 +NeoEsp8266Uart0Lc8812InvertedMethod KEYWORD1 +NeoEsp8266Uart0Apa106InvertedMethod KEYWORD1 +NeoEsp8266Uart0800KbpsInvertedMethod KEYWORD1 +NeoEsp8266Uart0400KbpsInvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0Ws2813InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0Ws2812xInvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0Ws2812InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0Ws2811InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0Sk6812InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0Tm1814InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0Lc8812InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0Apa106InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0800KbpsInvertedMethod KEYWORD1 +NeoEsp8266AsyncUart0400KbpsInvertedMethod KEYWORD1 +NeoEsp8266Uart1Ws2813InvertedMethod KEYWORD1 +NeoEsp8266Uart1Ws2812xInvertedMethod KEYWORD1 +NeoEsp8266Uart1Ws2812InvertedMethod KEYWORD1 +NeoEsp8266Uart1Ws2811InvertedMethod KEYWORD1 +NeoEsp8266Uart1Sk6812InvertedMethod KEYWORD1 +NeoEsp8266Uart1Tm1814InvertedMethod KEYWORD1 +NeoEsp8266Uart1Lc8812InvertedMethod KEYWORD1 +NeoEsp8266Uart1Apa106InvertedMethod KEYWORD1 +NeoEsp8266Uart1800KbpsInvertedMethod KEYWORD1 +NeoEsp8266Uart1400KbpsInvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1Ws2813InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1Ws2812xInvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1Ws2812InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1Ws2811InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1Sk6812InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1Tm1814InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1Lc8812InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1Apa106InvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1800KbpsInvertedMethod KEYWORD1 +NeoEsp8266AsyncUart1400KbpsInvertedMethod KEYWORD1 +NeoEsp8266BitBangWs2813Method KEYWORD1 +NeoEsp8266BitBangWs2812xMethod KEYWORD1 +NeoEsp8266BitBangWs2812Method KEYWORD1 +NeoEsp8266BitBangWs2811Method KEYWORD1 +NeoEsp8266BitBangSk6812Method KEYWORD1 +NeoEsp8266BitBangTm1814Method KEYWORD1 +NeoEsp8266BitBangLc8812Method KEYWORD1 +NeoEsp8266BitBangApa106Method KEYWORD1 +NeoEsp8266BitBang800KbpsMethod KEYWORD1 +NeoEsp8266BitBang400KbpsMethod KEYWORD1 +NeoEsp8266BitBangWs2813InvertedMethod KEYWORD1 +NeoEsp8266BitBangWs2812xInvertedMethod KEYWORD1 +NeoEsp8266BitBangWs2812InvertedMethod KEYWORD1 +NeoEsp8266BitBangWs2811InvertedMethod KEYWORD1 +NeoEsp8266BitBangSk6812InvertedMethod KEYWORD1 +NeoEsp8266BitBangTm1814InvertedMethod KEYWORD1 +NeoEsp8266BitBangLc8812InvertedMethod KEYWORD1 +NeoEsp8266BitBangApa106InvertedMethod KEYWORD1 +NeoEsp8266BitBang800KbpsInvertedMethod KEYWORD1 +NeoEsp8266BitBang400KbpsInvertedMethod KEYWORD1 +NeoEsp32I2s0Ws2812xMethod KEYWORD1 +NeoEsp32I2s0Sk6812Method KEYWORD1 +NeoEsp32I2s0Tm1814Method KEYWORD1 +NeoEsp32I2s0800KbpsMethod KEYWORD1 +NeoEsp32I2s0400KbpsMethod KEYWORD1 +NeoEsp32I2s0Apa106Method KEYWORD1 +NeoEsp32I2s1Ws2812xMethod KEYWORD1 +NeoEsp32I2s1Sk6812Method KEYWORD1 +NeoEsp32I2s1Tm1814Method KEYWORD1 +NeoEsp32I2s1800KbpsMethod KEYWORD1 +NeoEsp32I2s1400KbpsMethod KEYWORD1 +NeoEsp32I2s1Apa106Method KEYWORD1 +NeoEsp32I2s0Ws2812xInvertedMethod KEYWORD1 +NeoEsp32I2s0Sk6812InvertedMethod KEYWORD1 +NeoEsp32I2s0Tm1814InvertedMethod KEYWORD1 +NeoEsp32I2s0800KbpsInvertedMethod KEYWORD1 +NeoEsp32I2s0400KbpsInvertedMethod KEYWORD1 +NeoEsp32I2s0Apa106InvertedMethod KEYWORD1 +NeoEsp32I2s1Ws2812xInvertedMethod KEYWORD1 +NeoEsp32I2s1Sk6812InvertedMethod KEYWORD1 +NeoEsp32I2s1Tm1814InvertedMethod KEYWORD1 +NeoEsp32I2s1800KbpsInvertedMethod KEYWORD1 +NeoEsp32I2s1400KbpsInvertedMethod KEYWORD1 +NeoEsp32I2s1Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt0Ws2811Method KEYWORD1 +NeoEsp32Rmt0Ws2812xMethod KEYWORD1 +NeoEsp32Rmt0Sk6812Method KEYWORD1 +NeoEsp32Rmt0Tm1814Method KEYWORD1 +NeoEsp32Rmt0Apa106Method KEYWORD1 +NeoEsp32Rmt0800KbpsMethod KEYWORD1 +NeoEsp32Rmt0400KbpsMethod KEYWORD1 +NeoEsp32Rmt1Ws2811Method KEYWORD1 +NeoEsp32Rmt1Ws2812xMethod KEYWORD1 +NeoEsp32Rmt1Sk6812Method KEYWORD1 +NeoEsp32Rmt1Tm1814Method KEYWORD1 +NeoEsp32Rmt1Apa106Method KEYWORD1 +NeoEsp32Rmt1800KbpsMethod KEYWORD1 +NeoEsp32Rmt1400KbpsMethod KEYWORD1 +NeoEsp32Rmt2Ws2811Method KEYWORD1 +NeoEsp32Rmt2Ws2812xMethod KEYWORD1 +NeoEsp32Rmt2Sk6812Method KEYWORD1 +NeoEsp32Rmt2Tm1814Method KEYWORD1 +NeoEsp32Rmt2Apa106Method KEYWORD1 +NeoEsp32Rmt2800KbpsMethod KEYWORD1 +NeoEsp32Rmt2400KbpsMethod KEYWORD1 +NeoEsp32Rmt3Ws2811Method KEYWORD1 +NeoEsp32Rmt3Ws2812xMethod KEYWORD1 +NeoEsp32Rmt3Sk6812Method KEYWORD1 +NeoEsp32Rmt3Tm1814Method KEYWORD1 +NeoEsp32Rmt3Apa106Method KEYWORD1 +NeoEsp32Rmt3800KbpsMethod KEYWORD1 +NeoEsp32Rmt3400KbpsMethod KEYWORD1 +NeoEsp32Rmt4Ws2811Method KEYWORD1 +NeoEsp32Rmt4Ws2812xMethod KEYWORD1 +NeoEsp32Rmt4Sk6812Method KEYWORD1 +NeoEsp32Rmt4Tm1814Method KEYWORD1 +NeoEsp32Rmt4Apa106Method KEYWORD1 +NeoEsp32Rmt4800KbpsMethod KEYWORD1 +NeoEsp32Rmt4400KbpsMethod KEYWORD1 +NeoEsp32Rmt5Ws2811Method KEYWORD1 +NeoEsp32Rmt5Ws2812xMethod KEYWORD1 +NeoEsp32Rmt5Sk6812Method KEYWORD1 +NeoEsp32Rmt5Tm1814Method KEYWORD1 +NeoEsp32Rmt5Apa106Method KEYWORD1 +NeoEsp32Rmt5800KbpsMethod KEYWORD1 +NeoEsp32Rmt5400KbpsMethod KEYWORD1 +NeoEsp32Rmt6Ws2811Method KEYWORD1 +NeoEsp32Rmt6Ws2812xMethod KEYWORD1 +NeoEsp32Rmt6Sk6812Method KEYWORD1 +NeoEsp32Rmt6Tm1814Method KEYWORD1 +NeoEsp32Rmt6Apa106Method KEYWORD1 +NeoEsp32Rmt6800KbpsMethod KEYWORD1 +NeoEsp32Rmt6400KbpsMethod KEYWORD1 +NeoEsp32Rmt7Ws2811Method KEYWORD1 +NeoEsp32Rmt7Ws2812xMethod KEYWORD1 +NeoEsp32Rmt7Sk6812Method KEYWORD1 +NeoEsp32Rmt7Tm1814Method KEYWORD1 +NeoEsp32Rmt7Apa106Method KEYWORD1 +NeoEsp32Rmt7800KbpsMethod KEYWORD1 +NeoEsp32Rmt7400KbpsMethod KEYWORD1 +NeoEsp32Rmt0Ws2811InvertedMethod KEYWORD1 +NeoEsp32Rmt0Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt0Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt0Tm1814InvertedMethod KEYWORD1 +NeoEsp32Rmt0Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt0800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt0400KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt1Ws2811InvertedMethod KEYWORD1 +NeoEsp32Rmt1Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt1Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt1Tm1814InvertedMethod KEYWORD1 +NeoEsp32Rmt1Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt1800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt1400KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt2Ws2811InvertedMethod KEYWORD1 +NeoEsp32Rmt2Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt2Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt2Tm1814InvertedMethod KEYWORD1 +NeoEsp32Rmt2Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt2800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt2400KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt3Ws2811InvertedMethod KEYWORD1 +NeoEsp32Rmt3Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt3Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt3Tm1814InvertedMethod KEYWORD1 +NeoEsp32Rmt3Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt3800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt3400KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt4Ws2811InvertedMethod KEYWORD1 +NeoEsp32Rmt4Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt4Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt4Tm1814InvertedMethod KEYWORD1 +NeoEsp32Rmt4Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt4800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt4400KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt5Ws2811InvertedMethod KEYWORD1 +NeoEsp32Rmt5Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt5Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt5Tm1814InvertedMethod KEYWORD1 +NeoEsp32Rmt5Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt5800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt5400KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt6Ws2811InvertedMethod KEYWORD1 +NeoEsp32Rmt6Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt6Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt6Tm1814InvertedMethod KEYWORD1 +NeoEsp32Rmt6Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt6800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt6400KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt7Ws2811InvertedMethod KEYWORD1 +NeoEsp32Rmt7Ws2812xInvertedMethod KEYWORD1 +NeoEsp32Rmt7Sk6812InvertedMethod KEYWORD1 +NeoEsp32Rmt7Tm1814InvertedMethod KEYWORD1 +NeoEsp32Rmt7Apa106InvertedMethod KEYWORD1 +NeoEsp32Rmt7800KbpsInvertedMethod KEYWORD1 +NeoEsp32Rmt7400KbpsInvertedMethod KEYWORD1 +NeoEsp32BitBangWs2813Method KEYWORD1 +NeoEsp32BitBangWs2812xMethod KEYWORD1 +NeoEsp32BitBangWs2812Method KEYWORD1 +NeoEsp32BitBangWs2811Method KEYWORD1 +NeoEsp32BitBangSk6812Method KEYWORD1 +NeoEsp32BitBangTm1814Method KEYWORD1 +NeoEsp32BitBangLc8812Method KEYWORD1 +NeoEsp32BitBangApa106Method KEYWORD1 +NeoEsp32BitBang800KbpsMethod KEYWORD1 +NeoEsp32BitBang400KbpsMethod KEYWORD1 +NeoEsp32BitBangWs2813InvertedMethod KEYWORD1 +NeoEsp32BitBangWs2812xInvertedMethod KEYWORD1 +NeoEsp32BitBangWs2812InvertedMethod KEYWORD1 +NeoEsp32BitBangWs2811InvertedMethod KEYWORD1 +NeoEsp32BitBangSk6812InvertedMethod KEYWORD1 +NeoEsp32BitBangTm1814InvertedMethod KEYWORD1 +NeoEsp32BitBangLc8812InvertedMethod KEYWORD1 +NeoEsp32BitBangApa106InvertedMethod KEYWORD1 +NeoEsp32BitBang800KbpsInvertedMethod KEYWORD1 +NeoEsp32BitBang400KbpsInvertedMethod KEYWORD1 +NeoNrf52xPwm0Ws2812xMethod KEYWORD1 +NeoNrf52xPwm0Sk6812Method KEYWORD1 +NeoNrf52xPwm0Tm1814Method KEYWORD1 +NeoNrf52xPwm0800KbpsMethod KEYWORD1 +NeoNrf52xPwm0400KbpsMethod KEYWORD1 +NeoNrf52xPwm0Apa106Method KEYWORD1 +NeoNrf52xPwm1Ws2812xMethod KEYWORD1 +NeoNrf52xPwm1Sk6812Method KEYWORD1 +NeoNrf52xPwm1Tm1814Method KEYWORD1 +NeoNrf52xPwm1800KbpsMethod KEYWORD1 +NeoNrf52xPwm1400KbpsMethod KEYWORD1 +NeoNrf52xPwm1Apa106Method KEYWORD1 +NeoNrf52xPwm2Ws2812xMethod KEYWORD1 +NeoNrf52xPwm2Sk6812Method KEYWORD1 +NeoNrf52xPwm2Tm1814Method KEYWORD1 +NeoNrf52xPwm2800KbpsMethod KEYWORD1 +NeoNrf52xPwm2400KbpsMethod KEYWORD1 +NeoNrf52xPwm2Apa106Method KEYWORD1 +NeoNrf52xPwm3Ws2812xMethod KEYWORD1 +NeoNrf52xPwm3Sk6812Method KEYWORD1 +NeoNrf52xPwm3Tm1814Method KEYWORD1 +NeoNrf52xPwm3800KbpsMethod KEYWORD1 +NeoNrf52xPwm3400KbpsMethod KEYWORD1 +NeoNrf52xPwm3Apa106Method KEYWORD1 +NeoNrf52xPwm0Ws2812xInvertedMethod KEYWORD1 +NeoNrf52xPwm0Sk6812InvertedMethod KEYWORD1 +NeoNrf52xPwm0Tm1814InvertedMethod KEYWORD1 +NeoNrf52xPwm0800KbpsInvertedMethod KEYWORD1 +NeoNrf52xPwm0400KbpsInvertedMethod KEYWORD1 +NeoNrf52xPwm0Apa106InvertedMethod KEYWORD1 +NeoNrf52xPwm1Ws2812xInvertedMethod KEYWORD1 +NeoNrf52xPwm1Sk6812InvertedMethod KEYWORD1 +NeoNrf52xPwm1Tm1814InvertedMethod KEYWORD1 +NeoNrf52xPwm1800KbpsInvertedMethod KEYWORD1 +NeoNrf52xPwm1400KbpsInvertedMethod KEYWORD1 +NeoNrf52xPwm1Apa106InvertedMethod KEYWORD1 +NeoNrf52xPwm2Ws2812xInvertedMethod KEYWORD1 +NeoNrf52xPwm2Sk6812InvertedMethod KEYWORD1 +NeoNrf52xPwm2Tm1814InvertedMethod KEYWORD1 +NeoNrf52xPwm2800KbpsInvertedMethod KEYWORD1 +NeoNrf52xPwm2400KbpsInvertedMethod KEYWORD1 +NeoNrf52xPwm2Apa106InvertedMethod KEYWORD1 +NeoNrf52xPwm3Ws2812xInvertedMethod KEYWORD1 +NeoNrf52xPwm3Sk6812InvertedMethod KEYWORD1 +NeoNrf52xPwm3Tm1814InvertedMethod KEYWORD1 +NeoNrf52xPwm3800KbpsInvertedMethod KEYWORD1 +NeoNrf52xPwm3400KbpsInvertedMethod KEYWORD1 +NeoNrf52xPwm3Apa106InvertedMethod KEYWORD1 +DotStarMethod KEYWORD1 +DotStarSpiMethod KEYWORD1 +DotStarSpi20MhzMethod KEYWORD1 +DotStarSpi10MhzMethod KEYWORD1 +DotStarSpi2MhzMethod KEYWORD1 +NeoWs2801Method KEYWORD1 +NeoWs2801SpiMethod KEYWORD1 +NeoWs2801Spi20MhzMethod KEYWORD1 +NeoWs2801Spi10MhzMethod KEYWORD1 +NeoWs2801Spi2MhzMethod KEYWORD1 +Lpd8806Method KEYWORD1 +Lpd8806SpiMethod KEYWORD1 +Lpd8806Spi20MhzMethod KEYWORD1 +Lpd8806Spi10MhzMethod KEYWORD1 +Lpd8806Spi2MhzMethod KEYWORD1 +P9813Method KEYWORD1 +P9813SpiMethod KEYWORD1 +P9813Spi20MhzMethod KEYWORD1 +P9813Spi10MhzMethod KEYWORD1 +P9813Spi2MhzMethod KEYWORD1 +NeoPixelAnimator KEYWORD1 +AnimUpdateCallback KEYWORD1 +AnimationParam KEYWORD1 +NeoEase KEYWORD1 +AnimEaseFunction KEYWORD1 +RowMajorLayout KEYWORD1 +RowMajor90Layout KEYWORD1 +RowMajor180Layout KEYWORD1 +RowMajor270Layout KEYWORD1 +RowMajorAlternatingLayout KEYWORD1 +RowMajorAlternating90Layout KEYWORD1 +RowMajorAlternating180Layout KEYWORD1 +RowMajorAlternating270Layout KEYWORD1 +ColumnMajorLayout KEYWORD1 +ColumnMajor90Layout KEYWORD1 +ColumnMajor180Layout KEYWORD1 +ColumnMajor270Layout KEYWORD1 +ColumnMajorAlternatingLayout KEYWORD1 +ColumnMajorAlternating90Layout KEYWORD1 +ColumnMajorAlternating180Layout KEYWORD1 +ColumnMajorAlternating270Layout KEYWORD1 +NeoTopology KEYWORD1 +NeoRingTopology KEYWORD1 +NeoTiles KEYWORD1 +NeoMosaic KEYWORD1 +NeoGammaEquationMethod KEYWORD1 +NeoGammaTableMethod KEYWORD1 +NeoGamma KEYWORD1 +NeoHueBlendShortestDistance KEYWORD1 +NeoHueBlendLongestDistance KEYWORD1 +NeoHueBlendClockwiseDirection KEYWORD1 +NeoHueBlendCounterClockwiseDirection KEYWORD1 +NeoBufferContext KEYWORD1 +LayoutMapCallback KEYWORD1 +NeoBufferMethod KEYWORD1 +NeoBufferProgmemMethod KEYWORD1 +NeoBuffer KEYWORD1 +NeoVerticalSpriteSheet KEYWORD1 +NeoBitmapFile KEYWORD1 +HtmlShortColorNames KEYWORD1 +HtmlColorNames KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +Begin KEYWORD2 +Show KEYWORD2 +CanShow KEYWORD2 +ClearTo KEYWORD2 +RotateLeft KEYWORD2 +ShiftLeft KEYWORD2 +RotateRight KEYWORD2 +ShiftRight KEYWORD2 +IsDirty KEYWORD2 +Dirty KEYWORD2 +ResetDirty KEYWORD2 +Pixels KEYWORD2 +PixelSize KEYWORD2 +PixelsSize KEYWORD2 +PixelCount KEYWORD2 +SetPixelColor KEYWORD2 +GetPixelColor KEYWORD2 +SwapPixelColor KEYWORD2 +CalculateBrightness KEYWORD2 +Dim KEYWORD2 +Brighten KEYWORD2 +Darken KEYWORD2 +Lighten KEYWORD2 +SetPixelSettings KEYWORD2 +LinearBlend KEYWORD2 +BilinearBlend KEYWORD2 +IsAnimating KEYWORD2 +NextAvailableAnimation KEYWORD2 +StartAnimation KEYWORD2 +StopAnimation KEYWORD2 +RestartAnimation KEYWORD2 +IsAnimationActive KEYWORD2 +AnimationDuration KEYWORD2 +ChangeAnimationDuration KEYWORD2 +UpdateAnimations KEYWORD2 +IsPaused KEYWORD2 +Pause KEYWORD2 +Resume KEYWORD2 +getTimeScale KEYWORD2 +setTimeScale KEYWORD2 +QuadraticIn KEYWORD2 +QuadraticOut KEYWORD2 +QuadraticInOut KEYWORD2 +QuadraticCenter KEYWORD2 +CubicIn KEYWORD2 +CubicOut KEYWORD2 +CubicInOut KEYWORD2 +CubicCenter KEYWORD2 +QuarticIn KEYWORD2 +QuarticOut KEYWORD2 +QuarticInOut KEYWORD2 +QuarticCenter KEYWORD2 +QuinticIn KEYWORD2 +QuinticOut KEYWORD2 +QuinticInOut KEYWORD2 +QuinticCenter KEYWORD2 +SinusoidalIn KEYWORD2 +SinusoidalOut KEYWORD2 +SinusoidalInOut KEYWORD2 +SinusoidalCenter KEYWORD2 +ExponentialIn KEYWORD2 +ExponentialOut KEYWORD2 +ExponentialInOut KEYWORD2 +ExponentialCenter KEYWORD2 +CircularIn KEYWORD2 +CircularOut KEYWORD2 +CircularInOut KEYWORD2 +CircularCenter KEYWORD2 +Gamma KEYWORD2 +Map KEYWORD2 +MapProbe KEYWORD2 +getWidth KEYWORD2 +getHeight KEYWORD2 +RingPixelShift KEYWORD2 +RingPixelRotate KEYWORD2 +getCountOfRings KEYWORD2 +getPixelCountAtRing KEYWORD2 +getPixelCount KEYWORD2 +TopologyHint KEYWORD2 +Correct KEYWORD2 +SpriteWidth KEYWORD2 +SpriteHeight KEYWORD2 +SpriteCount KEYWORD2 +Blt KEYWORD2 +Width KEYWORD2 +Height KEYWORD2 +Parse KEYWORD2 +ToString KEYWORD2 +ToNumericalString KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### + +NEO_MILLISECONDS LITERAL1 +NEO_CENTISECONDS LITERAL1 +NEO_DECISECONDS LITERAL1 +NEO_SECONDS LITERAL1 +NEO_DECASECONDS LITERAL1 +AnimationState_Started LITERAL1 +AnimationState_Progress LITERAL1 +AnimationState_Completed LITERAL1 +NeoTopologyHint_FirstOnPanel LITERAL1 +NeoTopologyHint_InPanel LITERAL1 +NeoTopologyHint_LastOnPanel LITERAL1 +NeoTopologyHint_OutOfBounds LITERAL1 +PixelIndex_OutOfBounds LITERAL1 \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/library.json b/lib/NeoPixelBus_by_Makuna/library.json new file mode 100644 index 0000000..e50ebd2 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/library.json @@ -0,0 +1,14 @@ +{ + "name": "NeoPixelBus", + "keywords": "NeoPixel, WS2811, WS2812, WS2813, SK6812, DotStar, APA102, SK9822, APA106, LPD8806, P9813, WS2801 RGB, RGBW", + "description": "A library that makes controlling NeoPixels (APA106, WS2811, WS2812, WS2813 & SK6812) and DotStars (APA102, LPD8806, SK9822, WS2801, P9813) easy. Supports most Arduino platforms, including async hardware support for Esp8266, Esp32, and Nrf52 (Nano 33 BLE). Support for RGBW pixels. Includes seperate RgbColor, RgbwColor, HslColor, and HsbColor objects. Includes an animator class that helps create asyncronous animations. For Esp8266 it has three methods of sending NeoPixel data, DMA, UART, and Bit Bang. For Esp32 it has two base methods of sending NeoPixel data, i2s and RMT. For all platforms, there are two methods of sending DotStar data, hardware SPI and software SPI.", + "homepage": "https://github.com/Makuna/NeoPixelBus/wiki", + "repository": { + "type": "git", + "url": "https://github.com/Makuna/NeoPixelBus" + }, + "version": "2.6.0", + "frameworks": "arduino", + "platforms": "*" +} + diff --git a/lib/NeoPixelBus_by_Makuna/library.properties b/lib/NeoPixelBus_by_Makuna/library.properties new file mode 100644 index 0000000..7182026 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/library.properties @@ -0,0 +1,9 @@ +name=NeoPixelBus by Makuna +version=2.6.0 +author=Michael C. Miller (makuna@live.com) +maintainer=Michael C. Miller (makuna@live.com) +sentence=A library that makes controlling NeoPixels (APA106, WS2811, WS2812, WS2813 & SK6812) and DotStars (APA102, LPD8806, SK9822, WS2801, P9813) easy. +paragraph=Supports most Arduino platforms, including async hardware support for Esp8266, Esp32, and Nrf52 (Nano 33 BLE). Support for RGBW pixels. Includes seperate RgbColor, RgbwColor, HslColor, and HsbColor objects. Includes an animator class that helps create asyncronous animations. Supports Matrix layout of pixels. Includes Gamma corretion object. For Esp8266 it has three methods of sending NeoPixel data, DMA, UART, and Bit Bang. For Esp32 it has two base methods of sending NeoPixel data, i2s and RMT. For all platforms, there are two methods of sending DotStar data, hardware SPI and software SPI. +category=Display +url=https://github.com/Makuna/NeoPixelBus/wiki +architectures=* \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/NeoPixelAnimator.h b/lib/NeoPixelBus_by_Makuna/src/NeoPixelAnimator.h new file mode 100644 index 0000000..d990599 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/NeoPixelAnimator.h @@ -0,0 +1,180 @@ +/*------------------------------------------------------------------------- +NeoPixelAnimator provides animation timing support. + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#include +#include "internal/NeoEase.h" + +enum AnimationState +{ + AnimationState_Started, + AnimationState_Progress, + AnimationState_Completed +}; + +struct AnimationParam +{ + float progress; + uint16_t index; + AnimationState state; +}; + +#if defined(NEOPIXEBUS_NO_STL) + +typedef void(*AnimUpdateCallback)(const AnimationParam& param); + +#else + +#undef max +#undef min +#include +typedef std::function AnimUpdateCallback; + +#endif + + +#define NEO_MILLISECONDS 1 // ~65 seconds max duration, ms updates +#define NEO_CENTISECONDS 10 // ~10.9 minutes max duration, centisecond updates +#define NEO_DECISECONDS 100 // ~1.8 hours max duration, decisecond updates +#define NEO_SECONDS 1000 // ~18.2 hours max duration, second updates +#define NEO_DECASECONDS 10000 // ~7.5 days, 10 second updates + +class NeoPixelAnimator +{ +public: + NeoPixelAnimator(uint16_t countAnimations, uint16_t timeScale = NEO_MILLISECONDS); + ~NeoPixelAnimator(); + + bool IsAnimating() const + { + return _activeAnimations > 0; + } + + + bool NextAvailableAnimation(uint16_t* indexAvailable, uint16_t indexStart = 0); + + void StartAnimation(uint16_t indexAnimation, uint16_t duration, AnimUpdateCallback animUpdate); + void StopAnimation(uint16_t indexAnimation); + void StopAll(); + + void RestartAnimation(uint16_t indexAnimation) + { + if (indexAnimation >= _countAnimations || _animations[indexAnimation]._duration == 0) + { + return; + } + + StartAnimation(indexAnimation, _animations[indexAnimation]._duration, (_animations[indexAnimation]._fnCallback)); + } + + bool IsAnimationActive(uint16_t indexAnimation) const + { + if (indexAnimation >= _countAnimations) + { + return false; + } + return (IsAnimating() && _animations[indexAnimation]._remaining != 0); + } + + uint16_t AnimationDuration(uint16_t indexAnimation) + { + if (indexAnimation >= _countAnimations) + { + return 0; + } + return _animations[indexAnimation]._duration; + } + + void ChangeAnimationDuration(uint16_t indexAnimation, uint16_t newDuration); + + void UpdateAnimations(); + + bool IsPaused() + { + return (!_isRunning); + } + + void Pause() + { + _isRunning = false; + } + + void Resume() + { + _isRunning = true; + _animationLastTick = millis(); + } + + uint16_t getTimeScale() + { + return _timeScale; + } + + void setTimeScale(uint16_t timeScale) + { + _timeScale = (timeScale < 1) ? (1) : (timeScale > 32768) ? 32768 : timeScale; + } + +private: + struct AnimationContext + { + AnimationContext() : + _duration(0), + _remaining(0), + _fnCallback(NULL) + {} + + void StartAnimation(uint16_t duration, AnimUpdateCallback animUpdate) + { + _duration = duration; + _remaining = duration; + _fnCallback = animUpdate; + } + + void StopAnimation() + { + _remaining = 0; + } + + float CurrentProgress() + { + return (float)(_duration - _remaining) / (float)_duration; + } + + uint16_t _duration; + uint16_t _remaining; + + AnimUpdateCallback _fnCallback; + }; + + uint16_t _countAnimations; + AnimationContext* _animations; + uint32_t _animationLastTick; + uint16_t _activeAnimations; + uint16_t _timeScale; + bool _isRunning; +}; diff --git a/lib/NeoPixelBus_by_Makuna/src/NeoPixelBrightnessBus.h b/lib/NeoPixelBus_by_Makuna/src/NeoPixelBrightnessBus.h new file mode 100644 index 0000000..3bea54b --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/NeoPixelBrightnessBus.h @@ -0,0 +1,142 @@ +/*------------------------------------------------------------------------- +NeoPixelBus library wrapper template class that provides overall brightness control + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#include "NeoPixelBus.h" + +template class NeoPixelBrightnessBus : + public NeoPixelBus +{ +private: + + void ScaleColor(uint16_t scale, typename T_COLOR_FEATURE::ColorObject* color) + { + uint8_t* ptr = (uint8_t*)color; + uint8_t* ptrEnd = ptr + sizeof(typename T_COLOR_FEATURE::ColorObject); + + while (ptr != ptrEnd) + { + uint16_t value = *ptr; + *ptr++ = (value * scale) >> 8; + } + } + + void ConvertColor(typename T_COLOR_FEATURE::ColorObject* color) + { + uint16_t scale = _brightness + 1; + ScaleColor(scale, color); + } + + void RecoverColor(typename T_COLOR_FEATURE::ColorObject* color) const + { + uint8_t* ptr = (uint8_t*)color; + uint8_t* ptrEnd = ptr + sizeof(typename T_COLOR_FEATURE::ColorObject); + uint16_t scale = _brightness + 1; + + while (ptr != ptrEnd) + { + uint16_t value = *ptr; + *ptr++ = (value << 8) / scale; + } + } + +public: + NeoPixelBrightnessBus(uint16_t countPixels, uint8_t pin) : + NeoPixelBus(countPixels, pin), + _brightness(255) + { + } + + NeoPixelBrightnessBus(uint16_t countPixels, uint8_t pinClock, uint8_t pinData) : + NeoPixelBus(countPixels, pinClock, pinData), + _brightness(255) + { + } + + NeoPixelBrightnessBus(uint16_t countPixels) : + NeoPixelBus(countPixels), + _brightness(255) + { + } + + void SetBrightness(uint8_t brightness) + { + // Only update if there is a change + if (brightness != _brightness) + { + uint16_t scale = (((uint16_t)brightness + 1) << 8) / ((uint16_t)_brightness + 1); + + // scale existing pixels + // + for (uint16_t indexPixel = 0; indexPixel < NeoPixelBus::PixelCount(); indexPixel++) + { + typename T_COLOR_FEATURE::ColorObject color = NeoPixelBus::GetPixelColor(indexPixel); + ScaleColor(scale, &color); + NeoPixelBus::SetPixelColor(indexPixel, color); + } + + _brightness = brightness; + this->Dirty(); + } + } + + uint8_t GetBrightness() const + { + return _brightness; + } + + void SetPixelColor(uint16_t indexPixel, typename T_COLOR_FEATURE::ColorObject color) + { + ConvertColor(&color); + NeoPixelBus::SetPixelColor(indexPixel, color); + } + + typename T_COLOR_FEATURE::ColorObject GetPixelColor(uint16_t indexPixel) const + { + typename T_COLOR_FEATURE::ColorObject color = NeoPixelBus::GetPixelColor(indexPixel); + RecoverColor(&color); + return color; + } + + void ClearTo(typename T_COLOR_FEATURE::ColorObject color) + { + ConvertColor(&color); + NeoPixelBus::ClearTo(color); + }; + + void ClearTo(typename T_COLOR_FEATURE::ColorObject color, uint16_t first, uint16_t last) + { + ConvertColor(&color); + NeoPixelBus::ClearTo(color, first, last); + } + + +protected: + uint8_t _brightness; +}; + + diff --git a/lib/NeoPixelBus_by_Makuna/src/NeoPixelBus.h b/lib/NeoPixelBus_by_Makuna/src/NeoPixelBus.h new file mode 100644 index 0000000..a9ec865 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/NeoPixelBus.h @@ -0,0 +1,468 @@ +/*------------------------------------------------------------------------- +NeoPixel library + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +#include + +// some platforms do not come with STL or properly defined one, specifically functional +// if you see... +// undefined reference to `std::__throw_bad_function_call()' +// ...then you can either add the platform symbol to the list so NEOPIXEBUS_NO_STL gets defined or +// go to boards.txt and enable c++ by adding (teensy31.build.flags.libs=-lstdc++) and set to "smallest code" option in Arduino +// +#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) || defined(STM32L432xx) || defined(STM32L476xx) || defined(ARDUINO_ARCH_SAM) +#define NEOPIXEBUS_NO_STL 1 +#endif + +// some platforms do not define this standard progmem type for some reason +// +#ifndef PGM_VOID_P +#define PGM_VOID_P const void * +#endif + +// '_state' flags for internal state +#define NEO_DIRTY 0x80 // a change was made to pixel data that requires a show + +#include "internal/NeoHueBlend.h" + +#include "internal/NeoSettings.h" + +#include "internal/RgbColor.h" +#include "internal/HslColor.h" +#include "internal/HsbColor.h" +#include "internal/HtmlColor.h" +#include "internal/RgbwColor.h" +#include "internal/SegmentDigit.h" + +#include "internal/NeoColorFeatures.h" +#include "internal/NeoTm1814ColorFeatures.h" +#include "internal/DotStarColorFeatures.h" +#include "internal/Lpd8806ColorFeatures.h" +#include "internal/P9813ColorFeatures.h" +#include "internal/NeoSegmentFeatures.h" + +#include "internal/Layouts.h" +#include "internal/NeoTopology.h" +#include "internal/NeoRingTopology.h" +#include "internal/NeoTiles.h" +#include "internal/NeoMosaic.h" + +#include "internal/NeoBufferContext.h" +#include "internal/NeoBufferMethods.h" +#include "internal/NeoBuffer.h" +#include "internal/NeoSpriteSheet.h" +#include "internal/NeoDib.h" +#include "internal/NeoBitmapFile.h" + +#include "internal/NeoEase.h" +#include "internal/NeoGamma.h" + +#include "internal/DotStarGenericMethod.h" +#include "internal/Lpd8806GenericMethod.h" +#include "internal/Ws2801GenericMethod.h" +#include "internal/P9813GenericMethod.h" + +#if defined(ARDUINO_ARCH_ESP8266) + +#include "internal/NeoEsp8266DmaMethod.h" +#include "internal/NeoEsp8266UartMethod.h" +#include "internal/NeoEspBitBangMethod.h" + +#elif defined(ARDUINO_ARCH_ESP32) + +#include "internal/NeoEsp32I2sMethod.h" +#include "internal/NeoEsp32RmtMethod.h" +#include "internal/NeoEspBitBangMethod.h" + +#elif defined(ARDUINO_ARCH_NRF52840) // must be before __arm__ + +#include "internal/NeoNrf52xMethod.h" + +#elif defined(__arm__) // must be before ARDUINO_ARCH_AVR due to Teensy incorrectly having it set + +#include "internal/NeoArmMethod.h" + +#elif defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) + +#include "internal/NeoAvrMethod.h" + +#else +#error "Platform Currently Not Supported, please add an Issue at Github/Makuna/NeoPixelBus" +#endif + + + + +template class NeoPixelBus +{ +public: + // Constructor: number of LEDs, pin number + // NOTE: Pin Number maybe ignored due to hardware limitations of the method. + + NeoPixelBus(uint16_t countPixels, uint8_t pin) : + _countPixels(countPixels), + _state(0), + _method(pin, countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize) + { + } + + NeoPixelBus(uint16_t countPixels, uint8_t pinClock, uint8_t pinData) : + _countPixels(countPixels), + _state(0), + _method(pinClock, pinData, countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize) + { + } + + NeoPixelBus(uint16_t countPixels) : + _countPixels(countPixels), + _state(0), + _method(countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize) + { + } + + ~NeoPixelBus() + { + } + + operator NeoBufferContext() + { + Dirty(); // we assume you are playing with bits + return NeoBufferContext(_pixels(), PixelsSize()); + } + + void Begin() + { + _method.Initialize(); + Dirty(); + } + + // used by DotStartSpiMethod if pins can be configured + void Begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) + { + _method.Initialize(sck, miso, mosi, ss); + Dirty(); + } + + void Show(bool maintainBufferConsistency = true) + { + if (!IsDirty()) + { + return; + } + + _method.Update(maintainBufferConsistency); + + ResetDirty(); + } + + inline bool CanShow() const + { + return _method.IsReadyToUpdate(); + }; + + bool IsDirty() const + { + return (_state & NEO_DIRTY); + }; + + void Dirty() + { + _state |= NEO_DIRTY; + }; + + void ResetDirty() + { + _state &= ~NEO_DIRTY; + }; + + uint8_t* Pixels() + { + return _pixels(); + }; + + size_t PixelsSize() const + { + return _method.getDataSize() - T_COLOR_FEATURE::SettingsSize; + }; + + size_t PixelSize() const + { + return T_COLOR_FEATURE::PixelSize; + }; + + uint16_t PixelCount() const + { + return _countPixels; + }; + + void SetPixelColor(uint16_t indexPixel, typename T_COLOR_FEATURE::ColorObject color) + { + if (indexPixel < _countPixels) + { + T_COLOR_FEATURE::applyPixelColor(_pixels(), indexPixel, color); + Dirty(); + } + }; + + typename T_COLOR_FEATURE::ColorObject GetPixelColor(uint16_t indexPixel) const + { + if (indexPixel < _countPixels) + { + return T_COLOR_FEATURE::retrievePixelColor(_pixels(), indexPixel); + } + else + { + // Pixel # is out of bounds, this will get converted to a + // color object type initialized to 0 (black) + return 0; + } + }; + + void ClearTo(typename T_COLOR_FEATURE::ColorObject color) + { + uint8_t temp[T_COLOR_FEATURE::PixelSize]; + uint8_t* pixels = _pixels(); + + T_COLOR_FEATURE::applyPixelColor(temp, 0, color); + + T_COLOR_FEATURE::replicatePixel(pixels, temp, _countPixels); + + Dirty(); + }; + + void ClearTo(typename T_COLOR_FEATURE::ColorObject color, uint16_t first, uint16_t last) + { + if (first < _countPixels && + last < _countPixels && + first <= last) + { + uint8_t temp[T_COLOR_FEATURE::PixelSize]; + uint8_t* pixels = _pixels(); + uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, first); + + T_COLOR_FEATURE::applyPixelColor(temp, 0, color); + + T_COLOR_FEATURE::replicatePixel(pFront, temp, last - first + 1); + + Dirty(); + } + } + + void RotateLeft(uint16_t rotationCount) + { + if ((_countPixels - 1) >= rotationCount) + { + _rotateLeft(rotationCount, 0, _countPixels - 1); + } + } + + void RotateLeft(uint16_t rotationCount, uint16_t first, uint16_t last) + { + if (first < _countPixels && + last < _countPixels && + first < last && + (last - first) >= rotationCount) + { + _rotateLeft(rotationCount, first, last); + } + } + + void ShiftLeft(uint16_t shiftCount) + { + if ((_countPixels - 1) >= shiftCount) + { + _shiftLeft(shiftCount, 0, _countPixels - 1); + Dirty(); + } + } + + void ShiftLeft(uint16_t shiftCount, uint16_t first, uint16_t last) + { + if (first < _countPixels && + last < _countPixels && + first < last && + (last - first) >= shiftCount) + { + _shiftLeft(shiftCount, first, last); + Dirty(); + } + } + + void RotateRight(uint16_t rotationCount) + { + if ((_countPixels - 1) >= rotationCount) + { + _rotateRight(rotationCount, 0, _countPixels - 1); + } + } + + void RotateRight(uint16_t rotationCount, uint16_t first, uint16_t last) + { + if (first < _countPixels && + last < _countPixels && + first < last && + (last - first) >= rotationCount) + { + _rotateRight(rotationCount, first, last); + } + } + + void ShiftRight(uint16_t shiftCount) + { + if ((_countPixels - 1) >= shiftCount) + { + _shiftRight(shiftCount, 0, _countPixels - 1); + Dirty(); + } + } + + void ShiftRight(uint16_t shiftCount, uint16_t first, uint16_t last) + { + if (first < _countPixels && + last < _countPixels && + first < last && + (last - first) >= shiftCount) + { + _shiftRight(shiftCount, first, last); + Dirty(); + } + } + + void SwapPixelColor(uint16_t indexPixelOne, uint16_t indexPixelTwo) + { + auto colorOne = GetPixelColor(indexPixelOne); + auto colorTwo = GetPixelColor(indexPixelTwo); + + SetPixelColor(indexPixelOne, colorTwo); + SetPixelColor(indexPixelTwo, colorOne); + }; + + void SetPixelSettings(const typename T_COLOR_FEATURE::SettingsObject& settings) + { + T_COLOR_FEATURE::applySettings(_method.getData(), settings); + Dirty(); + }; + + uint32_t CalcTotalMilliAmpere(const typename T_COLOR_FEATURE::ColorObject::SettingsObject& settings) + { + uint32_t total = 0; // in 1/10th milliamps + + for (uint16_t index = 0; index < _countPixels; index++) + { + auto color = GetPixelColor(index); + total += color.CalcTotalTenthMilliAmpere(settings); + } + + return total / 10; // return millamps + } + +protected: + const uint16_t _countPixels; // Number of RGB LEDs in strip + + uint8_t _state; // internal state + T_METHOD _method; + + uint8_t* _pixels() + { + // get pixels data within the data stream + return T_COLOR_FEATURE::pixels(_method.getData()); + } + + const uint8_t* _pixels() const + { + // get pixels data within the data stream + return T_COLOR_FEATURE::pixels(_method.getData()); + } + + void _rotateLeft(uint16_t rotationCount, uint16_t first, uint16_t last) + { + // store in temp + uint8_t temp[rotationCount * T_COLOR_FEATURE::PixelSize]; + uint8_t* pixels = _pixels(); + + uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, first); + + T_COLOR_FEATURE::movePixelsInc(temp, pFront, rotationCount); + + // shift data + _shiftLeft(rotationCount, first, last); + + // move temp back + pFront = T_COLOR_FEATURE::getPixelAddress(pixels, last - (rotationCount - 1)); + T_COLOR_FEATURE::movePixelsInc(pFront, temp, rotationCount); + + Dirty(); + } + + void _shiftLeft(uint16_t shiftCount, uint16_t first, uint16_t last) + { + uint16_t front = first + shiftCount; + uint16_t count = last - front + 1; + + uint8_t* pixels = _pixels(); + uint8_t* pFirst = T_COLOR_FEATURE::getPixelAddress(pixels, first); + uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, front); + + T_COLOR_FEATURE::movePixelsInc(pFirst, pFront, count); + + // intentional no dirty + } + + void _rotateRight(uint16_t rotationCount, uint16_t first, uint16_t last) + { + // store in temp + uint8_t temp[rotationCount * T_COLOR_FEATURE::PixelSize]; + uint8_t* pixels = _pixels(); + + uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, last - (rotationCount - 1)); + + T_COLOR_FEATURE::movePixelsDec(temp, pFront, rotationCount); + + // shift data + _shiftRight(rotationCount, first, last); + + // move temp back + pFront = T_COLOR_FEATURE::getPixelAddress(pixels, first); + T_COLOR_FEATURE::movePixelsDec(pFront, temp, rotationCount); + + Dirty(); + } + + void _shiftRight(uint16_t shiftCount, uint16_t first, uint16_t last) + { + uint16_t front = first + shiftCount; + uint16_t count = last - front + 1; + + uint8_t* pixels = _pixels(); + uint8_t* pFirst = T_COLOR_FEATURE::getPixelAddress(pixels, first); + uint8_t* pFront = T_COLOR_FEATURE::getPixelAddress(pixels, front); + + T_COLOR_FEATURE::movePixelsDec(pFront, pFirst, count); + // intentional no dirty + } +}; + + diff --git a/lib/NeoPixelBus_by_Makuna/src/NeoPixelSegmentBus.h b/lib/NeoPixelBus_by_Makuna/src/NeoPixelSegmentBus.h new file mode 100644 index 0000000..ebe16ce --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/NeoPixelSegmentBus.h @@ -0,0 +1,67 @@ +/*------------------------------------------------------------------------- +NeoPixelBus library wrapper template class that provides enhanced methods +for writing to segment based strips + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#include "NeoPixelBus.h" + +template class NeoPixelSegmentBus : + public NeoPixelBus +{ +public: + NeoPixelSegmentBus(uint16_t countPixels, uint8_t pin) : + NeoPixelBus(countPixels, pin) + { + } + + NeoPixelSegmentBus(uint16_t countPixels) : + NeoPixelBus(countPixels) + { + } + + void SetString(uint16_t indexDigit, + const char* str, + uint8_t brightness, + uint8_t defaultBrightness = 0) + { + T_COLOR_FEATURE::ColorObject::SetString(*this, + indexDigit, + str, + brightness, + defaultBrightness); + } + + void SetString(uint16_t indexDigit, + const String& str, + uint8_t brightness, + uint8_t defaultBrightness = 0) + { + SetString(indexDigit, str.c_str(), brightness, defaultBrightness); + } +}; + + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/DotStarColorFeatures.h b/lib/NeoPixelBus_by_Makuna/src/internal/DotStarColorFeatures.h new file mode 100644 index 0000000..918a12e --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/DotStarColorFeatures.h @@ -0,0 +1,698 @@ +/*------------------------------------------------------------------------- +DotStarColorFeatures provides feature classes to describe color order and +color depth for NeoPixelBus template class when used with DotStars + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +class DotStar3Elements +{ +public: + static const size_t PixelSize = 4; // still requires 4 to be sent + + static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + + static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + while (pPixelDest < pEnd) + { + *pPixelDest++ = pPixelSrc[0]; + *pPixelDest++ = pPixelSrc[1]; + *pPixelDest++ = pPixelSrc[2]; + *pPixelDest++ = pPixelSrc[3]; + } + } + + static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + while (pPixelDest < pEnd) + { + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + } + } + + static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + const uint8_t* pSrc = (const uint8_t*)pPixelSrc; + while (pPixelDest < pEnd) + { + *pPixelDest++ = pgm_read_byte(pSrc++); + *pPixelDest++ = pgm_read_byte(pSrc++); + *pPixelDest++ = pgm_read_byte(pSrc++); + *pPixelDest++ = pgm_read_byte(pSrc++); + } + } + + static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pDestBack = pPixelDest + (count * PixelSize); + const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize); + while (pDestBack > pPixelDest) + { + *--pDestBack = *--pSrcBack; + *--pDestBack = *--pSrcBack; + *--pDestBack = *--pSrcBack; + *--pDestBack = *--pSrcBack; + } + } + + typedef RgbColor ColorObject; +}; + +class DotStar4Elements +{ +public: + static const size_t PixelSize = 4; + + static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + + static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + while (pPixelDest < pEnd) + { + *pPixelDest++ = pPixelSrc[0]; + *pPixelDest++ = pPixelSrc[1]; + *pPixelDest++ = pPixelSrc[2]; + *pPixelDest++ = pPixelSrc[3]; + } + } + + static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + while (pPixelDest < pEnd) + { + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + } + } + + static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + const uint8_t* pSrc = (const uint8_t*)pPixelSrc; + while (pPixelDest < pEnd) + { + *pPixelDest++ = pgm_read_byte(pSrc++); + *pPixelDest++ = pgm_read_byte(pSrc++); + *pPixelDest++ = pgm_read_byte(pSrc++); + *pPixelDest++ = pgm_read_byte(pSrc++); + } + } + + static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pDestBack = pPixelDest + (count * PixelSize); + const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize); + while (pDestBack > pPixelDest) + { + *--pDestBack = *--pSrcBack; + *--pDestBack = *--pSrcBack; + *--pDestBack = *--pSrcBack; + *--pDestBack = *--pSrcBack; + } + } + + typedef RgbwColor ColorObject; +}; + + +class DotStar3ElementsNoSettings : public DotStar3Elements +{ +public: + typedef NeoNoSettings SettingsObject; + static const size_t SettingsSize = 0; + + static void applySettings(uint8_t*, const SettingsObject&) + { + } + + static uint8_t* pixels(uint8_t* pData) + { + return pData; + } + + static const uint8_t* pixels(const uint8_t* pData) + { + return pData; + } +}; + +class DotStar4ElementsNoSettings : public DotStar4Elements +{ +public: + typedef NeoNoSettings SettingsObject; + static const size_t SettingsSize = 0; + + static void applySettings(uint8_t*, const SettingsObject&) + { + } + + static uint8_t* pixels(uint8_t* pData) + { + return pData; + } + + static const uint8_t* pixels(const uint8_t* pData) + { + return pData; + } +}; + +class DotStarBgrFeature : public DotStar3ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = 0xff; // upper three bits are always 111 and brightness at max + *p++ = color.B; + *p++ = color.G; + *p = color.R; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + p++; // ignore the first byte + color.B = *p++; + color.G = *p++; + color.R = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + pgm_read_byte(p++); // ignore the first byte + color.B = pgm_read_byte(p++); + color.G = pgm_read_byte(p++); + color.R = pgm_read_byte(p); + + return color; + } + +}; + +class DotStarLbgrFeature : public DotStar4ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111 + *p++ = color.B; + *p++ = color.G; + *p = color.R; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.W = (*p++) & 0x1F; // mask out upper three bits + color.B = *p++; + color.G = *p++; + color.R = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits + color.B = pgm_read_byte(p++); + color.G = pgm_read_byte(p++); + color.R = pgm_read_byte(p); + + return color; + } + +}; + +class DotStarGrbFeature : public DotStar3ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = 0xff; // upper three bits are always 111 and brightness at max + *p++ = color.G; + *p++ = color.R; + *p = color.B; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + p++; // ignore the first byte + color.G = *p++; + color.R = *p++; + color.B = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + pgm_read_byte(p++); // ignore the first byte + color.G = pgm_read_byte(p++); + color.R = pgm_read_byte(p++); + color.B = pgm_read_byte(p); + + return color; + } + +}; + +class DotStarLgrbFeature : public DotStar4ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111 + *p++ = color.G; + *p++ = color.R; + *p = color.B; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.W = (*p++) & 0x1F; // mask out upper three bits + color.G = *p++; + color.R = *p++; + color.B = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits + color.G = pgm_read_byte(p++); + color.R = pgm_read_byte(p++); + color.B = pgm_read_byte(p); + + return color; + } + +}; + +/* RGB Feature -- Some APA102s ship in RGB order */ +class DotStarRgbFeature : public DotStar3ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = 0xff; // upper three bits are always 111 and brightness at max + *p++ = color.R; + *p++ = color.G; + *p = color.B; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + p++; // ignore the first byte + color.R = *p++; + color.G = *p++; + color.B = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + pgm_read_byte(p++); // ignore the first byte + color.R = pgm_read_byte(p++); + color.G = pgm_read_byte(p++); + color.B = pgm_read_byte(p); + + return color; + } + +}; + +class DotStarLrgbFeature : public DotStar4ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111 + *p++ = color.R; + *p++ = color.G; + *p = color.B; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.W = (*p++) & 0x1F; // mask out upper three bits + color.R = *p++; + color.G = *p++; + color.B = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits + color.R = pgm_read_byte(p++); + color.G = pgm_read_byte(p++); + color.B = pgm_read_byte(p); + + return color; + } + +}; +/* RBG Feature -- Some APA102s ship in RBG order */ +class DotStarRbgFeature : public DotStar3ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = 0xff; // upper three bits are always 111 and brightness at max + *p++ = color.R; + *p++ = color.B; + *p = color.G; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + p++; // ignore the first byte + color.R = *p++; + color.B = *p++; + color.G = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + pgm_read_byte(p++); // ignore the first byte + color.R = pgm_read_byte(p++); + color.B = pgm_read_byte(p++); + color.G = pgm_read_byte(p); + + return color; + } + +}; + +class DotStarLrbgFeature : public DotStar4ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111 + *p++ = color.R; + *p++ = color.B; + *p = color.G; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.W = (*p++) & 0x1F; // mask out upper three bits + color.R = *p++; + color.B = *p++; + color.G = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits + color.R = pgm_read_byte(p++); + color.B = pgm_read_byte(p++); + color.G = pgm_read_byte(p); + + return color; + } + +}; + +/* GBR Feature -- Some APA102s ship in GBR order */ +class DotStarGbrFeature : public DotStar3ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = 0xff; // upper three bits are always 111 and brightness at max + *p++ = color.G; + *p++ = color.B; + *p = color.R; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + p++; // ignore the first byte + color.G = *p++; + color.B = *p++; + color.R = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + pgm_read_byte(p++); // ignore the first byte + color.G = pgm_read_byte(p++); + color.B = pgm_read_byte(p++); + color.R = pgm_read_byte(p); + + return color; + } + +}; + +class DotStarLgbrFeature : public DotStar4ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111 + *p++ = color.G; + *p++ = color.B; + *p = color.R; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.W = (*p++) & 0x1F; // mask out upper three bits + color.G = *p++; + color.B = *p++; + color.R = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits + color.G = pgm_read_byte(p++); + color.B = pgm_read_byte(p++); + color.R = pgm_read_byte(p); + + return color; + } + +}; +/* BRG Feature -- Some APA102s ship in BRG order */ +class DotStarBrgFeature : public DotStar3ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = 0xff; // upper three bits are always 111 and brightness at max + *p++ = color.B; + *p++ = color.R; + *p = color.G; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + p++; // ignore the first byte + color.B = *p++; + color.R = *p++; + color.G = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + pgm_read_byte(p++); // ignore the first byte + color.B = pgm_read_byte(p++); + color.R = pgm_read_byte(p++); + color.G = pgm_read_byte(p); + + return color; + } + +}; + +class DotStarLbrgFeature : public DotStar4ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = 0xE0 | (color.W < 31 ? color.W : 31); // upper three bits are always 111 + *p++ = color.B; + *p++ = color.R; + *p = color.G; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.W = (*p++) & 0x1F; // mask out upper three bits + color.B = *p++; + color.R = *p++; + color.G = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.W = pgm_read_byte(p++) & 0x1F; // mask out upper three bits + color.B = pgm_read_byte(p++); + color.R = pgm_read_byte(p++); + color.G = pgm_read_byte(p); + + return color; + } + +}; diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/DotStarGenericMethod.h b/lib/NeoPixelBus_by_Makuna/src/internal/DotStarGenericMethod.h new file mode 100644 index 0000000..64c8f9a --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/DotStarGenericMethod.h @@ -0,0 +1,135 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for DotStars using general Pins (APA102). + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set +#if defined(ARDUINO_ARCH_AVR) && !defined(__arm__) +#include "TwoWireBitBangImpleAvr.h" +#else +#include "TwoWireBitBangImple.h" +#endif + + +template class DotStarMethodBase +{ +public: + DotStarMethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + _sizeEndFrame((pixelCount + 15) / 16), // 16 = div 2 (bit for every two pixels) div 8 (bits to bytes) + _wire(pinClock, pinData) + { + _data = static_cast(malloc(_sizeData)); + memset(_data, 0, _sizeData); + } + +#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny) + DotStarMethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + DotStarMethodBase(SCK, MOSI, pixelCount, elementSize, settingsSize) + { + } +#endif + + ~DotStarMethodBase() + { + free(_data); + } + + bool IsReadyToUpdate() const + { + return true; // dot stars don't have a required delay + } + +#if defined(ARDUINO_ARCH_ESP32) + void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) + { + _wire.begin(sck, miso, mosi, ss); + } +#endif + + void Initialize() + { + _wire.begin(); + } + + void Update(bool) + { + const uint8_t startFrame[4] = { 0x00 }; + const uint8_t resetFrame[4] = { 0x00 }; + + _wire.beginTransaction(); + + // start frame + _wire.transmitBytes(startFrame, sizeof(startFrame)); + + // data + _wire.transmitBytes(_data, _sizeData); + + // reset frame + _wire.transmitBytes(resetFrame, sizeof(resetFrame)); + + // end frame + + // one bit for every two pixels with no less than 1 byte + for (size_t endFrameByte = 0; endFrameByte < _sizeEndFrame; endFrameByte++) + { + _wire.transmitByte(0x00); + } + + _wire.endTransaction(); + } + + uint8_t* getData() const + { + return _data; + }; + + size_t getDataSize() const + { + return _sizeData; + }; + +private: + const size_t _sizeData; // Size of '_data' buffer below + const size_t _sizeEndFrame; + + T_TWOWIRE _wire; + uint8_t* _data; // Holds LED color values +}; + +typedef DotStarMethodBase DotStarMethod; + +#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny) +#include "TwoWireSpiImple.h" +typedef DotStarMethodBase> DotStarSpi40MhzMethod; +typedef DotStarMethodBase> DotStarSpi20MhzMethod; +typedef DotStarMethodBase> DotStarSpi10MhzMethod; +typedef DotStarMethodBase> DotStarSpi2MhzMethod; +typedef DotStarSpi10MhzMethod DotStarSpiMethod; +#endif + + + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/Esp32_i2s.c b/lib/NeoPixelBus_by_Makuna/src/internal/Esp32_i2s.c new file mode 100644 index 0000000..6f6b730 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/Esp32_i2s.c @@ -0,0 +1,498 @@ +// WARNING: This file contains code that is more than likely already +// exposed from the Esp32 Arduino API. It will be removed once integration is complete. +// +// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if defined(ARDUINO_ARCH_ESP32) + +#include +#include +#include "stdlib.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/queue.h" + + +#if ESP_IDF_VERSION_MAJOR>=4 +#include "esp_intr_alloc.h" +#else +#include "esp_intr.h" +#endif + +#include "soc/gpio_reg.h" +#include "soc/gpio_sig_map.h" +#include "soc/io_mux_reg.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/i2s_struct.h" +#include "soc/dport_reg.h" +#include "soc/sens_reg.h" +#include "driver/gpio.h" +#include "driver/i2s.h" +#include "driver/dac.h" +#include "Esp32_i2s.h" +#include "esp32-hal.h" + +#if ESP_IDF_VERSION_MAJOR<4 +#define I2S_BASE_CLK (160000000L) +#endif + +#define ESP32_REG(addr) (*((volatile uint32_t*)(0x3FF00000+(addr)))) + +#define I2S_DMA_QUEUE_SIZE 16 + +#define I2S_DMA_SILENCE_LEN 256 // bytes + +typedef struct i2s_dma_item_s { + uint32_t blocksize: 12; // datalen + uint32_t datalen : 12; // len*(bits_per_sample/8)*2 => max 2047*8bit/1023*16bit samples + uint32_t unused : 5; // 0 + uint32_t sub_sof : 1; // 0 + uint32_t eof : 1; // 1 => last? + uint32_t owner : 1; // 1 + + void* data; // malloc(datalen) + struct i2s_dma_item_s* next; + + // if this pointer is not null, it will be freed + void* free_ptr; + + // if DMA buffers are preallocated + uint8_t* buf; +} i2s_dma_item_t; + +typedef struct { + i2s_dev_t* bus; + int8_t ws; + int8_t bck; + int8_t out; + int8_t in; + uint32_t rate; + intr_handle_t isr_handle; + xQueueHandle tx_queue; + + uint8_t* silence_buf; + size_t silence_len; + + i2s_dma_item_t* dma_items; + size_t dma_count; + uint32_t dma_buf_len :12; + uint32_t unused :20; +} i2s_bus_t; + +static uint8_t i2s_silence_buf[I2S_DMA_SILENCE_LEN]; + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) +// (I2S_NUM_MAX == 2) +static i2s_bus_t I2S[I2S_NUM_MAX] = { + {&I2S0, -1, -1, -1, -1, 0, NULL, NULL, i2s_silence_buf, I2S_DMA_SILENCE_LEN, NULL, I2S_DMA_QUEUE_SIZE, 0, 0}, + {&I2S1, -1, -1, -1, -1, 0, NULL, NULL, i2s_silence_buf, I2S_DMA_SILENCE_LEN, NULL, I2S_DMA_QUEUE_SIZE, 0, 0} +}; +#else +static i2s_bus_t I2S[I2S_NUM_MAX] = { + {&I2S0, -1, -1, -1, -1, 0, NULL, NULL, i2s_silence_buf, I2S_DMA_SILENCE_LEN, NULL, I2S_DMA_QUEUE_SIZE, 0, 0} +}; +#endif + +void IRAM_ATTR i2sDmaISR(void* arg); +bool i2sInitDmaItems(uint8_t bus_num); + +bool i2sInitDmaItems(uint8_t bus_num) { + if (bus_num >= I2S_NUM_MAX) { + return false; + } + if (I2S[bus_num].tx_queue) {// already set + return true; + } + + if (I2S[bus_num].dma_items == NULL) { + I2S[bus_num].dma_items = (i2s_dma_item_t*)(malloc(I2S[bus_num].dma_count* sizeof(i2s_dma_item_t))); + if (I2S[bus_num].dma_items == NULL) { + log_e("MEM ERROR!"); + return false; + } + } + + int i, i2, a; + i2s_dma_item_t* item; + + for(i=0; ieof = 1; + item->owner = 1; + item->sub_sof = 0; + item->unused = 0; + item->data = I2S[bus_num].silence_buf; + item->blocksize = I2S[bus_num].silence_len; + item->datalen = I2S[bus_num].silence_len; + item->next = &I2S[bus_num].dma_items[i2]; + item->free_ptr = NULL; + if (I2S[bus_num].dma_buf_len) { + item->buf = (uint8_t*)(malloc(I2S[bus_num].dma_buf_len)); + if (item->buf == NULL) { + log_e("MEM ERROR!"); + for(a=0; abuf = NULL; + } + } + + I2S[bus_num].tx_queue = xQueueCreate(I2S[bus_num].dma_count, sizeof(i2s_dma_item_t*)); + if (I2S[bus_num].tx_queue == NULL) {// memory error + log_e("MEM ERROR!"); + free(I2S[bus_num].dma_items); + I2S[bus_num].dma_items = NULL; + return false; + } + return true; +} + +void i2sSetSilenceBuf(uint8_t bus_num, uint8_t* data, size_t len) { + if (bus_num >= I2S_NUM_MAX || !data || !len) { + return; + } + I2S[bus_num].silence_buf = data; + I2S[bus_num].silence_len = len; +} + +esp_err_t i2sSetClock(uint8_t bus_num, uint8_t div_num, uint8_t div_b, uint8_t div_a, uint8_t bck, uint8_t bits) { + if (bus_num >= I2S_NUM_MAX || div_a > 63 || div_b > 63 || bck > 63) { + return ESP_FAIL; + } + i2s_dev_t* i2s = I2S[bus_num].bus; + + typeof(i2s->clkm_conf) clkm_conf; + + clkm_conf.val = 0; +#if !defined(CONFIG_IDF_TARGET_ESP32S2) + clkm_conf.clka_en = 0; +#else + clkm_conf.clk_sel = 2; +#endif + + clkm_conf.clkm_div_a = div_a; + clkm_conf.clkm_div_b = div_b; + clkm_conf.clkm_div_num = div_num; + i2s->clkm_conf.val = clkm_conf.val; + + typeof(i2s->sample_rate_conf) sample_rate_conf; + sample_rate_conf.val = 0; + sample_rate_conf.tx_bck_div_num = bck; + sample_rate_conf.rx_bck_div_num = bck; + sample_rate_conf.tx_bits_mod = bits; + sample_rate_conf.rx_bits_mod = bits; + i2s->sample_rate_conf.val = sample_rate_conf.val; + return ESP_OK; +} + +void i2sSetDac(uint8_t bus_num, bool right, bool left) { + if (bus_num >= I2S_NUM_MAX) { + return; + } + + if (!right && !left) { + dac_output_disable(DAC_CHANNEL_1); + dac_output_disable(DAC_CHANNEL_2); + dac_i2s_disable(); + I2S[bus_num].bus->conf2.lcd_en = 0; + I2S[bus_num].bus->conf.tx_right_first = 0; + I2S[bus_num].bus->conf2.camera_en = 0; + I2S[bus_num].bus->conf.tx_msb_shift = 1;// I2S signaling + return; + } + + i2sSetPins(bus_num, -1, false); + I2S[bus_num].bus->conf2.lcd_en = 1; + I2S[bus_num].bus->conf.tx_right_first = 0; + I2S[bus_num].bus->conf2.camera_en = 0; + I2S[bus_num].bus->conf.tx_msb_shift = 0; + dac_i2s_enable(); + + if (right) {// DAC1, right channel, GPIO25 + dac_output_enable(DAC_CHANNEL_1); + } + if (left) { // DAC2, left channel, GPIO26 + dac_output_enable(DAC_CHANNEL_2); + } +} + +void i2sSetPins(uint8_t bus_num, int8_t out, bool invert) { + if (bus_num >= I2S_NUM_MAX) { + return; + } + + if (out >= 0) { + if (I2S[bus_num].out != out) { + if (I2S[bus_num].out >= 0) { + gpio_matrix_out(I2S[bus_num].out, 0x100, invert, false); + } + I2S[bus_num].out = out; + pinMode(out, OUTPUT); + + int i2sSignal; +#if !defined(CONFIG_IDF_TARGET_ESP32S2) +// (I2S_NUM_MAX == 2) + if (bus_num == 1) { + i2sSignal = I2S1O_DATA_OUT23_IDX; + } + else +#endif + { + i2sSignal = I2S0O_DATA_OUT23_IDX; + } + + gpio_matrix_out(out, i2sSignal, invert, false); + } + } else if (I2S[bus_num].out >= 0) { + gpio_matrix_out(I2S[bus_num].out, 0x100, invert, false); + I2S[bus_num].out = -1; + } + +} + +bool i2sWriteDone(uint8_t bus_num) { + if (bus_num >= I2S_NUM_MAX) { + return false; + } + return (I2S[bus_num].dma_items[I2S[bus_num].dma_count - 1].data == I2S[bus_num].silence_buf); +} + +void i2sInit(uint8_t bus_num, uint32_t bits_per_sample, uint32_t sample_rate, i2s_tx_chan_mod_t chan_mod, i2s_tx_fifo_mod_t fifo_mod, size_t dma_count, size_t dma_len) { + if (bus_num >= I2S_NUM_MAX) { + return; + } + + I2S[bus_num].dma_count = dma_count; + I2S[bus_num].dma_buf_len = dma_len & 0xFFF; + + if (!i2sInitDmaItems(bus_num)) { + return; + } + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) +// (I2S_NUM_MAX == 2) + if (bus_num) { + periph_module_enable(PERIPH_I2S1_MODULE); + } else +#endif + { + periph_module_enable(PERIPH_I2S0_MODULE); + } + + esp_intr_disable(I2S[bus_num].isr_handle); + i2s_dev_t* i2s = I2S[bus_num].bus; + i2s->out_link.stop = 1; + i2s->conf.tx_start = 0; + i2s->int_ena.val = 0; + i2s->int_clr.val = 0xFFFFFFFF; + i2s->fifo_conf.dscr_en = 0; + + // reset fifo + i2s->conf.rx_fifo_reset = 1; + i2s->conf.rx_fifo_reset = 0; + i2s->conf.tx_fifo_reset = 1; + i2s->conf.tx_fifo_reset = 0; + + // reset i2s + i2s->conf.tx_reset = 1; + i2s->conf.tx_reset = 0; + i2s->conf.rx_reset = 1; + i2s->conf.rx_reset = 0; + + // reset dma + i2s->lc_conf.in_rst = 1; + i2s->lc_conf.in_rst = 0; + i2s->lc_conf.out_rst = 1; + i2s->lc_conf.out_rst = 0; + + // Enable and configure DMA + typeof(i2s->lc_conf) lc_conf; + lc_conf.val = 0; + lc_conf.out_eof_mode = 1; + i2s->lc_conf.val = lc_conf.val; + + i2s->pdm_conf.pcm2pdm_conv_en = 0; + i2s->pdm_conf.pdm2pcm_conv_en = 0; + // SET_PERI_REG_BITS(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, 0x1, RTC_CNTL_SOC_CLK_SEL_S); + + typeof(i2s->conf_chan) conf_chan; + conf_chan.val = 0; + conf_chan.tx_chan_mod = chan_mod; // 0-two channel;1-right;2-left;3-righ;4-left + conf_chan.rx_chan_mod = chan_mod; // 0-two channel;1-right;2-left;3-righ;4-left + i2s->conf_chan.val = conf_chan.val; + + typeof(i2s->fifo_conf) fifo_conf; + fifo_conf.val = 0; + fifo_conf.tx_fifo_mod = fifo_mod; // 0-right&left channel;1-one channel + fifo_conf.rx_fifo_mod = fifo_mod; // 0-right&left channel;1-one channel + i2s->fifo_conf.val = fifo_conf.val; + + typeof(i2s->conf) conf; + conf.val = 0; + conf.tx_msb_shift = (bits_per_sample != 8);// 0:DAC/PCM, 1:I2S + conf.tx_right_first = (bits_per_sample == 8); + i2s->conf.val = conf.val; + + typeof(i2s->conf2) conf2; + conf2.val = 0; + conf2.lcd_en = (bits_per_sample == 8); + i2s->conf2.val = conf2.val; + + i2s->fifo_conf.tx_fifo_mod_force_en = 1; + + i2s->pdm_conf.rx_pdm_en = 0; + i2s->pdm_conf.tx_pdm_en = 0; + + i2sSetSampleRate(bus_num, sample_rate, bits_per_sample); + + // enable intr in cpu // + int i2sIntSource; + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) +// (I2S_NUM_MAX == 2) + if (bus_num == 1) { + i2sIntSource = ETS_I2S1_INTR_SOURCE; + } + else +#endif + { + i2sIntSource = ETS_I2S0_INTR_SOURCE; + } + + + esp_intr_alloc(i2sIntSource, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1, &i2sDmaISR, &I2S[bus_num], &I2S[bus_num].isr_handle); + // enable send intr + i2s->int_ena.out_eof = 1; + i2s->int_ena.out_dscr_err = 1; + + i2s->fifo_conf.dscr_en = 1;// enable dma + i2s->out_link.start = 0; + i2s->out_link.addr = (uint32_t)(&I2S[bus_num].dma_items[0]); // loads dma_struct to dma + i2s->out_link.start = 1; // starts dma + i2s->conf.tx_start = 1;// Start I2s module + + esp_intr_enable(I2S[bus_num].isr_handle); +} + +esp_err_t i2sSetSampleRate(uint8_t bus_num, uint32_t rate, uint8_t bits) { + if (bus_num >= I2S_NUM_MAX) { + return ESP_FAIL; + } + + if (I2S[bus_num].rate == rate) { + return ESP_OK; + } + + int clkmInteger, clkmDecimals, bck = 0; + double denom = (double)1 / 63; + int channel = 2; + +// double mclk; + double clkmdiv; + + int factor; + + if (bits == 8) { + factor = 120; + } else { + factor = (256 % bits) ? 384 : 256; + } + + clkmdiv = (double)I2S_BASE_CLK / (rate* factor); + if (clkmdiv > 256) { + log_e("rate is too low"); + return ESP_FAIL; + } + I2S[bus_num].rate = rate; + + clkmInteger = clkmdiv; + clkmDecimals = ((clkmdiv - clkmInteger) / denom); + + if (bits == 8) { +// mclk = rate* factor; + bck = 60; + bits = 16; + } else { +// mclk = (double)clkmInteger + (denom* clkmDecimals); + bck = factor/(bits* channel); + } + + i2sSetClock(bus_num, clkmInteger, clkmDecimals, 63, bck, bits); + + return ESP_OK; +} + +void IRAM_ATTR i2sDmaISR(void* arg) +{ + i2s_dma_item_t* dummy = NULL; + i2s_bus_t* dev = (i2s_bus_t*)(arg); + portBASE_TYPE hpTaskAwoken = 0; + + if (dev->bus->int_st.out_eof) { + i2s_dma_item_t* item = (i2s_dma_item_t*)(dev->bus->out_eof_des_addr); + item->data = dev->silence_buf; + item->blocksize = dev->silence_len; + item->datalen = dev->silence_len; + if (xQueueIsQueueFullFromISR(dev->tx_queue) == pdTRUE) { + xQueueReceiveFromISR(dev->tx_queue, &dummy, &hpTaskAwoken); + } + xQueueSendFromISR(dev->tx_queue, (void*)&item, &hpTaskAwoken); + } + dev->bus->int_clr.val = dev->bus->int_st.val; + if (hpTaskAwoken == pdTRUE) { + portYIELD_FROM_ISR(); + } +} + +size_t i2sWrite(uint8_t bus_num, uint8_t* data, size_t len, bool copy, bool free_when_sent) { + if (bus_num >= I2S_NUM_MAX || !I2S[bus_num].tx_queue) { + return 0; + } + size_t index = 0; + size_t toSend = len; + size_t limit = I2S_DMA_MAX_DATA_LEN; + i2s_dma_item_t* item = NULL; + + while (len) { + toSend = len; + if (toSend > limit) { + toSend = limit; + } + + if (xQueueReceive(I2S[bus_num].tx_queue, &item, portMAX_DELAY) == pdFALSE) { + log_e("xQueueReceive failed\n"); + break; + } + // data is constant. no need to copy + item->data = data + index; + item->blocksize = toSend; + item->datalen = toSend; + + len -= toSend; + index += toSend; + } + return index; +} + + +#endif diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/Esp32_i2s.h b/lib/NeoPixelBus_by_Makuna/src/internal/Esp32_i2s.h new file mode 100644 index 0000000..a95e7c5 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/Esp32_i2s.h @@ -0,0 +1,38 @@ +#pragma once + +#if defined(ARDUINO_ARCH_ESP32) + +#ifdef __cplusplus +extern "C" { +#endif + +#include "esp_err.h" + +#define I2S_DMA_MAX_DATA_LEN 4092// maximum bytes in one dma item + +typedef enum { + I2S_CHAN_STEREO, I2S_CHAN_RIGHT_TO_LEFT, I2S_CHAN_LEFT_TO_RIGHT, I2S_CHAN_RIGHT_ONLY, I2S_CHAN_LEFT_ONLY +} i2s_tx_chan_mod_t; + +typedef enum { + I2S_FIFO_16BIT_DUAL, I2S_FIFO_16BIT_SINGLE, I2S_FIFO_32BIT_DUAL, I2S_FIFO_32BIT_SINGLE +} i2s_tx_fifo_mod_t; + +void i2sInit(uint8_t bus_num, uint32_t bits_per_sample, uint32_t sample_rate, i2s_tx_chan_mod_t chan_mod, i2s_tx_fifo_mod_t fifo_mod, size_t dma_count, size_t dma_len); + +void i2sSetPins(uint8_t bus_num, int8_t out, bool invert); +void i2sSetDac(uint8_t bus_num, bool right, bool left); + +esp_err_t i2sSetClock(uint8_t bus_num, uint8_t div_num, uint8_t div_b, uint8_t div_a, uint8_t bck, uint8_t bits_per_sample); +esp_err_t i2sSetSampleRate(uint8_t bus_num, uint32_t sample_rate, uint8_t bits_per_sample); + +void i2sSetSilenceBuf(uint8_t bus_num, uint8_t* data, size_t len); + +size_t i2sWrite(uint8_t bus_num, uint8_t* data, size_t len, bool copy, bool free_when_sent); +bool i2sWriteDone(uint8_t bus_num); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/HsbColor.cpp b/lib/NeoPixelBus_by_Makuna/src/internal/HsbColor.cpp new file mode 100644 index 0000000..e47912f --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/HsbColor.cpp @@ -0,0 +1,68 @@ +/*------------------------------------------------------------------------- +HsbColor provides a color object that can be directly consumed by NeoPixelBus + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#include "RgbColor.h" +#include "HsbColor.h" + + +HsbColor::HsbColor(const RgbColor& color) +{ + // convert colors to float between (0.0 - 1.0) + float r = color.R / 255.0f; + float g = color.G / 255.0f; + float b = color.B / 255.0f; + + float max = (r > g && r > b) ? r : (g > b) ? g : b; + float min = (r < g && r < b) ? r : (g < b) ? g : b; + + float d = max - min; + + float h = 0.0; + float v = max; + float s = (v == 0.0f) ? 0 : (d / v); + + if (d != 0.0f) + { + if (r == max) + { + h = (g - b) / d + (g < b ? 6.0f : 0.0f); + } + else if (g == max) + { + h = (b - r) / d + 2.0f; + } + else + { + h = (r - g) / d + 4.0f; + } + h /= 6.0f; + } + + + H = h; + S = s; + B = v; +} diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/HsbColor.h b/lib/NeoPixelBus_by_Makuna/src/internal/HsbColor.h new file mode 100644 index 0000000..4d0bdfa --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/HsbColor.h @@ -0,0 +1,113 @@ + +/*------------------------------------------------------------------------- +HsbColor provides a color object that can be directly consumed by NeoPixelBus + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +#include + +// ------------------------------------------------------------------------ +// HsbColor represents a color object that is represented by Hue, Saturation, Brightness +// component values. It contains helpful color routines to manipulate the +// color. +// ------------------------------------------------------------------------ +struct HsbColor +{ + // ------------------------------------------------------------------------ + // Construct a HsbColor using H, S, B values (0.0 - 1.0) + // ------------------------------------------------------------------------ + HsbColor(float h, float s, float b) : + H(h), S(s), B(b) + { + }; + + // ------------------------------------------------------------------------ + // Construct a HsbColor using RgbColor + // ------------------------------------------------------------------------ + HsbColor(const RgbColor& color); + + // ------------------------------------------------------------------------ + // Construct a HsbColor that will have its values set in latter operations + // CAUTION: The H,S,B members are not initialized and may not be consistent + // ------------------------------------------------------------------------ + HsbColor() + { + }; + + // ------------------------------------------------------------------------ + // LinearBlend between two colors by the amount defined by progress variable + // left - the color to start the blend at + // right - the color to end the blend at + // progress - (0.0 - 1.0) value where 0.0 will return left and 1.0 will return right + // and a value between will blend the color weighted linearly between them + // ------------------------------------------------------------------------ + template static HsbColor LinearBlend(const HsbColor& left, + const HsbColor& right, + float progress) + { + return HsbColor(T_NEOHUEBLEND::HueBlend(left.H, right.H, progress), + left.S + ((right.S - left.S) * progress), + left.B + ((right.B - left.B) * progress)); + } + + // ------------------------------------------------------------------------ + // BilinearBlend between four colors by the amount defined by 2d variable + // c00 - upper left quadrant color + // c01 - upper right quadrant color + // c10 - lower left quadrant color + // c11 - lower right quadrant color + // x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space + // y - unit value (0.0 - 1.0) that defines the blend progress in vertical space + // ------------------------------------------------------------------------ + template static HsbColor BilinearBlend(const HsbColor& c00, + const HsbColor& c01, + const HsbColor& c10, + const HsbColor& c11, + float x, + float y) + { + float v00 = (1.0f - x) * (1.0f - y); + float v10 = x * (1.0f - y); + float v01 = (1.0f - x) * y; + float v11 = x * y; + + return HsbColor( + T_NEOHUEBLEND::HueBlend( + T_NEOHUEBLEND::HueBlend(c00.H, c10.H, x), + T_NEOHUEBLEND::HueBlend(c01.H, c11.H, x), + y), + c00.S * v00 + c10.S * v10 + c01.S * v01 + c11.S * v11, + c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11); + }; + + // ------------------------------------------------------------------------ + // Hue, Saturation, Brightness color members + // ------------------------------------------------------------------------ + + float H; + float S; + float B; +}; + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/HslColor.cpp b/lib/NeoPixelBus_by_Makuna/src/internal/HslColor.cpp new file mode 100644 index 0000000..ce9b238 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/HslColor.cpp @@ -0,0 +1,72 @@ +/*------------------------------------------------------------------------- +HslColor provides a color object that can be directly consumed by NeoPixelBus + + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#include "RgbColor.h" +#include "HslColor.h" + + +HslColor::HslColor(const RgbColor& color) +{ + // convert colors to float between (0.0 - 1.0) + float r = color.R / 255.0f; + float g = color.G / 255.0f; + float b = color.B / 255.0f; + + float max = (r > g && r > b) ? r : (g > b) ? g : b; + float min = (r < g && r < b) ? r : (g < b) ? g : b; + + float h, s, l; + l = (max + min) / 2.0f; + + if (max == min) + { + h = s = 0.0f; + } + else + { + float d = max - min; + s = (l > 0.5f) ? d / (2.0f - (max + min)) : d / (max + min); + + if (r > g && r > b) + { + h = (g - b) / d + (g < b ? 6.0f : 0.0f); + } + else if (g > b) + { + h = (b - r) / d + 2.0f; + } + else + { + h = (r - g) / d + 4.0f; + } + h /= 6.0f; + } + + H = h; + S = s; + L = l; +} diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/HslColor.h b/lib/NeoPixelBus_by_Makuna/src/internal/HslColor.h new file mode 100644 index 0000000..f6988bd --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/HslColor.h @@ -0,0 +1,113 @@ +/*------------------------------------------------------------------------- +HslColor provides a color object that can be directly consumed by NeoPixelBus + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +#include + +// ------------------------------------------------------------------------ +// HslColor represents a color object that is represented by Hue, Saturation, Lightness +// component values. It contains helpful color routines to manipulate the +// color. +// ------------------------------------------------------------------------ +struct HslColor +{ + + // ------------------------------------------------------------------------ + // Construct a HslColor using H, S, L values (0.0 - 1.0) + // L should be limited to between (0.0 - 0.5) + // ------------------------------------------------------------------------ + HslColor(float h, float s, float l) : + H(h), S(s), L(l) + { + }; + + // ------------------------------------------------------------------------ + // Construct a HslColor using RgbColor + // ------------------------------------------------------------------------ + HslColor(const RgbColor& color); + + // ------------------------------------------------------------------------ + // Construct a HslColor that will have its values set in latter operations + // CAUTION: The H,S,L members are not initialized and may not be consistent + // ------------------------------------------------------------------------ + HslColor() + { + }; + + // ------------------------------------------------------------------------ + // LinearBlend between two colors by the amount defined by progress variable + // left - the color to start the blend at + // right - the color to end the blend at + // progress - (0.0 - 1.0) value where 0.0 will return left and 1.0 will return right + // and a value between will blend the color weighted linearly between them + // ------------------------------------------------------------------------ + template static HslColor LinearBlend(const HslColor& left, + const HslColor& right, + float progress) + { + return HslColor(T_NEOHUEBLEND::HueBlend(left.H, right.H, progress), + left.S + ((right.S - left.S) * progress), + left.L + ((right.L - left.L) * progress)); + }; + + // ------------------------------------------------------------------------ + // BilinearBlend between four colors by the amount defined by 2d variable + // c00 - upper left quadrant color + // c01 - upper right quadrant color + // c10 - lower left quadrant color + // c11 - lower right quadrant color + // x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space + // y - unit value (0.0 - 1.0) that defines the blend progress in vertical space + // ------------------------------------------------------------------------ + template static HslColor BilinearBlend(const HslColor& c00, + const HslColor& c01, + const HslColor& c10, + const HslColor& c11, + float x, + float y) + { + float v00 = (1.0f - x) * (1.0f - y); + float v10 = x * (1.0f - y); + float v01 = (1.0f - x) * y; + float v11 = x * y; + + return HslColor( + T_NEOHUEBLEND::HueBlend( + T_NEOHUEBLEND::HueBlend(c00.H, c10.H, x), + T_NEOHUEBLEND::HueBlend(c01.H, c11.H, x), + y), + c00.S * v00 + c10.S * v10 + c01.S * v01 + c11.S * v11, + c00.L * v00 + c10.L * v10 + c01.L * v01 + c11.L * v11); + }; + + // ------------------------------------------------------------------------ + // Hue, Saturation, Lightness color members + // ------------------------------------------------------------------------ + float H; + float S; + float L; +}; + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColor.cpp b/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColor.cpp new file mode 100644 index 0000000..018d58f --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColor.cpp @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------- +This file contains the HtmlColor implementation + +Written by Unai Uribarri + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#include "HtmlColor.h" + +static inline char hexdigit(uint8_t v) +{ + return v + (v < 10 ? '0' : 'a' - 10); +} + + +size_t HtmlColor::ToNumericalString(char* buf, size_t bufSize) const +{ + size_t bufLen = bufSize - 1; + + if (bufLen-- > 0) + { + if (bufLen > 0) + { + buf[0] = '#'; + } + + uint32_t color = Color; + for (uint8_t indexDigit = 6; indexDigit > 0; indexDigit--) + { + if (bufLen > indexDigit) + { + buf[indexDigit] = hexdigit(color & 0x0000000f); + } + color >>= 4; + } + + buf[(bufLen < 7 ? bufLen : 7)] = 0; + } + return 7; +} diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColor.h b/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColor.h new file mode 100644 index 0000000..238d4ac --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColor.h @@ -0,0 +1,340 @@ +/*------------------------------------------------------------------------- +HtmlColor provides a color object that can be directly consumed by NeoPixelBus + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +#include +#include "RgbColor.h" + +#define MAX_HTML_COLOR_NAME_LEN 21 + +#ifndef pgm_read_ptr +// ESP8266 doesn't define this macro +#define pgm_read_ptr(addr) (*reinterpret_cast(addr)) +#endif + +#ifndef countof +#define countof(array) (sizeof(array)/sizeof(array[0])) +#endif + +// ------------------------------------------------------------------------ +// HtmlColorPair represents an association between a name and a HTML color code +// ------------------------------------------------------------------------ +struct HtmlColorPair +{ + PGM_P Name; + uint32_t Color; +}; + +// ------------------------------------------------------------------------ +// HtmlShortColorNames is a template class used for Parse and ToString +// ------------------------------------------------------------------------ +class HtmlShortColorNames +{ +public: + static const HtmlColorPair* Pair(uint8_t index); + static uint8_t Count(); +}; + +// ------------------------------------------------------------------------ +// HtmlColorNames is a template class used for Parse and ToString +// ------------------------------------------------------------------------ +class HtmlColorNames +{ +public: + static const HtmlColorPair* Pair(uint8_t index); + static uint8_t Count(); +}; + +// ------------------------------------------------------------------------ +// HtmlColor represents a color object that is represented by a single uint32 +// value. It contains minimal routines and used primarily as a helper to +// initialize other color objects +// ------------------------------------------------------------------------ +struct HtmlColor +{ + // ------------------------------------------------------------------------ + // Construct a HtmlColor using a single value (0-0xffffff) + // This works well for hexidecimal color definitions + // 0xff0000 = red, 0x00ff00 = green, and 0x0000ff = blue + // ------------------------------------------------------------------------ + HtmlColor(uint32_t color) : + Color(color) + { + }; + + // ------------------------------------------------------------------------ + // Construct a HtmlColor using RgbColor + // ------------------------------------------------------------------------ + HtmlColor(const RgbColor& color) + { + Color = (uint32_t)color.R << 16 | (uint32_t)color.G << 8 | (uint32_t)color.B; + } + + // ------------------------------------------------------------------------ + // Construct a HtmlColor that will have its values set in latter operations + // CAUTION: The Color member is not initialized and may not be consistent + // ------------------------------------------------------------------------ + HtmlColor() + { + }; + + // ------------------------------------------------------------------------ + // Comparison operators + // ------------------------------------------------------------------------ + bool operator==(const HtmlColor& other) const + { + return (Color == other.Color); + }; + + bool operator!=(const HtmlColor& other) const + { + return !(*this == other); + }; + + // ------------------------------------------------------------------------ + // Parse a HTML4/CSS3 color name + // T_HTMLCOLORNAMES - template class that defines the collection of names + // name - the color name + // nameSize - the max size of name to check + // + // returns - zero if failed, or the number of chars parsed + // + // It will stop parsing name when a null terminator is reached, + // nameSize is reached, no match is found in the name/color pair table, or + // a non-alphanumeric is read like seperators or whitespace. + // + // It also accepts 3 or 6 digit hexadecimal notation (#rgb or #rrggbb), + // but it doesn't accept RGB, RGBA nor HSL values. + // + // See https://www.w3.org/TR/css3-color/#SRGB + // + // name must point to the first non-whitespace character to be parsed + // parsing will stop at the first non-alpha numeric + // + // Name MUST NOT be a PROGMEM pointer + // + // examples: + // Parse(buff, buffSize); + // Parse(buff, buffSize); + // ------------------------------------------------------------------------ + + template size_t Parse(const char* name, size_t nameSize) + { + if (nameSize > 0) + { + if (name[0] == '#') + { + // Parse an hexadecimal notation "#rrbbgg" or "#rgb" + // + uint8_t temp[6]; // stores preconverted chars to hex values + uint8_t tempSize = 0; + + for (uint8_t indexChar = 1; indexChar < nameSize && indexChar < 8; ++indexChar) + { + char c = name[indexChar]; + if (c >= '0' && c <= '9') + { + c -= '0'; + } + else + { + // Convert a letter to lower case (only for ASCII letters) + // It's faster & smaller than tolower() + c |= 32; + if (c >= 'a' && c <= 'f') + { + c = c - 'a' + 10; + } + else + { + // we found an non hexidecimal char + // which could be null, deliminator, or other spacing + break; + } + } + + temp[tempSize] = c; + tempSize++; + } + + if (tempSize != 3 && tempSize != 6) + { + // invalid count of numerical chars + return 0; + } + else + { + uint32_t color = 0; + for (uint8_t indexChar = 0; indexChar < tempSize; ++indexChar) + { + color = color * 16 + temp[indexChar]; + if (tempSize == 3) + { + // 3 digit hexadecimal notation can be supported easily + // duplicating digits. + color = color * 16 + temp[indexChar]; + } + } + + Color = color; + return tempSize; + } + } + else + { + // parse a standard name for the color + // + + // the normal list is small enough a binary search isn't interesting, + for (uint8_t indexName = 0; indexName < T_HTMLCOLORNAMES::Count(); ++indexName) + { + const HtmlColorPair* colorPair = T_HTMLCOLORNAMES::Pair(indexName); + PGM_P searchName = reinterpret_cast(pgm_read_ptr(&(colorPair->Name))); + size_t str1Size = nameSize; + const char* str1 = name; + const char* str2P = searchName; + + uint16_t result; + + while (str1Size > 0) + { + char ch1 = tolower(*str1++); + char ch2 = tolower(pgm_read_byte(str2P++)); + result = ch1 - ch2; + if (result != 0 || ch2 == '\0') + { + if (ch2 == '\0' && !isalnum(ch1)) + { + // the string continues but is not part of a + // valid color name, + // ends in white space, deliminator, etc + result = 0; + } + break; + } + result = -1; // have not reached the end of searchName; + str1Size--; + } + + if (result == 0) + { + Color = pgm_read_dword(&colorPair->Color); + return nameSize - str1Size; + } + } + } + } + + return 0; + } + + template size_t Parse(const char* name) + { + return Parse(name, MAX_HTML_COLOR_NAME_LEN + 1); + } + + template size_t Parse(String const &name) + { + return Parse(name.c_str(), name.length() + 1); + } + + // ------------------------------------------------------------------------ + // Converts this color code to its HTML4/CSS3 name + // T_HTMLCOLORNAMES - template class that defines the collection of names + // buf - buffer to write the string + // bufSize - actual size of buf array + // + // It returns the number of chars required not including the NUL terminator. + // + // If there is not enough space in the buffer, it will write as many + // characters as allowed and will always finish the buffer with a NUL char + // + // examples: + // ToString(buf, bufSize); + // ToString(buf, bufSize); + // ------------------------------------------------------------------------ + + template size_t ToString(char* buf, size_t bufSize) const + { + // search for a color value/name pairs first + for (uint8_t indexName = 0; indexName < T_HTMLCOLORNAMES::Count(); ++indexName) + { + const HtmlColorPair* colorPair = T_HTMLCOLORNAMES::Pair(indexName); + if (pgm_read_dword(&colorPair->Color) == Color) + { + PGM_P name = (PGM_P)pgm_read_ptr(&colorPair->Name); + strncpy_P(buf, name, bufSize); + return strlen_P(name); + } + } + + // no color name pair match, convert using numerical format + return ToNumericalString(buf, bufSize); + } + + // ------------------------------------------------------------------------ + // Converts this color code to its HTML4/CSS3 numerical name + // + // buf - buffer to write the string + // bufSize - actual size of buf array + // + // It returns the number of chars required not including the NUL terminator. + // + // If there is not enough space in the buffer, it will write as many + // characters as allowed and will always finish the buffer with a NUL char + // ------------------------------------------------------------------------ + + size_t ToNumericalString(char* buf, size_t bufSize) const; + + // ------------------------------------------------------------------------ + // BilinearBlend between four colors by the amount defined by 2d variable + // c00 - upper left quadrant color + // c01 - upper right quadrant color + // c10 - lower left quadrant color + // c11 - lower right quadrant color + // x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space + // y - unit value (0.0 - 1.0) that defines the blend progress in vertical space + // ------------------------------------------------------------------------ + + static HtmlColor BilinearBlend(const HtmlColor& c00, + const HtmlColor& c01, + const HtmlColor& c10, + const HtmlColor& c11, + float x, + float y) + { + return RgbColor::BilinearBlend(c00, c01, c10, c11, x, y); + } + + // ------------------------------------------------------------------------ + // Color member (0-0xffffff) where + // 0xff0000 is red + // 0x00ff00 is green + // 0x0000ff is blue + // ------------------------------------------------------------------------ + uint32_t Color; +}; + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNameStrings.cpp b/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNameStrings.cpp new file mode 100644 index 0000000..87dda4b --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNameStrings.cpp @@ -0,0 +1,178 @@ +/*------------------------------------------------------------------------- +HtmlColorNameStrings provides the implemenation of the color string names + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#include "HtmlColorNameStrings.h" + +/* HTML4 color names */ +const char c_HtmlNameAqua[] PROGMEM = "aqua"; +const char c_HtmlNameBlack[] PROGMEM = "black"; +const char c_HtmlNameBlue[] PROGMEM = "blue"; +const char c_HtmlNameFuchsia[] PROGMEM = "fuchsia"; +const char c_HtmlNameGray[] PROGMEM = "gray"; +const char c_HtmlNameGreen[] PROGMEM = "green"; +const char c_HtmlNameLime[] PROGMEM = "lime"; +const char c_HtmlNameMaroon[] PROGMEM = "maroon"; +const char c_HtmlNameNavy[] PROGMEM = "navy"; +const char c_HtmlNameOlive[] PROGMEM = "olive"; +const char c_HtmlNameOrange[] PROGMEM = "orange"; +const char c_HtmlNamePurple[] PROGMEM = "purple"; +const char c_HtmlNameRed[] PROGMEM = "red"; +const char c_HtmlNameSilver[] PROGMEM = "silver"; +const char c_HtmlNameTeal[] PROGMEM = "teal"; +const char c_HtmlNameWhite[] PROGMEM = "white"; +const char c_HtmlNameYellow[] PROGMEM = "yellow"; + +/* Additional CSS3 color names */ +const char c_HtmlNameAliceBlue[] PROGMEM = "aliceblue"; +const char c_HtmlNameAntiqueWhite[] PROGMEM = "antiquewhite"; +const char c_HtmlNameAquamarine[] PROGMEM = "aquamarine"; +const char c_HtmlNameAzure[] PROGMEM = "azure"; +const char c_HtmlNameBeige[] PROGMEM = "beige"; +const char c_HtmlNameBisque[] PROGMEM = "bisque"; +const char c_HtmlNameBlanchedAlmond[] PROGMEM = "blanchedalmond"; +const char c_HtmlNameBlueViolet[] PROGMEM = "blueviolet"; +const char c_HtmlNameBrown[] PROGMEM = "brown"; +const char c_HtmlNameBurlyWood[] PROGMEM = "burlywood"; +const char c_HtmlNameCadetBlue[] PROGMEM = "cadetblue"; +const char c_HtmlNameChartreuse[] PROGMEM = "chartreuse"; +const char c_HtmlNameChocolate[] PROGMEM = "chocolate"; +const char c_HtmlNameCoral[] PROGMEM = "coral"; +const char c_HtmlNameCornflowerBlue[] PROGMEM = "cornflowerblue"; +const char c_HtmlNameCornsilk[] PROGMEM = "cornsilk"; +const char c_HtmlNameCrimson[] PROGMEM = "crimson"; +const char c_HtmlNameCyan[] PROGMEM = "cyan"; +const char c_HtmlNameDarkBlue[] PROGMEM = "darkblue"; +const char c_HtmlNameDarkCyan[] PROGMEM = "darkcyan"; +const char c_HtmlNameDarkGoldenrod[] PROGMEM = "darkgoldenrod"; +const char c_HtmlNameDarkGray[] PROGMEM = "darkgray"; +const char c_HtmlNameDarkGreen[] PROGMEM = "darkgreen"; +const char c_HtmlNameDarkGrey[] PROGMEM = "darkgrey"; +const char c_HtmlNameDarkKhaki[] PROGMEM = "darkkhaki"; +const char c_HtmlNameDarkMagenta[] PROGMEM = "darkmagenta"; +const char c_HtmlNameDarkOliveGreen[] PROGMEM = "darkolivegreen"; +const char c_HtmlNameDarkOrange[] PROGMEM = "darkorange"; +const char c_HtmlNameDarkOrchid[] PROGMEM = "darkorchid"; +const char c_HtmlNameDarkRed[] PROGMEM = "darkred"; +const char c_HtmlNameDarkSalmon[] PROGMEM = "darksalmon"; +const char c_HtmlNameDarkSeaGreen[] PROGMEM = "darkseagreen"; +const char c_HtmlNameDarkSlateBlue[] PROGMEM = "darkslateblue"; +const char c_HtmlNameDarkSlateGray[] PROGMEM = "darkslategray"; +const char c_HtmlNameDarkSlateGrey[] PROGMEM = "darkslategrey"; +const char c_HtmlNameDarkTurquoise[] PROGMEM = "darkturquoise"; +const char c_HtmlNameDarkViolet[] PROGMEM = "darkviolet"; +const char c_HtmlNameDeepPink[] PROGMEM = "deeppink"; +const char c_HtmlNameDeepSkyBlue[] PROGMEM = "deepskyblue"; +const char c_HtmlNameDimGray[] PROGMEM = "dimgray"; +const char c_HtmlNameDimGrey[] PROGMEM = "dimgrey"; +const char c_HtmlNameDodgerBlue[] PROGMEM = "dodgerblue"; +const char c_HtmlNameFirebrick[] PROGMEM = "firebrick"; +const char c_HtmlNameFloralWhite[] PROGMEM = "floralwhite"; +const char c_HtmlNameForestGreen[] PROGMEM = "forestgreen"; +const char c_HtmlNameGainsboro[] PROGMEM = "gainsboro"; +const char c_HtmlNameGhostWhite[] PROGMEM = "ghostwhite"; +const char c_HtmlNameGold[] PROGMEM = "gold"; +const char c_HtmlNameGoldenrod[] PROGMEM = "goldenrod"; +const char c_HtmlNameGreenYellow[] PROGMEM = "greenyellow"; +const char c_HtmlNameGrey[] PROGMEM = "grey"; +const char c_HtmlNameHoneydew[] PROGMEM = "honeydew"; +const char c_HtmlNameHotPink[] PROGMEM = "hotpink"; +const char c_HtmlNameIndianRed[] PROGMEM = "indianred"; +const char c_HtmlNameIndigo[] PROGMEM = "indigo"; +const char c_HtmlNameIvory[] PROGMEM = "ivory"; +const char c_HtmlNameKhaki[] PROGMEM = "khaki"; +const char c_HtmlNameLavender[] PROGMEM = "lavender"; +const char c_HtmlNameLavenderBlush[] PROGMEM = "lavenderblush"; +const char c_HtmlNameLawnGreen[] PROGMEM = "lawngreen"; +const char c_HtmlNameLemonChiffon[] PROGMEM = "lemonchiffon"; +const char c_HtmlNameLightBlue[] PROGMEM = "lightblue"; +const char c_HtmlNameLightCoral[] PROGMEM = "lightcoral"; +const char c_HtmlNameLightCyan[] PROGMEM = "lightcyan"; +const char c_HtmlNameLightGoldenrodYellow[] PROGMEM = "lightgoldenrodyellow"; +const char c_HtmlNameLightGray[] PROGMEM = "lightgray"; +const char c_HtmlNameLightGreen[] PROGMEM = "lightgreen"; +const char c_HtmlNameLightGrey[] PROGMEM = "lightgrey"; +const char c_HtmlNameLightPink[] PROGMEM = "lightpink"; +const char c_HtmlNameLightSalmon[] PROGMEM = "lightsalmon"; +const char c_HtmlNameLightSeaGreen[] PROGMEM = "lightseagreen"; +const char c_HtmlNameLightSkyBlue[] PROGMEM = "lightskyblue"; +const char c_HtmlNameLightSlateGray[] PROGMEM = "lightslategray"; +const char c_HtmlNameLightSlateGrey[] PROGMEM = "lightslategrey"; +const char c_HtmlNameLightSteelBlue[] PROGMEM = "lightsteelblue"; +const char c_HtmlNameLightYellow[] PROGMEM = "lightyellow"; +const char c_HtmlNameLimeGreen[] PROGMEM = "limegreen"; +const char c_HtmlNameLinen[] PROGMEM = "linen"; +const char c_HtmlNameMagenta[] PROGMEM = "magenta"; +const char c_HtmlNameMediumAquamarine[] PROGMEM = "mediumaquamarine"; +const char c_HtmlNameMediumBlue[] PROGMEM = "mediumblue"; +const char c_HtmlNameMediumOrchid[] PROGMEM = "mediumorchid"; +const char c_HtmlNameMediumPurple[] PROGMEM = "mediumpurple"; +const char c_HtmlNameMediumSeagreen[] PROGMEM = "mediumseagreen"; +const char c_HtmlNameMediumSlateBlue[] PROGMEM = "mediumslateblue"; +const char c_HtmlNameMediumSpringGreen[] PROGMEM = "mediumspringgreen"; +const char c_HtmlNameMediumTurquoise[] PROGMEM = "mediumturquoise"; +const char c_HtmlNameMediumVioletRed[] PROGMEM = "mediumvioletred"; +const char c_HtmlNameMidnightBlue[] PROGMEM = "midnightblue"; +const char c_HtmlNameMintCream[] PROGMEM = "mintcream"; +const char c_HtmlNameMistyRose[] PROGMEM = "mistyrose"; +const char c_HtmlNameMoccasin[] PROGMEM = "moccasin"; +const char c_HtmlNameNavajoWhite[] PROGMEM = "navajowhite"; +const char c_HtmlNameOldLace[] PROGMEM = "oldlace"; +const char c_HtmlNameOliveDrab[] PROGMEM = "olivedrab"; +const char c_HtmlNameOrangeRed[] PROGMEM = "orangered"; +const char c_HtmlNameOrchid[] PROGMEM = "orchid"; +const char c_HtmlNamePaleGoldenrod[] PROGMEM = "palegoldenrod"; +const char c_HtmlNamePaleGreen[] PROGMEM = "palegreen"; +const char c_HtmlNamePaleTurquoise[] PROGMEM = "paleturquoise"; +const char c_HtmlNamePaleVioletRed[] PROGMEM = "palevioletred"; +const char c_HtmlNamePapayaWhip[] PROGMEM = "papayawhip"; +const char c_HtmlNamePeachPuff[] PROGMEM = "peachpuff"; +const char c_HtmlNamePeru[] PROGMEM = "peru"; +const char c_HtmlNamePink[] PROGMEM = "pink"; +const char c_HtmlNamePlum[] PROGMEM = "plum"; +const char c_HtmlNamePowderBlue[] PROGMEM = "powderblue"; +const char c_HtmlNameRosyBrown[] PROGMEM = "rosybrown"; +const char c_HtmlNameRoyalBlue[] PROGMEM = "royalblue"; +const char c_HtmlNameSaddleBrown[] PROGMEM = "saddlebrown"; +const char c_HtmlNameSalmon[] PROGMEM = "salmon"; +const char c_HtmlNameSandyBrown[] PROGMEM = "sandybrown"; +const char c_HtmlNameSeaGreen[] PROGMEM = "seagreen"; +const char c_HtmlNameSeaShell[] PROGMEM = "seashell"; +const char c_HtmlNameSienna[] PROGMEM = "sienna"; +const char c_HtmlNameSkyBlue[] PROGMEM = "skyblue"; +const char c_HtmlNameSlateBlue[] PROGMEM = "slateblue"; +const char c_HtmlNameSlateGray[] PROGMEM = "slategray"; +const char c_HtmlNameSlateGrey[] PROGMEM = "slategrey"; +const char c_HtmlNameSnow[] PROGMEM = "snow"; +const char c_HtmlNameSpringGreen[] PROGMEM = "springgreen"; +const char c_HtmlNameSteelBlue[] PROGMEM = "steelblue"; +const char c_HtmlNameTan[] PROGMEM = "tan"; +const char c_HtmlNameThistle[] PROGMEM = "thistle"; +const char c_HtmlNameTomato[] PROGMEM = "tomato"; +const char c_HtmlNameTurquoise[] PROGMEM = "turquoise"; +const char c_HtmlNameViolet[] PROGMEM = "violet"; +const char c_HtmlNameWheat[] PROGMEM = "wheat"; +const char c_HtmlNameWhiteSmoke[] PROGMEM = "whitesmoke"; +const char c_HtmlNameYellowGreen[] PROGMEM = "yellowgreen"; \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNameStrings.h b/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNameStrings.h new file mode 100644 index 0000000..86ffcf4 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNameStrings.h @@ -0,0 +1,180 @@ +/*------------------------------------------------------------------------- +HtmlColorNameStrings provides the declaration of the color string names + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#include + +/* HTML4 color names */ +extern const char c_HtmlNameAqua[] PROGMEM; +extern const char c_HtmlNameBlack[] PROGMEM; +extern const char c_HtmlNameBlue[] PROGMEM; +extern const char c_HtmlNameFuchsia[] PROGMEM; +extern const char c_HtmlNameGray[] PROGMEM; +extern const char c_HtmlNameGreen[] PROGMEM; +extern const char c_HtmlNameLime[] PROGMEM; +extern const char c_HtmlNameMaroon[] PROGMEM; +extern const char c_HtmlNameNavy[] PROGMEM; +extern const char c_HtmlNameOlive[] PROGMEM; +extern const char c_HtmlNameOrange[] PROGMEM; +extern const char c_HtmlNamePurple[] PROGMEM; +extern const char c_HtmlNameRed[] PROGMEM; +extern const char c_HtmlNameSilver[] PROGMEM; +extern const char c_HtmlNameTeal[] PROGMEM; +extern const char c_HtmlNameWhite[] PROGMEM; +extern const char c_HtmlNameYellow[] PROGMEM; + +/* Additional CSS3 color names */ +extern const char c_HtmlNameAliceBlue[] PROGMEM; +extern const char c_HtmlNameAntiqueWhite[] PROGMEM; +extern const char c_HtmlNameAquamarine[] PROGMEM; +extern const char c_HtmlNameAzure[] PROGMEM; +extern const char c_HtmlNameBeige[] PROGMEM; +extern const char c_HtmlNameBisque[] PROGMEM; +extern const char c_HtmlNameBlanchedAlmond[] PROGMEM; +extern const char c_HtmlNameBlueViolet[] PROGMEM; +extern const char c_HtmlNameBrown[] PROGMEM; +extern const char c_HtmlNameBurlyWood[] PROGMEM; +extern const char c_HtmlNameCadetBlue[] PROGMEM; +extern const char c_HtmlNameChartreuse[] PROGMEM; +extern const char c_HtmlNameChocolate[] PROGMEM; +extern const char c_HtmlNameCoral[] PROGMEM; +extern const char c_HtmlNameCornflowerBlue[] PROGMEM; +extern const char c_HtmlNameCornsilk[] PROGMEM; +extern const char c_HtmlNameCrimson[] PROGMEM; +extern const char c_HtmlNameCyan[] PROGMEM; +extern const char c_HtmlNameDarkBlue[] PROGMEM; +extern const char c_HtmlNameDarkCyan[] PROGMEM; +extern const char c_HtmlNameDarkGoldenrod[] PROGMEM; +extern const char c_HtmlNameDarkGray[] PROGMEM; +extern const char c_HtmlNameDarkGreen[] PROGMEM; +extern const char c_HtmlNameDarkGrey[] PROGMEM; +extern const char c_HtmlNameDarkKhaki[] PROGMEM; +extern const char c_HtmlNameDarkMagenta[] PROGMEM; +extern const char c_HtmlNameDarkOliveGreen[] PROGMEM; +extern const char c_HtmlNameDarkOrange[] PROGMEM; +extern const char c_HtmlNameDarkOrchid[] PROGMEM; +extern const char c_HtmlNameDarkRed[] PROGMEM; +extern const char c_HtmlNameDarkSalmon[] PROGMEM; +extern const char c_HtmlNameDarkSeaGreen[] PROGMEM; +extern const char c_HtmlNameDarkSlateBlue[] PROGMEM; +extern const char c_HtmlNameDarkSlateGray[] PROGMEM; +extern const char c_HtmlNameDarkSlateGrey[] PROGMEM; +extern const char c_HtmlNameDarkTurquoise[] PROGMEM; +extern const char c_HtmlNameDarkViolet[] PROGMEM; +extern const char c_HtmlNameDeepPink[] PROGMEM; +extern const char c_HtmlNameDeepSkyBlue[] PROGMEM; +extern const char c_HtmlNameDimGray[] PROGMEM; +extern const char c_HtmlNameDimGrey[] PROGMEM; +extern const char c_HtmlNameDodgerBlue[] PROGMEM; +extern const char c_HtmlNameFirebrick[] PROGMEM; +extern const char c_HtmlNameFloralWhite[] PROGMEM; +extern const char c_HtmlNameForestGreen[] PROGMEM; +extern const char c_HtmlNameGainsboro[] PROGMEM; +extern const char c_HtmlNameGhostWhite[] PROGMEM; +extern const char c_HtmlNameGold[] PROGMEM; +extern const char c_HtmlNameGoldenrod[] PROGMEM; +extern const char c_HtmlNameGreenYellow[] PROGMEM; +extern const char c_HtmlNameGrey[] PROGMEM; +extern const char c_HtmlNameHoneydew[] PROGMEM; +extern const char c_HtmlNameHotPink[] PROGMEM; +extern const char c_HtmlNameIndianRed[] PROGMEM; +extern const char c_HtmlNameIndigo[] PROGMEM; +extern const char c_HtmlNameIvory[] PROGMEM; +extern const char c_HtmlNameKhaki[] PROGMEM; +extern const char c_HtmlNameLavender[] PROGMEM; +extern const char c_HtmlNameLavenderBlush[] PROGMEM; +extern const char c_HtmlNameLawnGreen[] PROGMEM; +extern const char c_HtmlNameLemonChiffon[] PROGMEM; +extern const char c_HtmlNameLightBlue[] PROGMEM; +extern const char c_HtmlNameLightCoral[] PROGMEM; +extern const char c_HtmlNameLightCyan[] PROGMEM; +extern const char c_HtmlNameLightGoldenrodYellow[] PROGMEM; +extern const char c_HtmlNameLightGray[] PROGMEM; +extern const char c_HtmlNameLightGreen[] PROGMEM; +extern const char c_HtmlNameLightGrey[] PROGMEM; +extern const char c_HtmlNameLightPink[] PROGMEM; +extern const char c_HtmlNameLightSalmon[] PROGMEM; +extern const char c_HtmlNameLightSeaGreen[] PROGMEM; +extern const char c_HtmlNameLightSkyBlue[] PROGMEM; +extern const char c_HtmlNameLightSlateGray[] PROGMEM; +extern const char c_HtmlNameLightSlateGrey[] PROGMEM; +extern const char c_HtmlNameLightSteelBlue[] PROGMEM; +extern const char c_HtmlNameLightYellow[] PROGMEM; +extern const char c_HtmlNameLimeGreen[] PROGMEM; +extern const char c_HtmlNameLinen[] PROGMEM; +extern const char c_HtmlNameMagenta[] PROGMEM; +extern const char c_HtmlNameMediumAquamarine[] PROGMEM; +extern const char c_HtmlNameMediumBlue[] PROGMEM; +extern const char c_HtmlNameMediumOrchid[] PROGMEM; +extern const char c_HtmlNameMediumPurple[] PROGMEM; +extern const char c_HtmlNameMediumSeagreen[] PROGMEM; +extern const char c_HtmlNameMediumSlateBlue[] PROGMEM; +extern const char c_HtmlNameMediumSpringGreen[] PROGMEM; +extern const char c_HtmlNameMediumTurquoise[] PROGMEM; +extern const char c_HtmlNameMediumVioletRed[] PROGMEM; +extern const char c_HtmlNameMidnightBlue[] PROGMEM; +extern const char c_HtmlNameMintCream[] PROGMEM; +extern const char c_HtmlNameMistyRose[] PROGMEM; +extern const char c_HtmlNameMoccasin[] PROGMEM; +extern const char c_HtmlNameNavajoWhite[] PROGMEM; +extern const char c_HtmlNameOldLace[] PROGMEM; +extern const char c_HtmlNameOliveDrab[] PROGMEM; +extern const char c_HtmlNameOrangeRed[] PROGMEM; +extern const char c_HtmlNameOrchid[] PROGMEM; +extern const char c_HtmlNamePaleGoldenrod[] PROGMEM; +extern const char c_HtmlNamePaleGreen[] PROGMEM; +extern const char c_HtmlNamePaleTurquoise[] PROGMEM; +extern const char c_HtmlNamePaleVioletRed[] PROGMEM; +extern const char c_HtmlNamePapayaWhip[] PROGMEM; +extern const char c_HtmlNamePeachPuff[] PROGMEM; +extern const char c_HtmlNamePeru[] PROGMEM; +extern const char c_HtmlNamePink[] PROGMEM; +extern const char c_HtmlNamePlum[] PROGMEM; +extern const char c_HtmlNamePowderBlue[] PROGMEM; +extern const char c_HtmlNameRosyBrown[] PROGMEM; +extern const char c_HtmlNameRoyalBlue[] PROGMEM; +extern const char c_HtmlNameSaddleBrown[] PROGMEM; +extern const char c_HtmlNameSalmon[] PROGMEM; +extern const char c_HtmlNameSandyBrown[] PROGMEM; +extern const char c_HtmlNameSeaGreen[] PROGMEM; +extern const char c_HtmlNameSeaShell[] PROGMEM; +extern const char c_HtmlNameSienna[] PROGMEM; +extern const char c_HtmlNameSkyBlue[] PROGMEM; +extern const char c_HtmlNameSlateBlue[] PROGMEM; +extern const char c_HtmlNameSlateGray[] PROGMEM; +extern const char c_HtmlNameSlateGrey[] PROGMEM; +extern const char c_HtmlNameSnow[] PROGMEM; +extern const char c_HtmlNameSpringGreen[] PROGMEM; +extern const char c_HtmlNameSteelBlue[] PROGMEM; +extern const char c_HtmlNameTan[] PROGMEM; +extern const char c_HtmlNameThistle[] PROGMEM; +extern const char c_HtmlNameTomato[] PROGMEM; +extern const char c_HtmlNameTurquoise[] PROGMEM; +extern const char c_HtmlNameViolet[] PROGMEM; +extern const char c_HtmlNameWheat[] PROGMEM; +extern const char c_HtmlNameWhiteSmoke[] PROGMEM; +extern const char c_HtmlNameYellowGreen[] PROGMEM; \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNames.cpp b/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNames.cpp new file mode 100644 index 0000000..b1098ea --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorNames.cpp @@ -0,0 +1,188 @@ +/*------------------------------------------------------------------------- +HtmlColorNames provides a template class for access to the full name table + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#include "HtmlColor.h" +#include "HtmlColorNameStrings.h" + +static const HtmlColorPair c_ColorNames[] PROGMEM = { + { c_HtmlNameAliceBlue, 0xf0f8ff }, + { c_HtmlNameAntiqueWhite, 0xfaebd7 }, + { c_HtmlNameAqua, 0xffff }, + { c_HtmlNameAquamarine, 0x7fffd4 }, + { c_HtmlNameAzure, 0xf0ffff }, + { c_HtmlNameBeige, 0xf5f5dc }, + { c_HtmlNameBisque, 0xffe4c4 }, + { c_HtmlNameBlack, 0x0 }, + { c_HtmlNameBlanchedAlmond, 0xffebcd }, + { c_HtmlNameBlue, 0xff }, + { c_HtmlNameBlueViolet, 0x8a2be2 }, + { c_HtmlNameBrown, 0xa52a2a }, + { c_HtmlNameBurlyWood, 0xdeb887 }, + { c_HtmlNameCadetBlue, 0x5f9ea0 }, + { c_HtmlNameChartreuse, 0x7fff00 }, + { c_HtmlNameChocolate, 0xd2691e }, + { c_HtmlNameCoral, 0xff7f50 }, + { c_HtmlNameCornflowerBlue, 0x6495ed }, + { c_HtmlNameCornsilk, 0xfff8dc }, + { c_HtmlNameCrimson, 0xdc143c }, + { c_HtmlNameCyan, 0xffff }, + { c_HtmlNameDarkBlue, 0x8b }, + { c_HtmlNameDarkCyan, 0x8b8b }, + { c_HtmlNameDarkGoldenrod, 0xb8860b }, + { c_HtmlNameDarkGray, 0xa9a9a9 }, + { c_HtmlNameDarkGreen, 0x6400 }, + { c_HtmlNameDarkGrey, 0xa9a9a9 }, + { c_HtmlNameDarkKhaki, 0xbdb76b }, + { c_HtmlNameDarkMagenta, 0x8b008b }, + { c_HtmlNameDarkOliveGreen, 0x556b2f }, + { c_HtmlNameDarkOrange, 0xff8c00 }, + { c_HtmlNameDarkOrchid, 0x9932cc }, + { c_HtmlNameDarkRed, 0x8b0000 }, + { c_HtmlNameDarkSalmon, 0xe9967a }, + { c_HtmlNameDarkSeaGreen, 0x8fbc8f }, + { c_HtmlNameDarkSlateBlue, 0x483d8b }, + { c_HtmlNameDarkSlateGray, 0x2f4f4f }, + { c_HtmlNameDarkSlateGrey, 0x2f4f4f }, + { c_HtmlNameDarkTurquoise, 0xced1 }, + { c_HtmlNameDarkViolet, 0x9400d3 }, + { c_HtmlNameDeepPink, 0xff1493 }, + { c_HtmlNameDeepSkyBlue, 0xbfff }, + { c_HtmlNameDimGray, 0x696969 }, + { c_HtmlNameDimGrey, 0x696969 }, + { c_HtmlNameDodgerBlue, 0x1e90ff }, + { c_HtmlNameFirebrick, 0xb22222 }, + { c_HtmlNameFloralWhite, 0xfffaf0 }, + { c_HtmlNameForestGreen, 0x228b22 }, + { c_HtmlNameFuchsia, 0xff00ff }, + { c_HtmlNameGainsboro, 0xdcdcdc }, + { c_HtmlNameGhostWhite, 0xf8f8ff }, + { c_HtmlNameGold, 0xffd700 }, + { c_HtmlNameGoldenrod, 0xdaa520 }, + { c_HtmlNameGray, 0x808080 }, + { c_HtmlNameGreen, 0x8000 }, + { c_HtmlNameGreenYellow, 0xadff2f }, + { c_HtmlNameGrey, 0x808080 }, + { c_HtmlNameHoneydew, 0xf0fff0 }, + { c_HtmlNameHotPink, 0xff69b4 }, + { c_HtmlNameIndianRed, 0xcd5c5c }, + { c_HtmlNameIndigo, 0x4b0082 }, + { c_HtmlNameIvory, 0xfffff0 }, + { c_HtmlNameKhaki, 0xf0e68c }, + { c_HtmlNameLavender, 0xe6e6fa }, + { c_HtmlNameLavenderBlush, 0xfff0f5 }, + { c_HtmlNameLawnGreen, 0x7cfc00 }, + { c_HtmlNameLemonChiffon, 0xfffacd }, + { c_HtmlNameLightBlue, 0xadd8e6 }, + { c_HtmlNameLightCoral, 0xf08080 }, + { c_HtmlNameLightCyan, 0xe0ffff }, + { c_HtmlNameLightGoldenrodYellow, 0xfafad2 }, + { c_HtmlNameLightGray, 0xd3d3d3 }, + { c_HtmlNameLightGreen, 0x90ee90 }, + { c_HtmlNameLightGrey, 0xd3d3d3 }, + { c_HtmlNameLightPink, 0xffb6c1 }, + { c_HtmlNameLightSalmon, 0xffa07a }, + { c_HtmlNameLightSeaGreen, 0x20b2aa }, + { c_HtmlNameLightSkyBlue, 0x87cefa }, + { c_HtmlNameLightSlateGray, 0x778899 }, + { c_HtmlNameLightSlateGrey, 0x778899 }, + { c_HtmlNameLightSteelBlue, 0xb0c4de }, + { c_HtmlNameLightYellow, 0xffffe0 }, + { c_HtmlNameLime, 0xff00 }, + { c_HtmlNameLimeGreen, 0x32cd32 }, + { c_HtmlNameLinen, 0xfaf0e6 }, + { c_HtmlNameMagenta, 0xff00ff }, + { c_HtmlNameMaroon, 0x800000 }, + { c_HtmlNameMediumAquamarine, 0x66cdaa }, + { c_HtmlNameMediumBlue, 0xcd }, + { c_HtmlNameMediumOrchid, 0xba55d3 }, + { c_HtmlNameMediumPurple, 0x9370d8 }, + { c_HtmlNameMediumSeagreen, 0x3cb371 }, + { c_HtmlNameMediumSlateBlue, 0x7b68ee }, + { c_HtmlNameMediumSpringGreen, 0xfa9a }, + { c_HtmlNameMediumTurquoise, 0x48d1cc }, + { c_HtmlNameMediumVioletRed, 0xc71585 }, + { c_HtmlNameMidnightBlue, 0x191970 }, + { c_HtmlNameMintCream, 0xf5fffa }, + { c_HtmlNameMistyRose, 0xffe4e1 }, + { c_HtmlNameMoccasin, 0xffe4b5 }, + { c_HtmlNameNavajoWhite, 0xffdead }, + { c_HtmlNameNavy, 0x80 }, + { c_HtmlNameOldLace, 0xfdf5e6 }, + { c_HtmlNameOlive, 0x808000 }, + { c_HtmlNameOliveDrab, 0x6b8e23 }, + { c_HtmlNameOrange, 0xffa500 }, + { c_HtmlNameOrangeRed, 0xff4500 }, + { c_HtmlNameOrchid, 0xda70d6 }, + { c_HtmlNamePaleGoldenrod, 0xeee8aa }, + { c_HtmlNamePaleGreen, 0x98fb98 }, + { c_HtmlNamePaleTurquoise, 0xafeeee }, + { c_HtmlNamePaleVioletRed, 0xd87093 }, + { c_HtmlNamePapayaWhip, 0xffefd5 }, + { c_HtmlNamePeachPuff, 0xffdab9 }, + { c_HtmlNamePeru, 0xcd853f }, + { c_HtmlNamePink, 0xffc0cb }, + { c_HtmlNamePlum, 0xdda0dd }, + { c_HtmlNamePowderBlue, 0xb0e0e6 }, + { c_HtmlNamePurple, 0x800080 }, + { c_HtmlNameRed, 0xff0000 }, + { c_HtmlNameRosyBrown, 0xbc8f8f }, + { c_HtmlNameRoyalBlue, 0x4169e1 }, + { c_HtmlNameSaddleBrown, 0x8b4513 }, + { c_HtmlNameSalmon, 0xfa8072 }, + { c_HtmlNameSandyBrown, 0xf4a460 }, + { c_HtmlNameSeaGreen, 0x2e8b57 }, + { c_HtmlNameSeaShell, 0xfff5ee }, + { c_HtmlNameSienna, 0xa0522d }, + { c_HtmlNameSilver, 0xc0c0c0 }, + { c_HtmlNameSkyBlue, 0x87ceeb }, + { c_HtmlNameSlateBlue, 0x6a5acd }, + { c_HtmlNameSlateGray, 0x708090 }, + { c_HtmlNameSlateGrey, 0x708090 }, + { c_HtmlNameSnow, 0xfffafa }, + { c_HtmlNameSpringGreen, 0xff7f }, + { c_HtmlNameSteelBlue, 0x4682b4 }, + { c_HtmlNameTan, 0xd2b48c }, + { c_HtmlNameTeal, 0x8080 }, + { c_HtmlNameThistle, 0xd8bfd8 }, + { c_HtmlNameTomato, 0xff6347 }, + { c_HtmlNameTurquoise, 0x40e0d0 }, + { c_HtmlNameViolet, 0xee82ee }, + { c_HtmlNameWheat, 0xf5deb3 }, + { c_HtmlNameWhite, 0xffffff }, + { c_HtmlNameWhiteSmoke, 0xf5f5f5 }, + { c_HtmlNameYellow, 0xffff00 }, + { c_HtmlNameYellowGreen, 0x9acd32 }, +}; + +const HtmlColorPair* HtmlColorNames::Pair(uint8_t index) +{ + return &c_ColorNames[index]; +} + +uint8_t HtmlColorNames::Count() +{ + return countof(c_ColorNames); +} diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorShortNames.cpp b/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorShortNames.cpp new file mode 100644 index 0000000..3c4e27c --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/HtmlColorShortNames.cpp @@ -0,0 +1,59 @@ +/*------------------------------------------------------------------------- +HtmlShortColorNames provides a template class for access to the short name table + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#include "HtmlColor.h" +#include "HtmlColorNameStrings.h" + +static const HtmlColorPair c_ShortColorNames[] PROGMEM = { + { c_HtmlNameAqua, 0xffff }, + { c_HtmlNameBlack, 0x0 }, + { c_HtmlNameBlue, 0xff }, + { c_HtmlNameFuchsia, 0xff00ff }, + { c_HtmlNameGray, 0x808080 }, + { c_HtmlNameGreen, 0x8000 }, + { c_HtmlNameLime, 0xff00 }, + { c_HtmlNameMaroon, 0x800000 }, + { c_HtmlNameNavy, 0x80 }, + { c_HtmlNameOlive, 0x808000 }, + { c_HtmlNameOrange, 0xffa500 }, + { c_HtmlNamePurple, 0x800080 }, + { c_HtmlNameRed, 0xff0000 }, + { c_HtmlNameSilver, 0xc0c0c0 }, + { c_HtmlNameTeal, 0x8080 }, + { c_HtmlNameWhite, 0xffffff }, + { c_HtmlNameYellow, 0xffff00 }, +}; + + +const HtmlColorPair* HtmlShortColorNames::Pair(uint8_t index) +{ + return &c_ShortColorNames[index]; +} + +uint8_t HtmlShortColorNames::Count() +{ + return countof(c_ShortColorNames); +} \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/Layouts.h b/lib/NeoPixelBus_by_Makuna/src/internal/Layouts.h new file mode 100644 index 0000000..5b1016e --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/Layouts.h @@ -0,0 +1,426 @@ +#pragma once +/*------------------------------------------------------------------------- +Layout provides a collection of class objects that are used with NeoTopology +object. +They define the specific layout of pixels and do the math to change the 2d +cordinate space to 1d cordinate space + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +const uint16_t PixelIndex_OutOfBounds = 0xffff; + +//----------------------------------------------------------------------------- +// RowMajor +//----------------------------------------------------------------------------- + +class RowMajorLayout; +class RowMajor90Layout; +class RowMajor180Layout; +class RowMajor270Layout; + +class RowMajorTilePreference +{ +public: + typedef RowMajorLayout EvenRowEvenColumnLayout; + typedef RowMajor270Layout EvenRowOddColumnLayout; + typedef RowMajor90Layout OddRowEvenColumnLayout; + typedef RowMajor180Layout OddRowOddColumnLayout; +}; + +// layout example of 4x4 +// 00 01 02 03 +// 04 05 06 07 +// 08 09 10 11 +// 12 13 14 15 +// +class RowMajorLayout : public RowMajorTilePreference +{ +public: + static uint16_t Map(uint16_t width, uint16_t /* height */, uint16_t x, uint16_t y) + { + return x + y * width; + } +}; + +// layout example of 4x4 +// 12 08 04 00 +// 13 09 05 01 +// 14 10 06 02 +// 15 11 07 03 +// +class RowMajor90Layout : public RowMajorTilePreference +{ +public: + static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y) + { + return (width - 1 - x) * height + y; + } +}; + +// layout example of 4x4 +// 15 14 13 12 +// 11 10 09 08 +// 07 06 05 04 +// 03 02 01 00 +// +class RowMajor180Layout : public RowMajorTilePreference +{ +public: + static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y) + { + return (width - 1 - x) + (height - 1 - y) * width; + } +}; + +// layout example of 4x4 +// 03 07 11 15 +// 02 06 10 14 +// 01 05 09 13 +// 00 04 08 12 +// +class RowMajor270Layout : public RowMajorTilePreference +{ +public: + static uint16_t Map(uint16_t /* width */, uint16_t height, uint16_t x, uint16_t y) + { + return x * height + (height - 1 - y); + } +}; + + +//----------------------------------------------------------------------------- +// ColumnMajor +//----------------------------------------------------------------------------- + +class ColumnMajorLayout; +class ColumnMajor90Layout; +class ColumnMajor180Layout; +class ColumnMajor270Layout; + +class ColumnMajorTilePreference +{ +public: + typedef ColumnMajorLayout EvenRowEvenColumnLayout; + typedef ColumnMajor270Layout EvenRowOddColumnLayout; + typedef ColumnMajor90Layout OddRowEvenColumnLayout; + typedef ColumnMajor180Layout OddRowOddColumnLayout; +}; + +// layout example of 4x4 +// 00 04 08 12 +// 01 05 09 13 +// 02 06 10 14 +// 03 07 11 15 +// +class ColumnMajorLayout : public ColumnMajorTilePreference +{ +public: + static uint16_t Map(uint16_t /* width */, uint16_t height, uint16_t x, uint16_t y) + { + return x * height + y; + } +}; + +// layout example of 4x4 +// 03 02 01 00 +// 07 06 05 04 +// 11 10 09 08 +// 15 14 13 12 +// +class ColumnMajor90Layout : public ColumnMajorTilePreference +{ +public: + static uint16_t Map(uint16_t width, uint16_t /* height */, uint16_t x, uint16_t y) + { + return (width - 1 - x) + y * width; + } +}; + +// layout example of 4x4 +// 15 11 07 03 +// 14 10 06 02 +// 13 09 05 01 +// 12 08 04 00 +// +class ColumnMajor180Layout : public ColumnMajorTilePreference +{ +public: + static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y) + { + return (width - 1 - x) * height + (height - 1 - y); + } +}; + +// layout example of 4x4 +// 12 13 14 15 +// 08 09 10 11 +// 04 05 06 07 +// 00 01 02 03 +// +class ColumnMajor270Layout : public ColumnMajorTilePreference +{ +public: + static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y) + { + return x + (height - 1 - y) * width; + } +}; + + +//----------------------------------------------------------------------------- +// RowMajorAlternating +//----------------------------------------------------------------------------- + +class RowMajorAlternating270Layout; +class RowMajorAlternating90Layout; + +class RowMajorAlternatingTilePreference +{ +public: + typedef RowMajorAlternating270Layout EvenRowEvenColumnLayout; + typedef RowMajorAlternating270Layout EvenRowOddColumnLayout; + typedef RowMajorAlternating90Layout OddRowEvenColumnLayout; + typedef RowMajorAlternating90Layout OddRowOddColumnLayout; +}; + +// layout example of 4x4 +// 00 01 02 03 +// 07 06 05 04 +// 08 09 10 11 +// 15 14 13 12 +// +class RowMajorAlternatingLayout : public RowMajorAlternatingTilePreference +{ +public: + static uint16_t Map(uint16_t width, uint16_t /* height */, uint16_t x, uint16_t y) + { + uint16_t index = y * width; + + if (y & 0x0001) + { + index += ((width - 1) - x); + } + else + { + index += x; + } + return index; + } +}; + +// layout example of 4x4 +// 15 08 07 00 +// 14 09 06 01 +// 13 10 05 02 +// 12 11 04 03 +// +class RowMajorAlternating90Layout : public RowMajorAlternatingTilePreference +{ +public: + static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y) + { + uint16_t mx = ((width - 1) - x); + uint16_t index = mx * height; + + if (mx & 0x0001) + { + index += ((height - 1) - y); + } + else + { + index += y; + } + return index; + } +}; + +// layout example of 4x4 +// 12 13 14 15 +// 11 10 09 08 +// 04 05 06 07 +// 03 02 01 00 +// +class RowMajorAlternating180Layout : public RowMajorAlternatingTilePreference +{ +public: + static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y) + { + uint16_t my = ((height - 1) - y); + uint16_t index = my * width; + + if (my & 0x0001) + { + index += x; + } + else + { + index += ((width - 1) - x); + } + return index; + } +}; + +// layout example of 4x4 +// 03 04 11 12 +// 02 05 10 13 +// 01 06 09 14 +// 00 07 08 15 +// +class RowMajorAlternating270Layout : public RowMajorAlternatingTilePreference +{ +public: + static uint16_t Map(uint16_t /* width */, uint16_t height, uint16_t x, uint16_t y) + { + uint16_t index = x * height; + + if (x & 0x0001) + { + index += y; + } + else + { + index += ((height - 1) - y); + } + return index; + } +}; + + +//----------------------------------------------------------------------------- +// ColumnMajorAlternating +//----------------------------------------------------------------------------- + +class ColumnMajorAlternatingLayout; +class ColumnMajorAlternating180Layout; + +class ColumnMajorAlternatingTilePreference +{ +public: + typedef ColumnMajorAlternatingLayout EvenRowEvenColumnLayout; + typedef ColumnMajorAlternatingLayout EvenRowOddColumnLayout; + typedef ColumnMajorAlternating180Layout OddRowEvenColumnLayout; + typedef ColumnMajorAlternating180Layout OddRowOddColumnLayout; +}; + +// layout example of 4x4 +// 00 07 08 15 +// 01 06 09 14 +// 02 05 10 13 +// 03 04 11 12 +// +class ColumnMajorAlternatingLayout : public ColumnMajorAlternatingTilePreference +{ +public: + static uint16_t Map(uint16_t /* width */, uint16_t height, uint16_t x, uint16_t y) + { + uint16_t index = x * height; + + if (x & 0x0001) + { + index += ((height - 1) - y); + } + else + { + index += y; + } + return index; + } +}; + +// layout example of 4x4 +// 03 02 01 00 +// 04 05 06 07 +// 11 10 09 08 +// 12 13 14 15 +// +class ColumnMajorAlternating90Layout : public ColumnMajorAlternatingTilePreference +{ +public: + static uint16_t Map(uint16_t width, uint16_t /* height */, uint16_t x, uint16_t y) + { + uint16_t index = y * width; + + if (y & 0x0001) + { + index += x; + } + else + { + index += ((width - 1) - x); + } + return index; + } +}; + +// layout example of 4x4 +// 12 11 04 03 +// 13 10 05 02 +// 14 09 06 01 +// 15 08 07 00 +// +class ColumnMajorAlternating180Layout : public ColumnMajorAlternatingTilePreference +{ +public: + static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y) + { + uint16_t mx = ((width - 1) - x); + uint16_t index = mx * height; + + if (mx & 0x0001) + { + index += y; + } + else + { + index += ((height - 1) - y); + } + return index; + } +}; + +// layout example of 4x4 +// 15 14 13 12 +// 08 09 10 11 +// 07 06 05 04 +// 00 01 02 03 +// +class ColumnMajorAlternating270Layout : public ColumnMajorAlternatingTilePreference +{ +public: + static uint16_t Map(uint16_t width, uint16_t height, uint16_t x, uint16_t y) + { + uint16_t my = ((height - 1) - y); + uint16_t index = my * width; + + if (my & 0x0001) + { + index += ((width - 1) - x); + } + else + { + index += x; + } + return index; + } +}; diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/Lpd8806ColorFeatures.h b/lib/NeoPixelBus_by_Makuna/src/internal/Lpd8806ColorFeatures.h new file mode 100644 index 0000000..6ffb4d0 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/Lpd8806ColorFeatures.h @@ -0,0 +1,189 @@ +/*------------------------------------------------------------------------- +Lpd8806ColorFeatures provides feature classes to describe color order and +color depth for NeoPixelBus template class when used with DotStar like chips + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +class Lpd88063ElementsNoSettings +{ +public: + typedef NeoNoSettings SettingsObject; + static const size_t SettingsSize = 0; + + static void applySettings(uint8_t*, const SettingsObject&) + { + } + + static uint8_t* pixels(uint8_t* pData) + { + return pData; + } + + static const uint8_t* pixels(const uint8_t* pData) + { + return pData; + } +}; + +class Lpd88063Elements : public Lpd88063ElementsNoSettings +{ +public: + static const size_t PixelSize = 3; + + + static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + + static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + while (pPixelDest < pEnd) + { + *pPixelDest++ = pPixelSrc[0]; + *pPixelDest++ = pPixelSrc[1]; + *pPixelDest++ = pPixelSrc[2]; + } + } + + static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + while (pPixelDest < pEnd) + { + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + } + } + + static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + const uint8_t* pSrc = (const uint8_t*)pPixelSrc; + while (pPixelDest < pEnd) + { + *pPixelDest++ = pgm_read_byte(pSrc++); + *pPixelDest++ = pgm_read_byte(pSrc++); + *pPixelDest++ = pgm_read_byte(pSrc++); + } + } + + static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pDestBack = pPixelDest + (count * PixelSize); + const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize); + while (pDestBack > pPixelDest) + { + *--pDestBack = *--pSrcBack; + *--pDestBack = *--pSrcBack; + *--pDestBack = *--pSrcBack; + } + } + + typedef RgbColor ColorObject; +}; + +class Lpd8806BrgFeature : public Lpd88063Elements +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = (color.B >> 1) | 0x80; + *p++ = (color.R >> 1) | 0x80; + *p = (color.G >> 1) | 0x80; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.B = (*p++) << 1; + color.R = (*p++) << 1; + color.G = (*p) << 1; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.B = (pgm_read_byte(p++)) << 1; + color.R = (pgm_read_byte(p++)) << 1; + color.G = (pgm_read_byte(p)) << 1; + + return color; + } + +}; + +class Lpd8806GrbFeature : public Lpd88063Elements +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = (color.G >> 1) | 0x80; + *p++ = (color.R >> 1) | 0x80; + *p = (color.B >> 1) | 0x80; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.G = (*p++) << 1; + color.R = (*p++) << 1; + color.B = (*p) << 1; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.G = (pgm_read_byte(p++)) << 1; + color.R = (pgm_read_byte(p++)) << 1; + color.B = (pgm_read_byte(p)) << 1; + + return color; + } + +}; + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/Lpd8806GenericMethod.h b/lib/NeoPixelBus_by_Makuna/src/internal/Lpd8806GenericMethod.h new file mode 100644 index 0000000..2a741f9 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/Lpd8806GenericMethod.h @@ -0,0 +1,130 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for LPD8806 using general Pins + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set +#if defined(ARDUINO_ARCH_AVR) && !defined(__arm__) +#include "TwoWireBitBangImpleAvr.h" +#else +#include "TwoWireBitBangImple.h" +#endif + + +template class Lpd8806MethodBase +{ +public: + Lpd8806MethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + _sizeFrame((pixelCount + 31) / 32), + _wire(pinClock, pinData) + { + _data = static_cast(malloc(_sizeData)); + memset(_data, 0, _sizeData); + } + +#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny) + Lpd8806MethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + Lpd8806MethodBase(SCK, MOSI, pixelCount, elementSize, settingsSize) + { + } +#endif + + + ~Lpd8806MethodBase() + { + free(_data); + } + + bool IsReadyToUpdate() const + { + return true; // dot stars don't have a required delay + } + +#if defined(ARDUINO_ARCH_ESP32) + void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) + { + _wire.begin(sck, miso, mosi, ss); + } +#endif + + void Initialize() + { + _wire.begin(); + } + + void Update(bool) + { + _wire.beginTransaction(); + + // start frame + for (size_t frameByte = 0; frameByte < _sizeFrame; frameByte++) + { + _wire.transmitByte(0x00); + } + + // data + _wire.transmitBytes(_data, _sizeData); + + // end frame + for (size_t frameByte = 0; frameByte < _sizeFrame; frameByte++) + { + _wire.transmitByte(0xff); + } + + _wire.endTransaction(); + } + + uint8_t* getData() const + { + return _data; + }; + + size_t getDataSize() const + { + return _sizeData; + }; + +private: + const size_t _sizeData; // Size of '_data' buffer below + const size_t _sizeFrame; + + T_TWOWIRE _wire; + uint8_t* _data; // Holds LED color values +}; + +typedef Lpd8806MethodBase Lpd8806Method; + +#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny) +#include "TwoWireSpiImple.h" +typedef Lpd8806MethodBase> Lpd8806Spi20MhzMethod; +typedef Lpd8806MethodBase> Lpd8806Spi10MhzMethod; +typedef Lpd8806MethodBase> Lpd8806Spi2MhzMethod; +typedef Lpd8806Spi10MhzMethod Lpd8806SpiMethod; +#endif + + + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoArmMethod.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoArmMethod.h new file mode 100644 index 0000000..34f1116 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoArmMethod.h @@ -0,0 +1,818 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for ARM MCUs. +Teensy 3.0, 3.1, LC, Arduino Due + +Written by Michael C. Miller. +Some work taken from the Adafruit NeoPixel library. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. +The contents of this file were taken from the Adafruit NeoPixel library +and modified only to fit within individual calling functions. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#if defined(__arm__) && !defined(ARDUINO_ARCH_NRF52840) + +template class NeoArmMethodBase +{ +public: + NeoArmMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + _pin(pin) + { + pinMode(pin, OUTPUT); + + _data = static_cast(malloc(_sizeData)); + memset(_data, 0, _sizeData); + } + + ~NeoArmMethodBase() + { + pinMode(_pin, INPUT); + + free(_data); + } + + bool IsReadyToUpdate() const + { + uint32_t delta = micros() - _endTime; + + return (delta >= T_SPEED::ResetTimeUs); + } + + void Initialize() + { + digitalWrite(_pin, LOW); + + _endTime = micros(); + } + + void Update(bool) + { + // Data latch = 50+ microsecond pause in the output stream. Rather than + // put a delay at the end of the function, the ending time is noted and + // the function will simply hold off (if needed) on issuing the + // subsequent round of data until the latch time has elapsed. This + // allows the mainline code to start generating the next frame of data + // rather than stalling for the latch. + while (!IsReadyToUpdate()) + { + yield(); // allows for system yield if needed + } + + noInterrupts(); // Need 100% focus on instruction timing + + T_SPEED::send_pixels(_data, _sizeData, _pin); + + interrupts(); + + // save EOD time for latch on next call + _endTime = micros(); + } + + uint8_t* getData() const + { + return _data; + }; + + size_t getDataSize() const + { + return _sizeData; + }; + +private: + const size_t _sizeData; // Size of '_data' buffer below + + uint32_t _endTime; // Latch timing reference + uint8_t* _data; // Holds LED color values + uint8_t _pin; // output pin number +}; + +// Teensy 3.0 or 3.1 (3.2) or 3.5 or 3.6 +#if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) + +class NeoArmMk20dxSpeedProps800KbpsBase +{ +public: + static const uint32_t CyclesT0h = (F_CPU / 4000000); + static const uint32_t CyclesT1h = (F_CPU / 1250000); + static const uint32_t Cycles = (F_CPU / 800000); +}; + +class NeoArmMk20dxSpeedPropsWs2812x : public NeoArmMk20dxSpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 300; +}; + +class NeoArmMk20dxSpeedPropsSk6812 : public NeoArmMk20dxSpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 80; +}; + +class NeoArmMk20dxSpeedPropsTm1814 : public NeoArmMk20dxSpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 200; +}; + +class NeoArmMk20dxSpeedProps800Kbps : public NeoArmMk20dxSpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 50; +}; + +class NeoArmMk20dxSpeedProps400Kbps +{ +public: + static const uint32_t CyclesT0h = (F_CPU / 2000000); + static const uint32_t CyclesT1h = (F_CPU / 833333); + static const uint32_t Cycles = (F_CPU / 400000); + static const uint32_t ResetTimeUs = 50; +}; + +class NeoArmMk20dxSpeedPropsApa106 +{ +public: + static const uint32_t CyclesT0h = (F_CPU / 4000000); + static const uint32_t CyclesT1h = (F_CPU / 913750); + static const uint32_t Cycles = (F_CPU / 584800); + static const uint32_t ResetTimeUs = 50; +}; + +template class NeoArmMk20dxSpeedBase +{ +public: + static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs; + + static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) + { + uint8_t* p = pixels; + uint8_t* end = p + sizePixels; + uint8_t pix; + uint8_t mask; + + volatile uint8_t* set = portSetRegister(pin); + volatile uint8_t* clr = portClearRegister(pin); + + uint32_t cyc; + + ARM_DEMCR |= ARM_DEMCR_TRCENA; + ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; + + cyc = ARM_DWT_CYCCNT + T_SPEEDPROPS::Cycles; + while (p < end) + { + pix = *p++; + for (mask = 0x80; mask; mask >>= 1) + { + while (ARM_DWT_CYCCNT - cyc < T_SPEEDPROPS::Cycles); + + cyc = ARM_DWT_CYCCNT; + *set = 1; + if (pix & mask) + { + while (ARM_DWT_CYCCNT - cyc < T_SPEEDPROPS::CyclesT1h); + } + else + { + while (ARM_DWT_CYCCNT - cyc < T_SPEEDPROPS::CyclesT0h); + } + *clr = 1; + } + } + } +}; + +typedef NeoArmMethodBase> NeoArmWs2812xMethod; +typedef NeoArmMethodBase> NeoArmSk6812Method; +typedef NeoArmMethodBase> NeoArmTm1814InvertedMethod; +typedef NeoArmMethodBase> NeoArmApa106Method; +typedef NeoArmMethodBase> NeoArm800KbpsMethod; +typedef NeoArmMethodBase> NeoArm400KbpsMethod; + + +#elif defined(__MKL26Z64__) // Teensy-LC + +#if F_CPU == 48000000 + +class NeoArmMk26z64Speed800KbpsBase +{ +public: + static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) + { + uint8_t* p = pixels; + uint8_t pix; + uint8_t count; + uint8_t dly; + uint8_t bitmask = digitalPinToBitMask(pin); + volatile uint8_t* reg = portSetRegister(pin); + uint32_t num = sizePixels; + + asm volatile( + "L%=_begin:" "\n\t" + "ldrb %[pix], [%[p], #0]" "\n\t" + "lsl %[pix], #24" "\n\t" + "movs %[count], #7" "\n\t" + "L%=_loop:" "\n\t" + "lsl %[pix], #1" "\n\t" + "bcs L%=_loop_one" "\n\t" + "L%=_loop_zero:" + "strb %[bitmask], [%[reg], #0]" "\n\t" + "movs %[dly], #4" "\n\t" + "L%=_loop_delay_T0H:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_loop_delay_T0H" "\n\t" + "strb %[bitmask], [%[reg], #4]" "\n\t" + "movs %[dly], #13" "\n\t" + "L%=_loop_delay_T0L:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_loop_delay_T0L" "\n\t" + "b L%=_next" "\n\t" + "L%=_loop_one:" + "strb %[bitmask], [%[reg], #0]" "\n\t" + "movs %[dly], #13" "\n\t" + "L%=_loop_delay_T1H:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_loop_delay_T1H" "\n\t" + "strb %[bitmask], [%[reg], #4]" "\n\t" + "movs %[dly], #4" "\n\t" + "L%=_loop_delay_T1L:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_loop_delay_T1L" "\n\t" + "nop" "\n\t" + "L%=_next:" "\n\t" + "sub %[count], #1" "\n\t" + "bne L%=_loop" "\n\t" + "lsl %[pix], #1" "\n\t" + "bcs L%=_last_one" "\n\t" + "L%=_last_zero:" + "strb %[bitmask], [%[reg], #0]" "\n\t" + "movs %[dly], #4" "\n\t" + "L%=_last_delay_T0H:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_last_delay_T0H" "\n\t" + "strb %[bitmask], [%[reg], #4]" "\n\t" + "movs %[dly], #10" "\n\t" + "L%=_last_delay_T0L:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_last_delay_T0L" "\n\t" + "b L%=_repeat" "\n\t" + "L%=_last_one:" + "strb %[bitmask], [%[reg], #0]" "\n\t" + "movs %[dly], #13" "\n\t" + "L%=_last_delay_T1H:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_last_delay_T1H" "\n\t" + "strb %[bitmask], [%[reg], #4]" "\n\t" + "movs %[dly], #1" "\n\t" + "L%=_last_delay_T1L:" "\n\t" + "sub %[dly], #1" "\n\t" + "bne L%=_last_delay_T1L" "\n\t" + "nop" "\n\t" + "L%=_repeat:" "\n\t" + "add %[p], #1" "\n\t" + "sub %[num], #1" "\n\t" + "bne L%=_begin" "\n\t" + "L%=_done:" "\n\t" + : [p] "+r" (p), + [pix] "=&r" (pix), + [count] "=&r" (count), + [dly] "=&r" (dly), + [num] "+r" (num) + : [bitmask] "r" (bitmask), + [reg] "r" (reg) + ); + } +}; + +class NeoArmMk26z64SpeedWs2812x : public NeoArmMk26z64Speed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 300; +}; + +class NeoArmMk26z64SpeedSk6812 : public NeoArmMk26z64Speed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 80; +}; + +class NeoArmMk26z64SpeedTm1814 : public NeoArmMk26z64Speed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 200; +}; + +class NeoArmMk26z64Speed800Kbps : public NeoArmMk26z64Speed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 50; +}; + +typedef NeoArmMethodBase NeoArmWs2812xMethod; +typedef NeoArmMethodBase NeoArmSk6812Method; +typedef NeoArmMethodBase NeoArmTm1814InvertedMethod; +typedef NeoArmMethodBase NeoArm800KbpsMethod; +typedef NeoArm800KbpsMethod NeoArmApa106Method + +#else +#error "Teensy-LC: Sorry, only 48 MHz is supported, please set Tools > CPU Speed to 48 MHz" +#endif // F_CPU == 48000000 + +#elif defined(__SAMD21G18A__) // Arduino Zero + + +class NeoArmSamd21g18aSpeedProps800KbpsBase +{ +public: + static void BitPreWait() + { + asm("nop; nop; nop; nop; nop; nop; nop; nop;"); + } + static void BitT1hWait() + { + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop;"); + } + static void BitT0lWait() + { + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop;"); + } + static void BitPostWait() + { + asm("nop; nop; nop; nop; nop; nop; nop; nop; nop;"); + } +}; + +class NeoArmSamd21g18aSpeedPropsWs2812x : public NeoArmSamd21g18aSpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 300; +}; + +class NeoArmSamd21g18aSpeedPropsSk6812 : public NeoArmSamd21g18aSpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 80; +}; + +class NeoArmSamd21g18aSpeedPropsTm1814 : public NeoArmSamd21g18aSpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 200; +}; + +class NeoArmSamd21g18aSpeedProps800Kbps : public NeoArmSamd21g18aSpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 50; +}; + + +class NeoArmSamd21g18aSpeedProps400Kbps +{ +public: + static void BitPreWait() + { + asm("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;"); + } + static void BitT1hWait() + { + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop;"); + } + static void BitT0lWait() + { + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop;"); + } + static void BitPostWait() + { + asm("nop; nop; nop; nop; nop; nop; nop;"); + } + static const uint32_t ResetTimeUs = 50; +}; + +template class NeoArmSamd21g18aSpeedBase +{ +public: + static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs; + + static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) + { + // Tried this with a timer/counter, couldn't quite get adequate + // resolution. So yay, you get a load of goofball NOPs... + uint8_t* ptr = pixels; + uint8_t* end = ptr + sizePixels;; + uint8_t p = *ptr++; + uint8_t bitMask = 0x80; + uint8_t portNum = g_APinDescription[pin].ulPort; + uint32_t pinMask = 1ul << g_APinDescription[pin].ulPin; + + volatile uint32_t* set = &(PORT->Group[portNum].OUTSET.reg); + volatile uint32_t* clr = &(PORT->Group[portNum].OUTCLR.reg); + + for (;;) + { + *set = pinMask; + T_SPEEDPROPS::BitPreWait(); + + if (p & bitMask) + { + T_SPEEDPROPS::BitT1hWait(); + *clr = pinMask; + } + else + { + *clr = pinMask; + T_SPEEDPROPS::BitT0lWait(); + } + if (bitMask >>= 1) + { + T_SPEEDPROPS::BitPostWait(); + } + else + { + if (ptr >= end) + { + break; + } + p = *ptr++; + bitMask = 0x80; + } + } + } +}; + +typedef NeoArmMethodBase> NeoArmWs2812xMethod; +typedef NeoArmMethodBase> NeoArmSk6812Method; +typedef NeoArmMethodBase> NeoArmTm1814InvertedMethod; +typedef NeoArmMethodBase> NeoArm800KbpsMethod; +typedef NeoArmMethodBase> NeoArm400KbpsMethod; +typedef NeoArm400KbpsMethod NeoArmApa106Method; + +#elif defined(ARDUINO_STM32_FEATHER) || defined(ARDUINO_ARCH_STM32L4) || defined(ARDUINO_ARCH_STM32F4) || defined(ARDUINO_ARCH_STM32F1)// FEATHER WICED (120MHz) + +class NeoArmStm32SpeedProps800KbpsBase +{ +public: + static void BitT1hWait() + { + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop;"); + } + static void BitT1lWait() + { + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop;"); + } + static void BitT0hWait() + { + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop;"); + } + static void BitT0lWait() + { + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop;"); + } +}; + +class NeoArmStm32SpeedPropsWs2812x : public NeoArmStm32SpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 300; +}; + +class NeoArmStm32SpeedPropsSk6812 : public NeoArmStm32SpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 80; +}; + +class NeoArmStm32SpeedPropsTm1814 : public NeoArmStm32SpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 200; +}; + +class NeoArmStm32SpeedProps800Kbps : public NeoArmStm32SpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 50; +}; + +/* TODO - not found in Adafruit library +class NeoArmStm32SpeedProps400Kbps +{ +static void BitT1hWait() +{ +} +static void BitT1lWait() +{ +} +static void BitT0hWait() +{ +} +static void BitT0lWait() +{ +} +}; +*/ + +template class NeoArmStm32SpeedBase +{ +public: + static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs; + + static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) + { + // Tried this with a timer/counter, couldn't quite get adequate + // resolution. So yay, you get a load of goofball NOPs... + + uint8_t* ptr = pixels; + uint8_t* end = ptr + sizePixels; + uint8_t p = *ptr++; + uint8_t bitMask = 0x80; + +#if defined(ARDUINO_STM32_FEATHER) + uint32_t pinMask = BIT(PIN_MAP[pin].gpio_bit); + + volatile uint16_t* set = &(PIN_MAP[pin].gpio_device->regs->BSRRL); + volatile uint16_t* clr = &(PIN_MAP[pin].gpio_device->regs->BSRRH); + +#elif defined(ARDUINO_ARCH_STM32F4) + uint32_t pinMask = BIT(pin & 0x0f); + + volatile uint16_t* set = &(PIN_MAP[pin].gpio_device->regs->BSRRL); + volatile uint16_t* clr = &(PIN_MAP[pin].gpio_device->regs->BSRRH); + +#elif defined(ARDUINO_ARCH_STM32F1) + + uint32_t pinMask = BIT(PIN_MAP[pin].gpio_bit); + + volatile uint32_t* set = &(PIN_MAP[pin].gpio_device->regs->BRR); + volatile uint32_t* clr = &(PIN_MAP[pin].gpio_device->regs->BSRR); + +#elif defined(ARDUINO_ARCH_STM32L4) + + uint32_t pinMask = g_APinDescription[pin].bit; + + GPIO_TypeDef* GPIO = static_cast(g_APinDescription[pin].GPIO); + + volatile uint32_t* set = &(GPIO->BRR); + volatile uint32_t* clr = &(GPIO->BSRR); + +#endif + for (;;) + { + if (p & bitMask) + { + // ONE + // High 800ns + *set = pinMask; + T_SPEEDPROPS::BitT1hWait(); + // Low 450ns + *clr = pinMask; + T_SPEEDPROPS::BitT1lWait(); + } + else + { + // ZERO + // High 400ns + *set = pinMask; + T_SPEEDPROPS::BitT0hWait(); + // Low 850ns + *clr = pinMask; + T_SPEEDPROPS::BitT0lWait(); + } + if (bitMask >>= 1) + { + // Move on to the next pixel + asm("nop;"); + } + else + { + if (ptr >= end) + { + break; + } + + p = *ptr++; + bitMask = 0x80; + } + } + } +}; + +typedef NeoArmMethodBase> NeoArmWs2812xMethod; +typedef NeoArmMethodBase> NeoArmSk6812Method; +typedef NeoArmMethodBase> NeoArmTm1814InvertedMethod; +typedef NeoArmMethodBase> NeoArm800KbpsMethod; +typedef NeoArm800KbpsMethod NeoArmApa106Method; + +#else // Other ARM architecture -- Presumed Arduino Due + + +#define ARM_OTHER_SCALE VARIANT_MCK / 2UL / 1000000UL +#define ARM_OTHER_INST (2UL * F_CPU / VARIANT_MCK) + +class NeoArmOtherSpeedProps800KbpsBase +{ +public: + static const uint32_t CyclesT0h = ((uint32_t)(0.40 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); + static const uint32_t CyclesT1h = ((uint32_t)(0.80 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); + static const uint32_t Cycles = ((uint32_t)(1.25 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); +}; + +class NeoArmOtherSpeedPropsWs2812x : public NeoArmOtherSpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 300; +}; + +class NeoArmOtherSpeedPropsSk6812 : public NeoArmOtherSpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 80; +}; + +class NeoArmOtherSpeedPropsTm1814 : public NeoArmOtherSpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 200; +}; + +class NeoArmOtherSpeedProps800Kbps : public NeoArmOtherSpeedProps800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 50; +}; + +class NeoArmOtherSpeedProps400Kbps +{ +public: + static const uint32_t CyclesT0h = ((uint32_t)(0.50 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); + static const uint32_t CyclesT1h = ((uint32_t)(1.20 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); + static const uint32_t Cycles = ((uint32_t)(2.50 * ARM_OTHER_SCALE + 0.5) - (5 * ARM_OTHER_INST)); + static const uint32_t ResetTimeUs = 50; +}; + +template class NeoArmOtherSpeedBase +{ +public: + static const uint32_t ResetTimeUs = T_SPEEDPROPS::ResetTimeUs; + + static void send_pixels(uint8_t* pixels, size_t sizePixels, uint8_t pin) + { + uint32_t pinMask; + uint32_t t; + Pio* port; + volatile WoReg* portSet; + volatile WoReg* portClear; + volatile WoReg* timeValue; + volatile WoReg* timeReset; + uint8_t* p; + uint8_t* end; + uint8_t pix; + uint8_t mask; + + pmc_set_writeprotect(false); + pmc_enable_periph_clk((uint32_t)TC3_IRQn); + + TC_Configure(TC1, 0, + TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK1); + TC_Start(TC1, 0); + + pinMask = g_APinDescription[pin].ulPin; // Don't 'optimize' these into + port = g_APinDescription[pin].pPort; // declarations above. Want to + portSet = &(port->PIO_SODR); // burn a few cycles after + portClear = &(port->PIO_CODR); // starting timer to minimize + timeValue = &(TC1->TC_CHANNEL[0].TC_CV); // the initial 'while'. + timeReset = &(TC1->TC_CHANNEL[0].TC_CCR); + p = pixels; + end = p + sizePixels; + pix = *p++; + mask = 0x80; + + for (;;) + { + if (pix & mask) + { + t = T_SPEEDPROPS::CyclesT1h; + } + else + { + t = T_SPEEDPROPS::CyclesT0h; + } + + // wait for the end of the previous cycle + while (*timeValue < T_SPEEDPROPS::Cycles); + + *portSet = pinMask; + *timeReset = TC_CCR_CLKEN | TC_CCR_SWTRG; + + while (*timeValue < t); + + *portClear = pinMask; + if (!(mask >>= 1)) + { + // This 'inside-out' loop logic utilizes + if (p >= end) + { + break; // idle time to minimize inter-byte delays. + } + pix = *p++; + mask = 0x80; + } + } + + // not really needed as the wait for latch does this and + // while (*timeValue < T_SPEEDPROPS::Cycles); // Wait for last bit + + TC_Stop(TC1, 0); + } +}; + +typedef NeoArmMethodBase> NeoArmWs2812xMethod; +typedef NeoArmMethodBase> NeoArmSk6812Method; +typedef NeoArmMethodBase> NeoArmTm1814InvertedMethod; +typedef NeoArmMethodBase> NeoArm800KbpsMethod; +typedef NeoArmMethodBase> NeoArm400KbpsMethod; +typedef NeoArm400KbpsMethod NeoArmApa106Method; + +#endif + + +// Arm doesn't have alternatives methods yet, so only one to make the default +typedef NeoArmWs2812xMethod NeoWs2813Method; +typedef NeoArmWs2812xMethod NeoWs2812xMethod; +typedef NeoArmWs2812xMethod NeoWs2811Method; +typedef NeoArmSk6812Method NeoSk6812Method; +typedef NeoArmSk6812Method NeoLc8812Method; +typedef NeoArm800KbpsMethod NeoWs2812Method; +typedef NeoArmApa106Method NeoApa106Method; +typedef NeoArmWs2812xMethod Neo800KbpsMethod; +#ifdef NeoArm400KbpsMethod // this is needed due to missing 400Kbps for some platforms +typedef NeoArm400KbpsMethod Neo400KbpsMethod; +#endif +// there is no invert methods for arm, but the norm for TM1814 is inverted, so +typedef NeoArmTm1814InvertedMethod NeoTm1814InvertedMethod; + +#endif // defined(__arm__) + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoAvrMethod.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoAvrMethod.h new file mode 100644 index 0000000..b638d7b --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoAvrMethod.h @@ -0,0 +1,224 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Atmel AVR. + +Written by Michael C. Miller. +Some work taken from the Adafruit NeoPixel library. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) + +extern "C" +{ + void send_data_8mhz_800_PortD(uint8_t* data, size_t sizeData, uint8_t pinMask); + void send_data_8mhz_800_PortB(uint8_t* data, size_t sizeData, uint8_t pinMask); + void send_data_8mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask); + void send_data_12mhz_800_PortD(uint8_t* data, size_t sizeData, uint8_t pinMask); + void send_data_12mhz_800_PortB(uint8_t* data, size_t sizeData, uint8_t pinMask); + void send_data_12mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask); + void send_data_16mhz_800(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask); + void send_data_16mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask); +} + +class NeoAvrSpeed800KbpsBase +{ +public: + static void send_data(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask) + { +#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) // 8Mhz CPU +#ifdef PORTD // PORTD isn't present on ATtiny85, etc. + if (port == &PORTD) + send_data_8mhz_800_PortD(data, sizeData, pinMask); + else if (port == &PORTB) +#endif // PORTD + send_data_8mhz_800_PortB(data, sizeData, pinMask); + +#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) // 12Mhz CPU +#ifdef PORTD // PORTD + if (port == &PORTD) + send_data_12mhz_800_PortD(data, sizeData, pinMask); + else if (port == &PORTB) +#endif // PORTD + send_data_12mhz_800_PortB(data, sizeData, pinMask); + +#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) // 16Mhz CPU + send_data_16mhz_800(data, sizeData, port, pinMask); +#else +#error "CPU SPEED NOT SUPPORTED" +#endif + } + +}; + +class NeoAvrSpeedWs2812x : public NeoAvrSpeed800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 300; +}; + +class NeoAvrSpeedSk6812 : public NeoAvrSpeed800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 80; +}; + +class NeoAvrSpeedTm1814 : public NeoAvrSpeed800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 200; +}; + +class NeoAvrSpeed800Kbps: public NeoAvrSpeed800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 50; +}; + +class NeoAvrSpeed400Kbps +{ +public: + static void send_data(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask) + { +#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) // 8Mhz CPU + send_data_8mhz_400(data, sizeData, port, pinMask); + +#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) // 12Mhz CPU + send_data_12mhz_400(data, sizeData, port, pinMask); + +#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) // 16Mhz CPU + send_data_16mhz_400(data, sizeData, port, pinMask); +#else +#error "CPU SPEED NOT SUPPORTED" +#endif + } + static const uint32_t ResetTimeUs = 50; +}; + +template class NeoAvrMethodBase +{ +public: + NeoAvrMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + _pin(pin), + _port(NULL), + _pinMask(0) + { + pinMode(pin, OUTPUT); + + _data = static_cast(malloc(_sizeData)); + memset(_data, 0, _sizeData); + + _port = portOutputRegister(digitalPinToPort(pin)); + _pinMask = digitalPinToBitMask(pin); + } + + ~NeoAvrMethodBase() + { + pinMode(_pin, INPUT); + + free(_data); + } + + bool IsReadyToUpdate() const + { + uint32_t delta = micros() - _endTime; + + return (delta >= T_SPEED::ResetTimeUs); + } + + void Initialize() + { + digitalWrite(_pin, LOW); + + _endTime = micros(); + } + + void Update(bool) + { + // Data latch = 50+ microsecond pause in the output stream. Rather than + // put a delay at the end of the function, the ending time is noted and + // the function will simply hold off (if needed) on issuing the + // subsequent round of data until the latch time has elapsed. This + // allows the mainline code to start generating the next frame of data + // rather than stalling for the latch. + while (!IsReadyToUpdate()) + { +#if !defined(ARDUINO_TEEONARDU_LEO) && !defined(ARDUINO_TEEONARDU_FLORA) + yield(); // allows for system yield if needed +#endif + } + + noInterrupts(); // Need 100% focus on instruction timing + + T_SPEED::send_data(_data, _sizeData, _port, _pinMask); + + interrupts(); + + // save EOD time for latch on next call + _endTime = micros(); + } + + uint8_t* getData() const + { + return _data; + }; + + size_t getDataSize() const + { + return _sizeData; + }; + +private: + const size_t _sizeData; // size of _data below + const uint8_t _pin; // output pin number + + uint32_t _endTime; // Latch timing reference + uint8_t* _data; // Holds data stream which include LED color values and other settings as needed + + volatile uint8_t* _port; // Output PORT register + uint8_t _pinMask; // Output PORT bitmask +}; + + +typedef NeoAvrMethodBase NeoAvrWs2812xMethod; +typedef NeoAvrMethodBase NeoAvrSk6812Method; +typedef NeoAvrMethodBase NeoAvrTm1814InvertedMethod; +typedef NeoAvrMethodBase NeoAvr800KbpsMethod; +typedef NeoAvrMethodBase NeoAvr400KbpsMethod; + + +// AVR doesn't have alternatives yet, so there is just the default +typedef NeoAvrWs2812xMethod NeoWs2813Method; +typedef NeoAvrWs2812xMethod NeoWs2812xMethod; +typedef NeoAvr800KbpsMethod NeoWs2812Method; +typedef NeoAvrWs2812xMethod NeoWs2811Method; +typedef NeoAvrSk6812Method NeoSk6812Method; +typedef NeoAvrSk6812Method NeoLc8812Method; +typedef NeoAvr400KbpsMethod NeoApa106Method; +typedef NeoAvrWs2812xMethod Neo800KbpsMethod; +typedef NeoAvr400KbpsMethod Neo400KbpsMethod; + +typedef NeoAvrTm1814InvertedMethod NeoTm1814InvertedMethod; +#endif + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoBitmapFile.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoBitmapFile.h new file mode 100644 index 0000000..2f0718e --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoBitmapFile.h @@ -0,0 +1,388 @@ +/*------------------------------------------------------------------------- +NeoPixel library + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +const uint16_t c_BitmapFileId = 0x4d42; // "BM" + +#pragma pack(push, 2) +struct BitmapFileHeader +{ + uint16_t FileId; // only c_BitmapFileId is supported + uint32_t FileSize; + uint16_t Reserved0; + uint16_t Reserved1; + uint32_t PixelAddress; +}; + +struct BitmapInfoHeader +{ + uint32_t Size; + int32_t Width; + int32_t Height; + uint16_t Planes; // only support 1 + uint16_t BitsPerPixel; // only support 24 and 32 + uint32_t Compression; // only support BI_Rgb + uint32_t RawDateSize; // can be zero + int32_t XPpm; + int32_t YPpm; + uint32_t PaletteLength; + uint32_t ImportantColorCount; +}; +#pragma pack(pop) + +enum BmpCompression +{ + BI_Rgb, + BI_Rle8, + BI_Rle4, + BI_Bitfields, + BI_Jpeg, + BI_Png, + BI_AlphaBitfields, + BI_Cmyk = 11, + BI_CmykRle8, + BI_CmykRle4 +}; + +template class NeoBitmapFile +{ +public: + NeoBitmapFile() : + _fileAddressPixels(0), + _width(0), + _height(0), + _sizeRow(0), + _bytesPerPixel(0), + _bottomToTop(true) + { + } + + ~NeoBitmapFile() + { + _file.close(); + } + + bool Begin(T_FILE_METHOD file) + { + if (_file) + { + _file.close(); + } + + if (!file || !file.seek(0)) + { + goto error; + } + + _file = file; + + BitmapFileHeader bmpHeader; + BitmapInfoHeader bmpInfoHeader; + size_t result; + + result = _file.read((uint8_t*)(&bmpHeader), sizeof(bmpHeader)); + + if (result != sizeof(bmpHeader) || + bmpHeader.FileId != c_BitmapFileId || + bmpHeader.FileSize != _file.size()) + { + goto error; + } + + result = _file.read((uint8_t*)(&bmpInfoHeader), sizeof(bmpInfoHeader)); + + if (result != sizeof(bmpInfoHeader) || + result != bmpInfoHeader.Size || + 1 != bmpInfoHeader.Planes || + BI_Rgb != bmpInfoHeader.Compression) + { + goto error; + } + + if (!(24 == bmpInfoHeader.BitsPerPixel || + 32 == bmpInfoHeader.BitsPerPixel)) + { + goto error; + } + + // save the interesting information + _width = abs(bmpInfoHeader.Width); + _height = abs(bmpInfoHeader.Height); + _fileAddressPixels = bmpHeader.PixelAddress; + // negative height means rows are top to bottom + _bottomToTop = (bmpInfoHeader.Height > 0); + // rows are 32 bit aligned so they may have padding on each row + _sizeRow = (bmpInfoHeader.BitsPerPixel * _width + 31) / 32 * 4; + _bytesPerPixel = bmpInfoHeader.BitsPerPixel / 8; + + return true; + + error: + _fileAddressPixels = 0; + _width = 0; + _height = 0; + _sizeRow = 0; + _bytesPerPixel = 0; + + _file.close(); + return false; + }; + + size_t PixelSize() const + { + return T_COLOR_FEATURE::PixelSize; + }; + + uint16_t PixelCount() const + { + return _width * _height; + }; + + uint16_t Width() const + { + return _width; + }; + + uint16_t Height() const + { + return _height; + }; + + typename T_COLOR_FEATURE::ColorObject GetPixelColor(int16_t x, int16_t y) + { + if (x < 0 || x >= _width || y < 0 || y >= _height) + { + // Pixel # is out of bounds, this will get converted to a + // color object type initialized to 0 (black) + return 0; + } + + typename T_COLOR_FEATURE::ColorObject color; + if (!seek(x, y) || !readPixel(&color)) + { + return 0; + } + + return color; + }; + + + template void Render(NeoBufferContext destBuffer, + T_SHADER& shader, + uint16_t indexPixel, + int16_t xSrc, + int16_t ySrc, + int16_t wSrc) + { + const uint16_t destPixelCount = destBuffer.PixelCount(); + typename T_COLOR_FEATURE::ColorObject color(0); + xSrc = constrainX(xSrc); + ySrc = constrainY(ySrc); + + if (seek(xSrc, ySrc)) + { + for (int16_t x = 0; x < wSrc && indexPixel < destPixelCount; x++, indexPixel++) + { + if ((uint16_t)xSrc < _width) + { + if (readPixel(&color)) + { + color = shader.Apply(indexPixel, color); + xSrc++; + } + } + + T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, indexPixel, color); + } + } + } + + void Blt(NeoBufferContext destBuffer, + uint16_t indexPixel, + int16_t xSrc, + int16_t ySrc, + int16_t wSrc) + { + NeoShaderNop shaderNop; + + Render>(destBuffer, shaderNop, indexPixel, xSrc, ySrc, wSrc); + }; + + template void Render(NeoBufferContext destBuffer, + T_SHADER& shader, + int16_t xDest, + int16_t yDest, + int16_t xSrc, + int16_t ySrc, + int16_t wSrc, + int16_t hSrc, + LayoutMapCallback layoutMap) + { + const uint16_t destPixelCount = destBuffer.PixelCount(); + typename T_COLOR_FEATURE::ColorObject color(0); + + for (int16_t y = 0; y < hSrc; y++) + { + int16_t xFile = constrainX(xSrc); + int16_t yFile = constrainY(ySrc + y); + + if (seek(xFile, yFile)) + { + for (int16_t x = 0; x < wSrc; x++) + { + uint16_t indexDest = layoutMap(xDest + x, yDest + y); + + if ((uint16_t)xFile < _width) + { + if (readPixel(&color)) + { + color = shader.Apply(indexDest, color); + xFile++; + } + } + + if (indexDest < destPixelCount) + { + T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, indexDest, color); + } + } + } + } + }; + + void Blt(NeoBufferContext destBuffer, + int16_t xDest, + int16_t yDest, + int16_t xSrc, + int16_t ySrc, + int16_t wSrc, + int16_t hSrc, + LayoutMapCallback layoutMap) + { + NeoShaderNop shaderNop; + + Render>(destBuffer, + shaderNop, + xDest, + yDest, + xSrc, + ySrc, + wSrc, + hSrc, + layoutMap); + }; + + +private: + T_FILE_METHOD _file; + uint32_t _fileAddressPixels; + uint16_t _width; + uint16_t _height; + uint32_t _sizeRow; + uint8_t _bytesPerPixel; + bool _bottomToTop; + + int16_t constrainX(int16_t x) const + { + if (x < 0) + { + x = 0; + } + else if ((uint16_t)x >= _width) + { + x = _width - 1; + } + return x; + }; + + int16_t constrainY(int16_t y) const + { + if (y < 0) + { + y = 0; + } + else if ((uint16_t)y >= _height) + { + y = _height - 1; + } + return y; + }; + + bool seek(int16_t x, int16_t y) + { + if (_bottomToTop) + { + y = (_height - 1) - y; + } + + uint32_t pos = y * _sizeRow + x * _bytesPerPixel; + pos += _fileAddressPixels; + + return _file.seek(pos); + }; + + bool readPixel(RgbColor* color) + { + uint8_t bgr[4]; + int result; + + result = _file.read(bgr, _bytesPerPixel); + + if (result != _bytesPerPixel) + { + *color = 0; + return false; + } + + color->B = bgr[0]; + color->G = bgr[1]; + color->R = bgr[2]; + + return true; + }; + + bool readPixel(RgbwColor* color) + { + uint8_t bgr[4]; + int result; + + bgr[3] = 0; // init white channel as read maybe only 3 bytes + result = _file.read(bgr, _bytesPerPixel); + + if (result != _bytesPerPixel) + { + *color = 0; + return false; + } + + color->B = bgr[0]; + color->G = bgr[1]; + color->R = bgr[2]; + color->W = bgr[3]; + + return true; + }; +}; \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoBuffer.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoBuffer.h new file mode 100644 index 0000000..996a778 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoBuffer.h @@ -0,0 +1,173 @@ +/*------------------------------------------------------------------------- +NeoPixel library + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +template class NeoBuffer +{ +public: + NeoBuffer(uint16_t width, + uint16_t height, + PGM_VOID_P pixels) : + _method(width, height, pixels) + { + } + + operator NeoBufferContext() + { + return _method; + } + + uint16_t PixelCount() const + { + return _method.PixelCount(); + }; + + uint16_t Width() const + { + return _method.Width(); + }; + + uint16_t Height() const + { + return _method.Height(); + }; + + void SetPixelColor( + int16_t x, + int16_t y, + typename T_BUFFER_METHOD::ColorObject color) + { + _method.SetPixelColor(pixelIndex(x, y), color); + }; + + typename T_BUFFER_METHOD::ColorObject GetPixelColor( + int16_t x, + int16_t y) const + { + return _method.GetPixelColor(pixelIndex(x, y)); + }; + + void ClearTo(typename T_BUFFER_METHOD::ColorObject color) + { + _method.ClearTo(color); + }; + + void Blt(NeoBufferContext destBuffer, + uint16_t indexPixel) + { + uint16_t destPixelCount = destBuffer.PixelCount(); + // validate indexPixel + if (indexPixel >= destPixelCount) + { + return; + } + + // calc how many we can copy + uint16_t copyCount = destPixelCount - indexPixel; + uint16_t srcPixelCount = PixelCount(); + if (copyCount > srcPixelCount) + { + copyCount = srcPixelCount; + } + + uint8_t* pDest = T_BUFFER_METHOD::ColorFeature::getPixelAddress(destBuffer.Pixels, indexPixel); + _method.CopyPixels(pDest, _method.Pixels(), copyCount); + } + + void Blt(NeoBufferContext destBuffer, + int16_t xDest, + int16_t yDest, + int16_t xSrc, + int16_t ySrc, + int16_t wSrc, + int16_t hSrc, + LayoutMapCallback layoutMap) + { + uint16_t destPixelCount = destBuffer.PixelCount(); + + for (int16_t y = 0; y < hSrc; y++) + { + for (int16_t x = 0; x < wSrc; x++) + { + uint16_t indexDest = layoutMap(xDest + x, yDest + y); + + if (indexDest < destPixelCount) + { + const uint8_t* pSrc = T_BUFFER_METHOD::ColorFeature::getPixelAddress(_method.Pixels(), pixelIndex(xSrc + x, ySrc + y)); + uint8_t* pDest = T_BUFFER_METHOD::ColorFeature::getPixelAddress(destBuffer.Pixels, indexDest); + + _method.CopyPixels(pDest, pSrc, 1); + } + } + } + } + + void Blt(NeoBufferContext destBuffer, + int16_t xDest, + int16_t yDest, + LayoutMapCallback layoutMap) + { + Blt(destBuffer, xDest, yDest, 0, 0, Width(), Height(), layoutMap); + } + + template void Render(NeoBufferContext destBuffer, T_SHADER& shader) + { + uint16_t countPixels = destBuffer.PixelCount(); + + if (countPixels > _method.PixelCount()) + { + countPixels = _method.PixelCount(); + } + + for (uint16_t indexPixel = 0; indexPixel < countPixels; indexPixel++) + { + typename T_BUFFER_METHOD::ColorObject color; + + shader.Apply(indexPixel, (uint8_t*)(&color), _method.Pixels() + (indexPixel * _method.PixelSize())); + + T_BUFFER_METHOD::ColorFeature::applyPixelColor(destBuffer.Pixels, indexPixel, color); + } + } + +private: + T_BUFFER_METHOD _method; + + uint16_t pixelIndex( + int16_t x, + int16_t y) const + { + uint16_t result = PixelIndex_OutOfBounds; + + if (x >= 0 && + (uint16_t)x < Width() && + y >= 0 && + (uint16_t)y < Height()) + { + result = x + y * Width(); + } + return result; + } +}; \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoBufferContext.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoBufferContext.h new file mode 100644 index 0000000..8b57344 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoBufferContext.h @@ -0,0 +1,48 @@ +/*------------------------------------------------------------------------- +NeoPixel library + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +// This is used to allow a template classes that share common buffer concept to +// be able to pass that common information to functions +// The template classes just need to expose a conversion operator to this type +template struct NeoBufferContext +{ + NeoBufferContext(uint8_t* pixels, + size_t sizePixels) : + Pixels(pixels), + SizePixels(sizePixels) + { + } + + uint16_t PixelCount() const + { + return SizePixels / T_COLOR_FEATURE::PixelSize; + }; + + uint8_t* Pixels; + const size_t SizePixels; + +}; \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoBufferMethods.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoBufferMethods.h new file mode 100644 index 0000000..79d354f --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoBufferMethods.h @@ -0,0 +1,263 @@ +/*------------------------------------------------------------------------- +NeoPixel library + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + + +#if defined(NEOPIXEBUS_NO_STL) + +typedef uint16_t(*LayoutMapCallback)(int16_t x, int16_t y); + +#else + +#undef max +#undef min +#include +typedef std::function LayoutMapCallback; + +#endif + +template class NeoBufferMethod +{ +public: + NeoBufferMethod(uint16_t width, uint16_t height, PGM_VOID_P pixels = NULL) : + _width(width), + _height(height) + { + _pixels = (uint8_t*)malloc(PixelsSize()); + if (pixels) + { + // copy from progmem to initialize + T_COLOR_FEATURE::movePixelsInc_P(_pixels, pixels, PixelCount()); + } + } + + ~NeoBufferMethod() + { + free(_pixels); + } + + operator NeoBufferContext() + { + return NeoBufferContext(Pixels(), PixelsSize()); + } + + uint8_t* Pixels() const + { + return _pixels; + }; + + size_t PixelsSize() const + { + return PixelSize() * PixelCount(); + }; + + size_t PixelSize() const + { + return T_COLOR_FEATURE::PixelSize; + }; + + uint16_t PixelCount() const + { + return _width * _height; + }; + + uint16_t Width() const + { + return _width; + }; + + uint16_t Height() const + { + return _height; + }; + + void SetPixelColor(uint16_t indexPixel, typename T_COLOR_FEATURE::ColorObject color) + { + if (indexPixel < PixelCount()) + { + T_COLOR_FEATURE::applyPixelColor(_pixels, indexPixel, color); + } + }; + + void SetPixelColor(int16_t x, int16_t y, typename T_COLOR_FEATURE::ColorObject color) + { + if (x < 0 || x >= _width || y < 0 || y >= _height) + { + return; + } + + uint16_t indexPixel = x + y * _width; + T_COLOR_FEATURE::applyPixelColor(_pixels, indexPixel, color); + }; + + typename T_COLOR_FEATURE::ColorObject GetPixelColor(uint16_t indexPixel) const + { + if (indexPixel >= PixelCount()) + { + // Pixel # is out of bounds, this will get converted to a + // color object type initialized to 0 (black) + return 0; + } + + return T_COLOR_FEATURE::retrievePixelColor(_pixels, indexPixel); + }; + + typename T_COLOR_FEATURE::ColorObject GetPixelColor(int16_t x, int16_t y) const + { + if (x < 0 || x >= _width || y < 0 || y >= _height) + { + // Pixel # is out of bounds, this will get converted to a + // color object type initialized to 0 (black) + return 0; + } + + uint16_t indexPixel = x + y * _width; + return T_COLOR_FEATURE::retrievePixelColor(_pixels, indexPixel); + }; + + void ClearTo(typename T_COLOR_FEATURE::ColorObject color) + { + uint8_t temp[T_COLOR_FEATURE::PixelSize]; + + T_COLOR_FEATURE::applyPixelColor(temp, 0, color); + + T_COLOR_FEATURE::replicatePixel(_pixels, temp, PixelCount()); + }; + + void CopyPixels(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + T_COLOR_FEATURE::movePixelsInc(pPixelDest, pPixelSrc, count); + } + + typedef typename T_COLOR_FEATURE::ColorObject ColorObject; + typedef T_COLOR_FEATURE ColorFeature; + +private: + const uint16_t _width; + const uint16_t _height; + uint8_t* _pixels; +}; + +template class NeoBufferProgmemMethod +{ +public: + NeoBufferProgmemMethod(uint16_t width, uint16_t height, PGM_VOID_P pixels) : + _width(width), + _height(height), + _pixels(pixels) + { + } + + operator NeoBufferContext() + { + return NeoBufferContext(Pixels(), PixelsSize()); + } + + uint8_t* Pixels() const + { + return (uint8_t*)_pixels; + }; + + size_t PixelsSize() const + { + return PixelSize() * PixelCount(); + }; + + size_t PixelSize() const + { + return T_COLOR_FEATURE::PixelSize; + }; + + uint16_t PixelCount() const + { + return _width * _height; + }; + + uint16_t Width() const + { + return _width; + }; + + uint16_t Height() const + { + return _height; + }; + + void SetPixelColor(uint16_t indexPixel, typename T_COLOR_FEATURE::ColorObject color) + { + // PROGMEM is read only, this will do nothing + }; + + void SetPixelColor(uint16_t x, uint16_t y, typename T_COLOR_FEATURE::ColorObject color) + { + // PROGMEM is read only, this will do nothing + }; + + typename T_COLOR_FEATURE::ColorObject GetPixelColor(uint16_t indexPixel) const + { + if (indexPixel >= PixelCount()) + { + // Pixel # is out of bounds, this will get converted to a + // color object type initialized to 0 (black) + return 0; + } + + return T_COLOR_FEATURE::retrievePixelColor_P(_pixels, indexPixel); + }; + + typename T_COLOR_FEATURE::ColorObject GetPixelColor(int16_t x, int16_t y) const + { + if (x < 0 || x >= _width || y < 0 || y >= _height) + { + // Pixel # is out of bounds, this will get converted to a + // color object type initialized to 0 (black) + return 0; + } + + uint16_t indexPixel = x + y * _width; + return T_COLOR_FEATURE::retrievePixelColor_P(_pixels, indexPixel); + }; + + void ClearTo(typename T_COLOR_FEATURE::ColorObject color) + { + // PROGMEM is read only, this will do nothing + }; + + void CopyPixels(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + T_COLOR_FEATURE::movePixelsInc_P(pPixelDest, pPixelSrc, count); + } + + typedef typename T_COLOR_FEATURE::ColorObject ColorObject; + typedef T_COLOR_FEATURE ColorFeature; + +private: + const uint16_t _width; + const uint16_t _height; + PGM_VOID_P _pixels; +}; + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoColorFeatures.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoColorFeatures.h new file mode 100644 index 0000000..d1494a2 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoColorFeatures.h @@ -0,0 +1,427 @@ +/*------------------------------------------------------------------------- +NeoColorFeatures provides feature classes to describe color order and +color depth for NeoPixelBus template class + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +class Neo3Elements +{ +public: + static const size_t PixelSize = 3; + + static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + + static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + while (pPixelDest < pEnd) + { + for (uint8_t iElement = 0; iElement < PixelSize; iElement++) + { + *pPixelDest++ = pPixelSrc[iElement]; + } + } + } + + static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + while (pPixelDest < pEnd) + { + *pPixelDest++ = *pPixelSrc++; + } + } + + static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + const uint8_t* pSrc = (const uint8_t*)pPixelSrc; + while (pPixelDest < pEnd) + { + *pPixelDest++ = pgm_read_byte(pSrc++); + } + } + + static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pDestBack = pPixelDest + (count * PixelSize); + const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize); + while (pDestBack > pPixelDest) + { + *--pDestBack = *--pSrcBack; + } + } + + typedef RgbColor ColorObject; +}; + +class Neo4Elements +{ +public: + static const size_t PixelSize = 4; + + static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + + static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint32_t* pDest = (uint32_t*)pPixelDest; + const uint32_t* pSrc = (const uint32_t*)pPixelSrc; + + uint32_t* pEnd = pDest + count; + while (pDest < pEnd) + { + *pDest++ = *pSrc; + } + } + + static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint32_t* pDest = (uint32_t*)pPixelDest; + const uint32_t* pSrc = (uint32_t*)pPixelSrc; + uint32_t* pEnd = pDest + count; + while (pDest < pEnd) + { + *pDest++ = *pSrc++; + } + } + + static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count) + { + uint32_t* pDest = (uint32_t*)pPixelDest; + const uint32_t* pSrc = (const uint32_t*)pPixelSrc; + uint32_t* pEnd = pDest + count; + while (pDest < pEnd) + { + *pDest++ = pgm_read_dword(pSrc++); + } + } + + static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint32_t* pDest = (uint32_t*)pPixelDest; + const uint32_t* pSrc = (uint32_t*)pPixelSrc; + uint32_t* pDestBack = pDest + count; + const uint32_t* pSrcBack = pSrc + count; + while (pDestBack > pDest) + { + *--pDestBack = *--pSrcBack; + } + } + + typedef RgbwColor ColorObject; +}; + + +class Neo3ElementsNoSettings : public Neo3Elements +{ +public: + typedef NeoNoSettings SettingsObject; + static const size_t SettingsSize = 0; + + static void applySettings(uint8_t*, const SettingsObject&) + { + } + + static uint8_t* pixels(uint8_t* pData) + { + return pData; + } + + static const uint8_t* pixels(const uint8_t* pData) + { + return pData; + } +}; + +class Neo4ElementsNoSettings : public Neo4Elements +{ +public: + typedef NeoNoSettings SettingsObject; + static const size_t SettingsSize = 0; + + static void applySettings(uint8_t*, const SettingsObject&) + { + } + + static uint8_t* pixels(uint8_t* pData) + { + return pData; + } + + static const uint8_t* pixels(const uint8_t* pData) + { + return pData; + } +}; + +class NeoGrbFeature : public Neo3ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = color.G; + *p++ = color.R; + *p = color.B; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.G = *p++; + color.R = *p++; + color.B = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.G = pgm_read_byte(p++); + color.R = pgm_read_byte(p++); + color.B = pgm_read_byte(p); + + return color; + } + +}; + +class NeoGrbwFeature : public Neo4ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = color.G; + *p++ = color.R; + *p++ = color.B; + *p = color.W; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.G = *p++; + color.R = *p++; + color.B = *p++; + color.W = *p; + + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.G = pgm_read_byte(p++); + color.R = pgm_read_byte(p++); + color.B = pgm_read_byte(p++); + color.W = pgm_read_byte(p); + + return color; + } + +}; + +class NeoRgbwFeature : public Neo4ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = color.R; + *p++ = color.G; + *p++ = color.B; + *p = color.W; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.R = *p++; + color.G = *p++; + color.B = *p++; + color.W = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.R = pgm_read_byte(p++); + color.G = pgm_read_byte(p++); + color.B = pgm_read_byte(p++); + color.W = pgm_read_byte(p); + + return color; + } + +}; + +class NeoRgbFeature : public Neo3ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = color.R; + *p++ = color.G; + *p = color.B; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.R = *p++; + color.G = *p++; + color.B = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.R = pgm_read_byte(p++); + color.G = pgm_read_byte(p++); + color.B = pgm_read_byte(p); + + return color; + } + +}; + +class NeoBrgFeature : public Neo3ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = color.B; + *p++ = color.R; + *p = color.G; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.B = *p++; + color.R = *p++; + color.G = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.B = pgm_read_byte(p++); + color.R = pgm_read_byte(p++); + color.G = pgm_read_byte(p); + + return color; + } + +}; + +class NeoRbgFeature : public Neo3ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = color.R; + *p++ = color.B; + *p = color.G; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.R = *p++; + color.B = *p++; + color.G = *p; + + return color; + } + + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.R = pgm_read_byte(p++); + color.B = pgm_read_byte(p++); + color.G = pgm_read_byte(p); + + return color; + } + +}; diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoDib.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoDib.h new file mode 100644 index 0000000..9ede9b1 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoDib.h @@ -0,0 +1,208 @@ +/*------------------------------------------------------------------------- +NeoPixel library + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +template class NeoShaderNop +{ +public: + NeoShaderNop() + { + } + + bool IsDirty() const + { + return true; + }; + + void Dirty() + { + }; + + void ResetDirty() + { + }; + + T_COLOR_OBJECT Apply(uint16_t, T_COLOR_OBJECT color) + { + return color; + }; +}; + +class NeoShaderBase +{ +public: + NeoShaderBase() : + _state(0) + { + } + + bool IsDirty() const + { + return (_state & NEO_DIRTY); + }; + + void Dirty() + { + _state |= NEO_DIRTY; + }; + + void ResetDirty() + { + _state &= ~NEO_DIRTY; + }; + +protected: + uint8_t _state; // internal state +}; + +template class NeoDib +{ +public: + NeoDib(uint16_t countPixels) : + _countPixels(countPixels), + _state(0) + { + _pixels = (T_COLOR_OBJECT*)malloc(PixelsSize()); + ResetDirty(); + } + + ~NeoDib() + { + free((uint8_t*)_pixels); + } + + NeoDib& operator=(const NeoDib& other) + { + // check for self-assignment + if (&other == this) + { + return *this; + } + + uint16_t copyCount = other.PixelCount() < PixelCount() ? other.PixelCount() : PixelCount(); + + for (uint16_t pixel = 0; pixel < copyCount; pixel++) + { + _pixels[pixel] = other.Pixels()[pixel]; + } + + Dirty(); + return *this; + } + + T_COLOR_OBJECT* Pixels() const + { + return _pixels; + }; + + uint16_t PixelCount() const + { + return _countPixels; + }; + + size_t PixelsSize() const + { + return _countPixels * PixelSize(); + }; + + size_t PixelSize() const + { + return sizeof(T_COLOR_OBJECT); + }; + + void SetPixelColor( + uint16_t indexPixel, + T_COLOR_OBJECT color) + { + if (indexPixel < PixelCount()) + { + _pixels[indexPixel] = color; + Dirty(); + } + }; + + T_COLOR_OBJECT GetPixelColor( + uint16_t indexPixel) const + { + if (indexPixel >= PixelCount()) + { + return 0; + } + return _pixels[indexPixel]; + }; + + void ClearTo(T_COLOR_OBJECT color) + { + for (uint16_t pixel = 0; pixel < PixelCount(); pixel++) + { + _pixels[pixel] = color; + } + Dirty(); + }; + + template + void Render(NeoBufferContext destBuffer, T_SHADER& shader, uint16_t destIndexPixel = 0) + { + if (IsDirty() || shader.IsDirty()) + { + uint16_t countPixels = destBuffer.PixelCount(); + + if (countPixels > _countPixels) + { + countPixels = _countPixels; + } + + for (uint16_t indexPixel = 0; indexPixel < countPixels; indexPixel++) + { + T_COLOR_OBJECT color = shader.Apply(indexPixel, _pixels[indexPixel]); + T_COLOR_FEATURE::applyPixelColor(destBuffer.Pixels, destIndexPixel + indexPixel, color); + } + + shader.ResetDirty(); + ResetDirty(); + } + } + + bool IsDirty() const + { + return (_state & NEO_DIRTY); + }; + + void Dirty() + { + _state |= NEO_DIRTY; + }; + + void ResetDirty() + { + _state &= ~NEO_DIRTY; + }; + +private: + const uint16_t _countPixels; // Number of RGB LEDs in strip + T_COLOR_OBJECT* _pixels; + uint8_t _state; // internal state +}; \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoEase.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEase.h new file mode 100644 index 0000000..77a3460 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEase.h @@ -0,0 +1,313 @@ +/*------------------------------------------------------------------------- +NeoEase provides animation curve equations for animation support. + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#if defined(NEOPIXEBUS_NO_STL) + +typedef float(*AnimEaseFunction)(float unitValue); + +#else + +#undef max +#undef min +#include +typedef std::function AnimEaseFunction; + +#endif + +class NeoEase +{ +public: + static float Linear(float unitValue) + { + return unitValue; + } + + static float QuadraticIn(float unitValue) + { + return unitValue * unitValue; + } + + static float QuadraticOut(float unitValue) + { + return (-unitValue * (unitValue - 2.0f)); + } + + static float QuadraticInOut(float unitValue) + { + unitValue *= 2.0f; + if (unitValue < 1.0f) + { + return (0.5f * unitValue * unitValue); + } + else + { + unitValue -= 1.0f; + return (-0.5f * (unitValue * (unitValue - 2.0f) - 1.0f)); + } + } + + static float QuadraticCenter(float unitValue) + { + unitValue *= 2.0f; + if (unitValue < 1.0f) + { + return (-0.5f * (unitValue * unitValue - 2.0f)); + } + else + { + unitValue -= 1.0f; + return (0.5f * (unitValue * unitValue + 1.0f)); + } + } + + static float CubicIn(float unitValue) + { + return (unitValue * unitValue * unitValue); + } + + static float CubicOut(float unitValue) + { + unitValue -= 1.0f; + return (unitValue * unitValue * unitValue + 1.0f); + } + + static float CubicInOut(float unitValue) + { + unitValue *= 2.0f; + if (unitValue < 1.0f) + { + return (0.5f * unitValue * unitValue * unitValue); + } + else + { + unitValue -= 2.0f; + return (0.5f * (unitValue * unitValue * unitValue + 2.0f)); + } + } + + static float CubicCenter(float unitValue) + { + unitValue *= 2.0f; + unitValue -= 1.0f; + return (0.5f * (unitValue * unitValue * unitValue + 1.0f)); + } + + static float QuarticIn(float unitValue) + { + return (unitValue * unitValue * unitValue * unitValue); + } + + static float QuarticOut(float unitValue) + { + unitValue -= 1.0f; + return -(unitValue * unitValue * unitValue * unitValue - 1.0f); + } + + static float QuarticInOut(float unitValue) + { + unitValue *= 2.0f; + if (unitValue < 1.0f) + { + return (0.5f * unitValue * unitValue * unitValue * unitValue); + } + else + { + unitValue -= 2.0f; + return (-0.5f * (unitValue * unitValue * unitValue * unitValue - 2.0f)); + } + } + + static float QuarticCenter(float unitValue) + { + unitValue *= 2.0f; + unitValue -= 1.0f; + if (unitValue < 0.0f) + { + return (-0.5f * (unitValue * unitValue * unitValue * unitValue - 1.0f)); + } + else + { + return (0.5f * (unitValue * unitValue * unitValue * unitValue + 1.0f)); + } + } + + static float QuinticIn(float unitValue) + { + return (unitValue * unitValue * unitValue * unitValue * unitValue); + } + + static float QuinticOut(float unitValue) + { + unitValue -= 1.0f; + return (unitValue * unitValue * unitValue * unitValue * unitValue + 1.0f); + } + + static float QuinticInOut(float unitValue) + { + unitValue *= 2.0f; + if (unitValue < 1.0f) + { + return (0.5f * unitValue * unitValue * unitValue * unitValue * unitValue); + } + else + { + unitValue -= 2.0f; + return (0.5f * (unitValue * unitValue * unitValue * unitValue * unitValue + 2.0f)); + } + } + + static float QuinticCenter(float unitValue) + { + unitValue *= 2.0f; + unitValue -= 1.0f; + return (0.5f * (unitValue * unitValue * unitValue * unitValue * unitValue + 1.0f)); + } + + static float SinusoidalIn(float unitValue) + { + return (-cos(unitValue * HALF_PI) + 1.0f); + } + + static float SinusoidalOut(float unitValue) + { + return (sin(unitValue * HALF_PI)); + } + + static float SinusoidalInOut(float unitValue) + { + return -0.5f * (cos(PI * unitValue) - 1.0f); + } + + static float SinusoidalCenter(float unitValue) + { + if (unitValue < 0.5f) + { + return (0.5f * sin(PI * unitValue)); + } + else + { + return (-0.5f * (cos(PI * (unitValue-0.5f)) + 1.0f)); + } + + } + + static float ExponentialIn(float unitValue) + { + return (pow(2, 10.0f * (unitValue - 1.0f))); + } + + static float ExponentialOut(float unitValue) + { + return (-pow(2, -10.0f * unitValue) + 1.0f); + } + + static float ExponentialInOut(float unitValue) + { + unitValue *= 2.0f; + if (unitValue < 1.0f) + { + return (0.5f * pow(2, 10.0f * (unitValue - 1.0f))); + } + else + { + unitValue -= 1.0f; + return (0.5f * (-pow(2, -10.0f * unitValue) + 2.0f)); + } + } + + static float ExponentialCenter(float unitValue) + { + unitValue *= 2.0f; + if (unitValue < 1.0f) + { + return (0.5f * (-pow(2, -10.0f * unitValue) + 1.0f)); + } + else + { + unitValue -= 2.0f; + return (0.5f * (pow(2, 10.0f * unitValue) + 1.0f)); + } + } + + static float CircularIn(float unitValue) + { + if (unitValue == 1.0f) + { + return 1.0f; + } + else + { + return (-(sqrt(1.0f - unitValue * unitValue) - 1.0f)); + } + } + + static float CircularOut(float unitValue) + { + unitValue -= 1.0f; + return (sqrt(1.0f - unitValue * unitValue)); + } + + static float CircularInOut(float unitValue) + { + unitValue *= 2.0f; + if (unitValue < 1.0f) + { + return (-0.5f * (sqrt(1.0f - unitValue * unitValue) - 1.0f)); + } + else + { + unitValue -= 2.0f; + return (0.5f * (sqrt(1.0f - unitValue * unitValue) + 1.0f)); + } + } + + static float CircularCenter(float unitValue) + { + unitValue *= 2.0f; + unitValue -= 1.0f; + + if (unitValue < 0.0f) + { + return (0.5f * sqrt(1.0f - unitValue * unitValue)); + } + else if (unitValue > 0.0f) + { + unitValue -= 2.0f; + return (-0.5f * (sqrt(1.0f - unitValue * unitValue) - 1.0f ) + 0.5f); + } + else + { + return 1.0f; + } + } + + static float Gamma(float unitValue) + { + return pow(unitValue, 1.0f / 0.45f); + } +}; \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32I2sMethod.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32I2sMethod.h new file mode 100644 index 0000000..b3b8ee1 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32I2sMethod.h @@ -0,0 +1,276 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp32. + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#ifdef ARDUINO_ARCH_ESP32 + +extern "C" +{ +#include +#include "Esp32_i2s.h" +} + +const uint16_t c_dmaBytesPerPixelBytes = 4; + +class NeoEsp32I2sSpeedWs2812x +{ +public: + const static uint32_t I2sSampleRate = 100000; + const static uint16_t ByteSendTimeUs = 10; + const static uint16_t ResetTimeUs = 300; +}; + +class NeoEsp32I2sSpeedSk6812 +{ +public: + const static uint32_t I2sSampleRate = 100000; + const static uint16_t ByteSendTimeUs = 10; + const static uint16_t ResetTimeUs = 80; +}; + +class NeoEsp32I2sSpeedTm1814 +{ +public: + const static uint32_t I2sSampleRate = 100000; + const static uint16_t ByteSendTimeUs = 10; + const static uint16_t ResetTimeUs = 200; +}; + +class NeoEsp32I2sSpeed800Kbps +{ +public: + const static uint32_t I2sSampleRate = 100000; + const static uint16_t ByteSendTimeUs = 10; + const static uint16_t ResetTimeUs = 50; +}; + +class NeoEsp32I2sSpeed400Kbps +{ +public: + const static uint32_t I2sSampleRate = 50000; + const static uint16_t ByteSendTimeUs = 20; + const static uint16_t ResetTimeUs = 50; +}; + +class NeoEsp32I2sSpeedApa106 +{ +public: + const static uint32_t I2sSampleRate = 76000; + const static uint16_t ByteSendTimeUs = 14; + const static uint16_t ResetTimeUs = 50; +}; + +class NeoEsp32I2sBusZero +{ +public: + const static uint8_t I2sBusNumber = 0; +}; + +class NeoEsp32I2sBusOne +{ +public: + const static uint8_t I2sBusNumber = 1; +}; + +class NeoEsp32I2sNotInverted +{ +public: + const static bool Inverted = false; +}; + +class NeoEsp32I2sInverted +{ +public: + const static bool Inverted = true; +}; + +template class NeoEsp32I2sMethodBase +{ +public: + NeoEsp32I2sMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + _pin(pin) + { + uint16_t dmaSettingsSize = c_dmaBytesPerPixelBytes * settingsSize; + uint16_t dmaPixelSize = c_dmaBytesPerPixelBytes * elementSize; + uint16_t resetSize = c_dmaBytesPerPixelBytes * T_SPEED::ResetTimeUs / T_SPEED::ByteSendTimeUs; + + _i2sBufferSize = pixelCount * dmaPixelSize + dmaSettingsSize + resetSize; + + // must have a 4 byte aligned buffer for i2s + uint32_t alignment = _i2sBufferSize % 4; + if (alignment) + { + _i2sBufferSize += 4 - alignment; + } + + _data = static_cast(malloc(_sizeData)); + memset(_data, 0x00, _sizeData); + + _i2sBuffer = static_cast(malloc(_i2sBufferSize)); + memset(_i2sBuffer, 0x00, _i2sBufferSize); + } + + ~NeoEsp32I2sMethodBase() + { + while (!IsReadyToUpdate()) + { + yield(); + } + + pinMode(_pin, INPUT); + + free(_data); + free(_i2sBuffer); + } + + bool IsReadyToUpdate() const + { + return (i2sWriteDone(T_BUS::I2sBusNumber)); + } + + void Initialize() + { + size_t dmaCount = (_i2sBufferSize + I2S_DMA_MAX_DATA_LEN - 1) / I2S_DMA_MAX_DATA_LEN; + i2sInit(T_BUS::I2sBusNumber, 16, T_SPEED::I2sSampleRate, I2S_CHAN_STEREO, I2S_FIFO_16BIT_DUAL, dmaCount, 0); + i2sSetPins(T_BUS::I2sBusNumber, _pin, T_INVERT::Inverted); + } + + void Update(bool) + { + // wait for not actively sending data + while (!IsReadyToUpdate()) + { + yield(); + } + + FillBuffers(); + + i2sWrite(T_BUS::I2sBusNumber, _i2sBuffer, _i2sBufferSize, false, false); + } + + uint8_t* getData() const + { + return _data; + }; + + size_t getDataSize() const + { + return _sizeData; + } + +private: + const size_t _sizeData; // Size of '_data' buffer + const uint8_t _pin; // output pin number + + uint8_t* _data; // Holds LED color values + + uint32_t _i2sBufferSize; // total size of _i2sBuffer + uint8_t* _i2sBuffer; // holds the DMA buffer that is referenced by _i2sBufDesc + + void FillBuffers() + { + const uint16_t bitpatterns[16] = + { + 0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110, + 0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110, + 0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110, + 0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, + }; + + uint16_t* pDma = reinterpret_cast(_i2sBuffer); + uint8_t* pEnd = _data + _sizeData; + for (uint8_t* pPixel = _data; pPixel < pEnd; pPixel++) + { + *(pDma++) = bitpatterns[((*pPixel) & 0x0f)]; + *(pDma++) = bitpatterns[((*pPixel) >> 4) & 0x0f]; + } + } +}; + +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Ws2812xMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Sk6812Method; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Tm1814Method; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0800KbpsMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0400KbpsMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Apa106Method; + + +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Ws2812xInvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Sk6812InvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Tm1814InvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0800KbpsInvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0400KbpsInvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s0Apa106InvertedMethod; + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) +// (I2S_NUM_MAX == 2) + +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Ws2812xMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Sk6812Method; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Tm1814Method; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1800KbpsMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1400KbpsMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Apa106Method; + +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Ws2812xInvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Sk6812InvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Tm1814InvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1800KbpsInvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1400KbpsInvertedMethod; +typedef NeoEsp32I2sMethodBase NeoEsp32I2s1Apa106InvertedMethod; + +#endif + +/* due to a core issue where requests to send aren't consistent, I2s is no longer the default +// I2s Bus 1 method is the default method for Esp32 +typedef NeoEsp32I2s1Ws2812xMethod NeoWs2813Method; +typedef NeoEsp32I2s1Ws2812xMethod NeoWs2812xMethod; +typedef NeoEsp32I2s1800KbpsMethod NeoWs2812Method; +typedef NeoEsp32I2s1Ws2812xMethod NeoWs2811Method; +typedef NeoEsp32I2s1Sk6812Method NeoSk6812Method; +typedef NeoEsp32I2s1Tm1814Method NeoTm1814Method; +typedef NeoEsp32I2s1Sk6812Method NeoLc8812Method; +typedef NeoEsp32I2s1Apa106Method NeoApa106Method; + +typedef NeoEsp32I2s1Ws2812xMethod Neo800KbpsMethod; +typedef NeoEsp32I2s1400KbpsMethod Neo400KbpsMethod; + +typedef NeoEsp32I2s1Ws2812xInvertedMethod NeoWs2813InvertedMethod; +typedef NeoEsp32I2s1Ws2812xInvertedMethod NeoWs2812xInvertedMethod; +typedef NeoEsp32I2s1Ws2812xInvertedMethod NeoWs2811InvertedMethod; +typedef NeoEsp32I2s1800KbpsInvertedMethod NeoWs2812InvertedMethod; +typedef NeoEsp32I2s1Sk6812InvertedMethod NeoSk6812InvertedMethod; +typedef NeoEsp32I2s1Tm1814InvertedMethod NeoTm1814InvertedMethod; +typedef NeoEsp32I2s1Sk6812InvertedMethod NeoLc8812InvertedMethod; +typedef NeoEsp32I2s1Apa106InvertedMethod NeoApa106InvertedMethod; + +typedef NeoEsp32I2s1Ws2812xInvertedMethod Neo800KbpsInvertedMethod; +typedef NeoEsp32I2s1400KbpsInvertedMethod Neo400KbpsInvertedMethod; +*/ + +#endif \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32RmtMethod.cpp b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32RmtMethod.cpp new file mode 100644 index 0000000..278d56d --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32RmtMethod.cpp @@ -0,0 +1,262 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp32. + +A BIG thanks to Andreas Merkle for the investigation and implementation of +a workaround to the GCC bug that drops method attributes from template methods + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#include "NeoEsp32RmtMethod.h" + +#ifdef ARDUINO_ARCH_ESP32 + + +// translate NeoPixelBuffer into RMT buffer +// this is done on the fly so we don't require a send buffer in raw RMT format +// which would be 32x larger than the primary buffer +// +// NOTE: This was moved from the template below to here to workaround a GCC bug +// That bug is that the IRAM_ATTR attribute (any attributes) is lost on template classes. +// +// Further, it was removed from the header to support current Esp32 release +// which will need to be removed when the latest GitHub branchis released +// due to this method will not get inlined this way +// +void NeoEsp32RmtSpeed::_translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num, + const uint32_t rmtBit0, + const uint32_t rmtBit1, + const uint16_t rmtDurationReset) +{ + if (src == NULL || dest == NULL) + { + *translated_size = 0; + *item_num = 0; + return; + } + + size_t size = 0; + size_t num = 0; + const uint8_t* psrc = static_cast(src); + rmt_item32_t* pdest = dest; + + for (;;) + { + uint8_t data = *psrc; + + for (uint8_t bit = 0; bit < 8; bit++) + { + pdest->val = (data & 0x80) ? rmtBit1 : rmtBit0; + pdest++; + data <<= 1; + } + num += 8; + size++; + + // if this is the last byte we need to adjust the length of the last pulse + if (size >= src_size) + { + // extend the last bits LOW value to include the full reset signal length + pdest--; + pdest->duration1 = rmtDurationReset; + // and stop updating data to send + break; + } + + if (num >= wanted_num) + { + // stop updating data to send + break; + } + + psrc++; + } + + *translated_size = size; + *item_num = num; +} + + +// these are required due to the linker error with ISRs +// dangerous relocation: l32r: literal placed after use +// https://stackoverflow.com/questions/19532826/what-does-a-dangerous-relocation-error-mean +// +void NeoEsp32RmtSpeedWs2811::Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num) +{ + _translate(src, dest, src_size, wanted_num, translated_size, item_num, + RmtBit0, RmtBit1, RmtDurationReset); +} + +void NeoEsp32RmtSpeedWs2812x::Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num) +{ + _translate(src, dest, src_size, wanted_num, translated_size, item_num, + RmtBit0, RmtBit1, RmtDurationReset); +} + +void NeoEsp32RmtSpeedSk6812::Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num) +{ + _translate(src, dest, src_size, wanted_num, translated_size, item_num, + RmtBit0, RmtBit1, RmtDurationReset); +} + +void NeoEsp32RmtSpeedTm1814::Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num) +{ + _translate(src, dest, src_size, wanted_num, translated_size, item_num, + RmtBit0, RmtBit1, RmtDurationReset); +} + +void NeoEsp32RmtSpeed800Kbps::Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num) +{ + _translate(src, dest, src_size, wanted_num, translated_size, item_num, + RmtBit0, RmtBit1, RmtDurationReset); +} + +void NeoEsp32RmtSpeed400Kbps::Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num) +{ + _translate(src, dest, src_size, wanted_num, translated_size, item_num, + RmtBit0, RmtBit1, RmtDurationReset); +} + +void NeoEsp32RmtSpeedApa106::Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num) +{ + _translate(src, dest, src_size, wanted_num, translated_size, item_num, + RmtBit0, RmtBit1, RmtDurationReset); +} + +void NeoEsp32RmtInvertedSpeedWs2811::Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num) +{ + _translate(src, dest, src_size, wanted_num, translated_size, item_num, + RmtBit0, RmtBit1, RmtDurationReset); +} + +void NeoEsp32RmtInvertedSpeedWs2812x::Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num) +{ + _translate(src, dest, src_size, wanted_num, translated_size, item_num, + RmtBit0, RmtBit1, RmtDurationReset); +} + +void NeoEsp32RmtInvertedSpeedSk6812::Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num) +{ + _translate(src, dest, src_size, wanted_num, translated_size, item_num, + RmtBit0, RmtBit1, RmtDurationReset); +} + +void NeoEsp32RmtInvertedSpeedTm1814::Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num) +{ + _translate(src, dest, src_size, wanted_num, translated_size, item_num, + RmtBit0, RmtBit1, RmtDurationReset); +} + +void NeoEsp32RmtInvertedSpeed800Kbps::Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num) +{ + _translate(src, dest, src_size, wanted_num, translated_size, item_num, + RmtBit0, RmtBit1, RmtDurationReset); +} + +void NeoEsp32RmtInvertedSpeed400Kbps::Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num) +{ + _translate(src, dest, src_size, wanted_num, translated_size, item_num, + RmtBit0, RmtBit1, RmtDurationReset); +} + +void NeoEsp32RmtInvertedSpeedApa106::Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num) +{ + _translate(src, dest, src_size, wanted_num, translated_size, item_num, + RmtBit0, RmtBit1, RmtDurationReset); +} +#endif \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32RmtMethod.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32RmtMethod.h new file mode 100644 index 0000000..4d633ba --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp32RmtMethod.h @@ -0,0 +1,668 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp32. + +A BIG thanks to Andreas Merkle for the investigation and implementation of +a workaround to the GCC bug that drops method attributes from template methods + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#ifdef ARDUINO_ARCH_ESP32 + +/* General Reference documentation for the APIs used in this implementation +LOW LEVEL: (what is actually used) +DOCS: https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html +EXAMPLE: https://github.com/espressif/esp-idf/blob/826ff7186ae07dc81e960a8ea09ebfc5304bfb3b/examples/peripherals/rmt_tx/main/rmt_tx_main.c + +HIGHER LEVEL: +NO TRANSLATE SUPPORT so this was not used +NOTE: https://github.com/espressif/arduino-esp32/commit/50d142950d229b8fabca9b749dc4a5f2533bc426 +Esp32-hal-rmt.h +Esp32-hal-rmt.c +*/ + +#include + +extern "C" +{ +#include +} + +class NeoEsp32RmtSpeed +{ +public: + // ClkDiv of 2 provides for good resolution and plenty of reset resolution; but + // a ClkDiv of 1 will provide enough space for the longest reset and does show + // little better pulse accuracy + const static uint8_t RmtClockDivider = 2; + + inline constexpr static uint32_t FromNs(uint32_t ns) + { + return ns / NsPerRmtTick; + } + +protected: + const static uint32_t RmtCpu = 80000000L; // 80 mhz RMT clock + const static uint32_t NsPerSecond = 1000000000L; + const static uint32_t RmtTicksPerSecond = (RmtCpu / RmtClockDivider); + const static uint32_t NsPerRmtTick = (NsPerSecond / RmtTicksPerSecond); // about 25 + + static void IRAM_ATTR _translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num, + const uint32_t rmtBit0, + const uint32_t rmtBit1, + const uint16_t rmtDurationReset); + +}; + +class NeoEsp32RmtSpeedBase : public NeoEsp32RmtSpeed +{ +public: + // this is used rather than the rmt_item32_t as you can't correctly initialize + // it as a static constexpr within the template + inline constexpr static uint32_t Item32Val(uint16_t nsHigh, uint16_t nsLow) + { + return (FromNs(nsLow) << 16) | (1 << 15) | (FromNs(nsHigh)); + } + + const static rmt_idle_level_t IdleLevel = RMT_IDLE_LEVEL_LOW; +}; + +class NeoEsp32RmtInvertedSpeedBase : public NeoEsp32RmtSpeed +{ +public: + // this is used rather than the rmt_item32_t as you can't correctly initialize + // it as a static constexpr within the template + inline constexpr static uint32_t Item32Val(uint16_t nsHigh, uint16_t nsLow) + { + return (FromNs(nsLow) << 16) | (1 << 31) | (FromNs(nsHigh)); + } + + const static rmt_idle_level_t IdleLevel = RMT_IDLE_LEVEL_HIGH; +}; + +class NeoEsp32RmtSpeedWs2811 : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 950); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(900, 350); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us + + static void IRAM_ATTR Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num); +}; + +class NeoEsp32RmtSpeedWs2812x : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us + + static void IRAM_ATTR Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num); +}; + +class NeoEsp32RmtSpeedSk6812 : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(80000); // 80us + + static void IRAM_ATTR Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num); +}; + +// normal is inverted signal +class NeoEsp32RmtSpeedTm1814 : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(360, 890); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(720, 530); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us + + static void IRAM_ATTR Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num); +}; + +class NeoEsp32RmtSpeed800Kbps : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us + + static void IRAM_ATTR Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num); +}; + +class NeoEsp32RmtSpeed400Kbps : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(800, 1700); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1600, 900); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us + + static void IRAM_ATTR Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num); +}; + +class NeoEsp32RmtSpeedApa106 : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 1250); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1250, 400); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us + + static void IRAM_ATTR Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num); +}; + +class NeoEsp32RmtInvertedSpeedWs2811 : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 950); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(900, 350); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us + + static void IRAM_ATTR Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num); +}; + +class NeoEsp32RmtInvertedSpeedWs2812x : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us + + static void IRAM_ATTR Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num); +}; + +class NeoEsp32RmtInvertedSpeedSk6812 : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(80000); // 80us + + static void IRAM_ATTR Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num); +}; + +// normal is inverted signal +class NeoEsp32RmtInvertedSpeedTm1814 : public NeoEsp32RmtSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(360, 890); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(720, 530); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us + + static void IRAM_ATTR Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num); +}; + +class NeoEsp32RmtInvertedSpeed800Kbps : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us + + static void IRAM_ATTR Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num); +}; + +class NeoEsp32RmtInvertedSpeed400Kbps : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(800, 1700); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1600, 900); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us + + static void IRAM_ATTR Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num); +}; + +class NeoEsp32RmtInvertedSpeedApa106 : public NeoEsp32RmtInvertedSpeedBase +{ +public: + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 1250); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1250, 400); + const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us + + static void IRAM_ATTR Translate(const void* src, + rmt_item32_t* dest, + size_t src_size, + size_t wanted_num, + size_t* translated_size, + size_t* item_num); +}; + +class NeoEsp32RmtChannel0 +{ +public: + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_0; +}; + +class NeoEsp32RmtChannel1 +{ +public: + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_1; +}; + +class NeoEsp32RmtChannel2 +{ +public: + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_2; +}; + +class NeoEsp32RmtChannel3 +{ +public: + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_3; +}; + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) + +class NeoEsp32RmtChannel4 +{ +public: + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_4; +}; + +class NeoEsp32RmtChannel5 +{ +public: + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_5; +}; + +class NeoEsp32RmtChannel6 +{ +public: + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_6; +}; + +class NeoEsp32RmtChannel7 +{ +public: + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_7; +}; + +#endif + +template class NeoEsp32RmtMethodBase +{ +public: + NeoEsp32RmtMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + _pin(pin) + { + _dataEditing = static_cast(malloc(_sizeData)); + memset(_dataEditing, 0x00, _sizeData); + + _dataSending = static_cast(malloc(_sizeData)); + // no need to initialize it, it gets overwritten on every send + } + + ~NeoEsp32RmtMethodBase() + { + // wait until the last send finishes before destructing everything + // arbitrary time out of 10 seconds + ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_wait_tx_done(T_CHANNEL::RmtChannelNumber, 10000 / portTICK_PERIOD_MS)); + + ESP_ERROR_CHECK(rmt_driver_uninstall(T_CHANNEL::RmtChannelNumber)); + + free(_dataEditing); + free(_dataSending); + } + + + bool IsReadyToUpdate() const + { + return (ESP_OK == rmt_wait_tx_done(T_CHANNEL::RmtChannelNumber, 0)); + } + + void Initialize() + { + rmt_config_t config; + + config.rmt_mode = RMT_MODE_TX; + config.channel = T_CHANNEL::RmtChannelNumber; + config.gpio_num = static_cast(_pin); + config.mem_block_num = 1; + config.tx_config.loop_en = false; + + config.tx_config.idle_output_en = true; + config.tx_config.idle_level = T_SPEED::IdleLevel; + + config.tx_config.carrier_en = false; + config.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW; + + config.clk_div = T_SPEED::RmtClockDivider; + + ESP_ERROR_CHECK(rmt_config(&config)); + ESP_ERROR_CHECK(rmt_driver_install(T_CHANNEL::RmtChannelNumber, 0, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1)); + ESP_ERROR_CHECK(rmt_translator_init(T_CHANNEL::RmtChannelNumber, T_SPEED::Translate)); + } + + void Update(bool maintainBufferConsistency) + { + // wait for not actively sending data + // this will time out at 10 seconds, an arbitrarily long period of time + // and do nothing if this happens + if (ESP_OK == ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_wait_tx_done(T_CHANNEL::RmtChannelNumber, 10000 / portTICK_PERIOD_MS))) + { + // now start the RMT transmit with the editing buffer before we swap + ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_write_sample(T_CHANNEL::RmtChannelNumber, _dataEditing, _sizeData, false)); + + if (maintainBufferConsistency) + { + // copy editing to sending, + // this maintains the contract that "colors present before will + // be the same after", otherwise GetPixelColor will be inconsistent + memcpy(_dataSending, _dataEditing, _sizeData); + } + + // swap so the user can modify without affecting the async operation + std::swap(_dataSending, _dataEditing); + } + } + + uint8_t* getData() const + { + return _dataEditing; + }; + + size_t getDataSize() const + { + return _sizeData; + } + +private: + const size_t _sizeData; // Size of '_data*' buffers + const uint8_t _pin; // output pin number + + // Holds data stream which include LED color values and other settings as needed + uint8_t* _dataEditing; // exposed for get and set + uint8_t* _dataSending; // used for async send using RMT +}; + +// normal +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0400KbpsMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1400KbpsMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2400KbpsMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3400KbpsMethod; + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) +// (RMT_CHANNEL_MAX == 8) + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4400KbpsMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5400KbpsMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6400KbpsMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Ws2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Ws2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Sk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Tm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Apa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7400KbpsMethod; + +#endif + +// inverted +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt1400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt2400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt3400KbpsInvertedMethod; + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) +// (RMT_CHANNEL_MAX == 8) + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt4400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt5400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt6400KbpsInvertedMethod; + +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Ws2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Ws2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Sk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Tm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7Apa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32Rmt7400KbpsInvertedMethod; + +#endif + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) +// (RMT_CHANNEL_MAX == 8) +// due to a core issue where requests to send aren't consistent with I2s, RMT ch6 is temporarily the default +// RMT channel 6 method is the default method for Esp32 +typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2813Method; +typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2812xMethod; +typedef NeoEsp32Rmt6800KbpsMethod NeoWs2812Method; +typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2811Method; +typedef NeoEsp32Rmt6Sk6812Method NeoSk6812Method; +typedef NeoEsp32Rmt6Tm1814Method NeoTm1814Method; +typedef NeoEsp32Rmt6Sk6812Method NeoLc8812Method; +typedef NeoEsp32Rmt6Apa106Method NeoApa106Method; + +typedef NeoEsp32Rmt6Ws2812xMethod Neo800KbpsMethod; +typedef NeoEsp32Rmt6400KbpsMethod Neo400KbpsMethod; + +typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2813InvertedMethod; +typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2812xInvertedMethod; +typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2811InvertedMethod; +typedef NeoEsp32Rmt6800KbpsInvertedMethod NeoWs2812InvertedMethod; +typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoSk6812InvertedMethod; +typedef NeoEsp32Rmt6Tm1814InvertedMethod NeoTm1814InvertedMethod; +typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoLc8812InvertedMethod; +typedef NeoEsp32Rmt6Apa106InvertedMethod NeoApa106InvertedMethod; + +typedef NeoEsp32Rmt6Ws2812xInvertedMethod Neo800KbpsInvertedMethod; +typedef NeoEsp32Rmt6400KbpsInvertedMethod Neo400KbpsInvertedMethod; +#else + +// due to a core issue where requests to send aren't consistent with I2s, RMT ch3 is temporarily the default +// RMT channel 3 method is the default method for Esp32S2 +typedef NeoEsp32Rmt3Ws2812xMethod NeoWs2813Method; +typedef NeoEsp32Rmt3Ws2812xMethod NeoWs2812xMethod; +typedef NeoEsp32Rmt3800KbpsMethod NeoWs2812Method; +typedef NeoEsp32Rmt3Ws2812xMethod NeoWs2811Method; +typedef NeoEsp32Rmt3Sk6812Method NeoSk6812Method; +typedef NeoEsp32Rmt3Tm1814Method NeoTm1814Method; +typedef NeoEsp32Rmt3Sk6812Method NeoLc8812Method; +typedef NeoEsp32Rmt3Apa106Method NeoApa106Method; + +typedef NeoEsp32Rmt3Ws2812xMethod Neo800KbpsMethod; +typedef NeoEsp32Rmt3400KbpsMethod Neo400KbpsMethod; + +typedef NeoEsp32Rmt3Ws2812xInvertedMethod NeoWs2813InvertedMethod; +typedef NeoEsp32Rmt3Ws2812xInvertedMethod NeoWs2812xInvertedMethod; +typedef NeoEsp32Rmt3Ws2812xInvertedMethod NeoWs2811InvertedMethod; +typedef NeoEsp32Rmt3800KbpsInvertedMethod NeoWs2812InvertedMethod; +typedef NeoEsp32Rmt3Sk6812InvertedMethod NeoSk6812InvertedMethod; +typedef NeoEsp32Rmt3Tm1814InvertedMethod NeoTm1814InvertedMethod; +typedef NeoEsp32Rmt3Sk6812InvertedMethod NeoLc8812InvertedMethod; +typedef NeoEsp32Rmt3Apa106InvertedMethod NeoApa106InvertedMethod; + +typedef NeoEsp32Rmt3Ws2812xInvertedMethod Neo800KbpsInvertedMethod; +typedef NeoEsp32Rmt3400KbpsInvertedMethod Neo400KbpsInvertedMethod; + +#endif + +#endif diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266DmaMethod.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266DmaMethod.h new file mode 100644 index 0000000..be36eb3 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266DmaMethod.h @@ -0,0 +1,573 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp8266. + + +Written by Michael C. Miller. +Thanks to g3gg0.de for porting the initial DMA support which lead to this. +Thanks to github/cnlohr for the original work on DMA support, which opend +all our minds to a better way (located at https://github.com/cnlohr/esp8266ws2812i2s). + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#ifdef ARDUINO_ARCH_ESP8266 + +extern "C" +{ +#include "Arduino.h" +#include "osapi.h" +#include "ets_sys.h" + +#include "i2s_reg.h" +#include "i2s.h" +#include "eagle_soc.h" +#include "esp8266_peri.h" +#include "slc_register.h" + +#include "osapi.h" +#include "ets_sys.h" +#include "user_interface.h" + +#if !defined(__CORE_ESP8266_VERSION_H) || defined(ARDUINO_ESP8266_RELEASE_2_5_0) + void rom_i2c_writeReg_Mask(uint32_t block, uint32_t host_id, uint32_t reg_add, uint32_t Msb, uint32_t Lsb, uint32_t indata); +#endif +} + +struct slc_queue_item +{ + uint32 blocksize : 12; + uint32 datalen : 12; + uint32 unused : 5; + uint32 sub_sof : 1; + uint32 eof : 1; + uint32 owner : 1; + uint32 buf_ptr; + uint32 next_link_ptr; +}; + +class NeoEsp8266DmaSpeedBase +{ +public: + static const uint8_t Level = 0x00; + static uint16_t Convert(uint8_t value) + { + const uint16_t bitpatterns[16] = + { + 0b1000100010001000, 0b1000100010001110, 0b1000100011101000, 0b1000100011101110, + 0b1000111010001000, 0b1000111010001110, 0b1000111011101000, 0b1000111011101110, + 0b1110100010001000, 0b1110100010001110, 0b1110100011101000, 0b1110100011101110, + 0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110, + }; + + return bitpatterns[value]; + } +}; + +class NeoEsp8266DmaInvertedSpeedBase +{ +public: + static const uint8_t Level = 0xFF; + static uint16_t Convert(uint8_t value) + { + const uint16_t bitpatterns[16] = + { + 0b0111011101110111, 0b0111011101110001, 0b0111011100010111, 0b0111011100010001, + 0b0111000101110111, 0b0111000101110001, 0b0111000100010111, 0b0111000100010001, + 0b0001011101110111, 0b0001011101110001, 0b0001011100010111, 0b0001011100010001, + 0b0001000101110111, 0b0001000101110001, 0b0001000100010111, 0b0001000100010001, + }; + + return bitpatterns[value]; + } +}; + +class NeoEsp8266DmaSpeed800KbpsBase : public NeoEsp8266DmaSpeedBase +{ +public: + const static uint32_t I2sClockDivisor = 3; + const static uint32_t I2sBaseClockDivisor = 16; + const static uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800khz speed +}; + +class NeoEsp8266DmaSpeedWs2812x : public NeoEsp8266DmaSpeed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 300; +}; + +class NeoEsp8266DmaSpeedSk6812 : public NeoEsp8266DmaSpeed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 80; +}; + +class NeoEsp8266DmaInvertedSpeedTm1814 : public NeoEsp8266DmaSpeed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 200; +}; + +class NeoEsp8266DmaSpeed800Kbps : public NeoEsp8266DmaSpeed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 50; +}; + +class NeoEsp8266DmaSpeed400Kbps : public NeoEsp8266DmaSpeedBase +{ +public: + const static uint32_t I2sClockDivisor = 6; + const static uint32_t I2sBaseClockDivisor = 16; + const static uint32_t ByteSendTimeUs = 20; // us it takes to send a single pixel element at 400khz speed + const static uint32_t ResetTimeUs = 50; +}; + +class NeoEsp8266DmaSpeedApa106 : public NeoEsp8266DmaSpeedBase +{ +public: + const static uint32_t I2sClockDivisor = 4; + const static uint32_t I2sBaseClockDivisor = 16; + const static uint32_t ByteSendTimeUs = 17; // us it takes to send a single pixel element + const static uint32_t ResetTimeUs = 50; +}; + + + +class NeoEsp8266DmaInvertedSpeed800KbpsBase : public NeoEsp8266DmaInvertedSpeedBase +{ +public: + const static uint32_t I2sClockDivisor = 3; + const static uint32_t I2sBaseClockDivisor = 16; + const static uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800khz speed +}; + +class NeoEsp8266DmaInvertedSpeedWs2812x : public NeoEsp8266DmaInvertedSpeed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 300; +}; + +class NeoEsp8266DmaInvertedSpeedSk6812 : public NeoEsp8266DmaInvertedSpeed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 80; +}; + +class NeoEsp8266DmaSpeedTm1814 : public NeoEsp8266DmaInvertedSpeed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 200; +}; + +class NeoEsp8266DmaInvertedSpeed800Kbps : public NeoEsp8266DmaInvertedSpeed800KbpsBase +{ +public: + const static uint32_t ResetTimeUs = 50; +}; + +class NeoEsp8266DmaInvertedSpeed400Kbps : public NeoEsp8266DmaInvertedSpeedBase +{ +public: + const static uint32_t I2sClockDivisor = 6; + const static uint32_t I2sBaseClockDivisor = 16; + const static uint32_t ByteSendTimeUs = 20; // us it takes to send a single pixel element at 400khz speed + const static uint32_t ResetTimeUs = 50; +}; + +class NeoEsp8266DmaInvertedSpeedApa106 : public NeoEsp8266DmaInvertedSpeedBase +{ +public: + const static uint32_t I2sClockDivisor = 4; + const static uint32_t I2sBaseClockDivisor = 16; + const static uint32_t ByteSendTimeUs = 17; // us it takes to send a single pixel element + const static uint32_t ResetTimeUs = 50; +}; + +enum NeoDmaState +{ + NeoDmaState_Idle, + NeoDmaState_Pending, + NeoDmaState_Sending, + NeoDmaState_Zeroing, +}; +const uint16_t c_maxDmaBlockSize = 4095; +const uint16_t c_dmaBytesPerPixelBytes = 4; +const uint8_t c_I2sPin = 3; // due to I2S hardware, the pin used is restricted to this + +template class NeoEsp8266DmaMethodBase +{ +public: + NeoEsp8266DmaMethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize) + { + uint16_t dmaPixelSize = c_dmaBytesPerPixelBytes * elementSize; + uint16_t dmaSettingsSize = c_dmaBytesPerPixelBytes * settingsSize; + + _i2sBufferSize = pixelCount * dmaPixelSize + dmaSettingsSize; + + _data = static_cast(malloc(_sizeData)); + memset(_data, 0x00, _sizeData); + + _i2sBuffer = static_cast(malloc(_i2sBufferSize)); + memset(_i2sBuffer, T_SPEED::Level, _i2sBufferSize); + + // _i2sBuffer[0] = 0b11101000; // debug, 1 bit then 0 bit + + memset(_i2sZeroes, T_SPEED::Level, sizeof(_i2sZeroes)); + + _is2BufMaxBlockSize = (c_maxDmaBlockSize / dmaPixelSize) * dmaPixelSize; + + _i2sBufDescCount = (_i2sBufferSize / _is2BufMaxBlockSize) + 1 + 2; // need two more for state/latch blocks + _i2sBufDesc = (slc_queue_item*)malloc(_i2sBufDescCount * sizeof(slc_queue_item)); + + s_this = this; // store this for the ISR + } + + NeoEsp8266DmaMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + NeoEsp8266DmaMethodBase(pixelCount, elementSize, settingsSize) + { + } + + ~NeoEsp8266DmaMethodBase() + { + uint8_t waits = 1; + while (!IsReadyToUpdate()) + { + waits = 2; + yield(); + } + + // wait for any pending sends to complete + // due to internal i2s caching/send delays, this can more that once the data size + uint32_t time = micros(); + while ((micros() - time) < ((getPixelTime() + T_SPEED::ResetTimeUs) * waits)) + { + yield(); + } + + StopDma(); + + s_this = nullptr; + pinMode(c_I2sPin, INPUT); + + free(_data); + free(_i2sBuffer); + free(_i2sBufDesc); + } + + bool IsReadyToUpdate() const + { + return (_dmaState == NeoDmaState_Idle); + } + + void Initialize() + { + StopDma(); + + pinMode(c_I2sPin, FUNCTION_1); // I2S0_DATA + + uint8_t* is2Buffer = _i2sBuffer; + uint32_t is2BufferSize = _i2sBufferSize; + uint16_t indexDesc; + + // prepare main data block decriptors that point into our one static dma buffer + for (indexDesc = 0; indexDesc < (_i2sBufDescCount - 2); indexDesc++) + { + uint32_t blockSize = (is2BufferSize > _is2BufMaxBlockSize) ? _is2BufMaxBlockSize : is2BufferSize; + + _i2sBufDesc[indexDesc].owner = 1; + _i2sBufDesc[indexDesc].eof = 0; // no need to trigger interrupt generally + _i2sBufDesc[indexDesc].sub_sof = 0; + _i2sBufDesc[indexDesc].datalen = blockSize; + _i2sBufDesc[indexDesc].blocksize = blockSize; + _i2sBufDesc[indexDesc].buf_ptr = (uint32_t)is2Buffer; + _i2sBufDesc[indexDesc].unused = 0; + _i2sBufDesc[indexDesc].next_link_ptr = (uint32_t)&(_i2sBufDesc[indexDesc + 1]); + + is2Buffer += blockSize; + is2BufferSize -= blockSize; + } + + // prepare the two state/latch descriptors + for (; indexDesc < _i2sBufDescCount; indexDesc++) + { + _i2sBufDesc[indexDesc].owner = 1; + _i2sBufDesc[indexDesc].eof = 0; // no need to trigger interrupt generally + _i2sBufDesc[indexDesc].sub_sof = 0; + _i2sBufDesc[indexDesc].datalen = sizeof(_i2sZeroes); + _i2sBufDesc[indexDesc].blocksize = sizeof(_i2sZeroes); + _i2sBufDesc[indexDesc].buf_ptr = (uint32_t)_i2sZeroes; + _i2sBufDesc[indexDesc].unused = 0; + _i2sBufDesc[indexDesc].next_link_ptr = (uint32_t)&(_i2sBufDesc[indexDesc + 1]); + } + + // the first state block will trigger the interrupt + _i2sBufDesc[indexDesc - 2].eof = 1; + // the last state block will loop to the first state block by defualt + _i2sBufDesc[indexDesc - 1].next_link_ptr = (uint32_t)&(_i2sBufDesc[indexDesc - 2]); + + // setup the rest of i2s DMA + // + ETS_SLC_INTR_DISABLE(); + + // start off in sending state as that is what it will be all setup to be + // for the interrupt + _dmaState = NeoDmaState_Sending; + + SLCC0 |= SLCRXLR | SLCTXLR; + SLCC0 &= ~(SLCRXLR | SLCTXLR); + SLCIC = 0xFFFFFFFF; + + // Configure DMA + SLCC0 &= ~(SLCMM << SLCM); // clear DMA MODE + SLCC0 |= (1 << SLCM); // set DMA MODE to 1 + SLCRXDC |= SLCBINR | SLCBTNR; // enable INFOR_NO_REPLACE and TOKEN_NO_REPLACE + SLCRXDC &= ~(SLCBRXFE | SLCBRXEM | SLCBRXFM); // disable RX_FILL, RX_EOF_MODE and RX_FILL_MODE + + // Feed DMA the 1st buffer desc addr + // To send data to the I2S subsystem, counter-intuitively we use the RXLINK part, not the TXLINK as you might + // expect. The TXLINK part still needs a valid DMA descriptor, even if it's unused: the DMA engine will throw + // an error at us otherwise. Just feed it any random descriptor. + SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address + // set TX descriptor address. any random desc is OK, we don't use TX but it needs to be valid + SLCTXL |= (uint32)&(_i2sBufDesc[_i2sBufDescCount-1]) << SLCTXLA; + SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address + // set RX descriptor address. use first of the data addresses + SLCRXL |= (uint32)&(_i2sBufDesc[0]) << SLCRXLA; + + ETS_SLC_INTR_ATTACH(i2s_slc_isr, NULL); + SLCIE = SLCIRXEOF; // Enable only for RX EOF interrupt + + ETS_SLC_INTR_ENABLE(); + + //Start transmission + SLCTXL |= SLCTXLS; + SLCRXL |= SLCRXLS; + + I2S_CLK_ENABLE(); + I2SIC = 0x3F; + I2SIE = 0; + + //Reset I2S + I2SC &= ~(I2SRST); + I2SC |= I2SRST; + I2SC &= ~(I2SRST); + + // Set RX/TX FIFO_MOD=0 and disable DMA (FIFO only) + I2SFC &= ~(I2SDE | (I2STXFMM << I2STXFM) | (I2SRXFMM << I2SRXFM)); + I2SFC |= I2SDE; //Enable DMA + // Set RX/TX CHAN_MOD=0 + I2SCC &= ~((I2STXCMM << I2STXCM) | (I2SRXCMM << I2SRXCM)); + + // set the rate + uint32_t i2s_clock_div = T_SPEED::I2sClockDivisor & I2SCDM; + uint8_t i2s_bck_div = T_SPEED::I2sBaseClockDivisor & I2SBDM; + + //!trans master, !bits mod, rece slave mod, rece msb shift, right first, msb right + I2SC &= ~(I2STSM | I2SRSM | (I2SBMM << I2SBM) | (I2SBDM << I2SBD) | (I2SCDM << I2SCD)); + I2SC |= I2SRF | I2SMR | I2SRSM | I2SRMS | (i2s_bck_div << I2SBD) | (i2s_clock_div << I2SCD); + + I2SC |= I2STXS; // Start transmission + } + + void ICACHE_RAM_ATTR Update(bool) + { + // wait for not actively sending data + while (!IsReadyToUpdate()) + { + yield(); + } + FillBuffers(); + + // toggle state so the ISR reacts + _dmaState = NeoDmaState_Pending; + } + + uint8_t* getData() const + { + return _data; + }; + + size_t getDataSize() const + { + return _sizeData; + } + +private: + static NeoEsp8266DmaMethodBase* s_this; // for the ISR + + const size_t _sizeData; // Size of '_data' buffer + uint8_t* _data; // Holds LED color values + + size_t _i2sBufferSize; // total size of _i2sBuffer + uint8_t* _i2sBuffer; // holds the DMA buffer that is referenced by _i2sBufDesc + + // normally 24 bytes creates the minimum 50us latch per spec, but + // with the new logic, this latch is used to space between mulitple states + // buffer size = (24 * (reset time / 50)) / 6 + uint8_t _i2sZeroes[(24L * (T_SPEED::ResetTimeUs / 50L)) / 6L]; + + slc_queue_item* _i2sBufDesc; // dma block descriptors + uint16_t _i2sBufDescCount; // count of block descriptors in _i2sBufDesc + uint16_t _is2BufMaxBlockSize; // max size based on size of a pixel of a single block + + volatile NeoDmaState _dmaState; + + // This routine is called as soon as the DMA routine has something to tell us. All we + // handle here is the RX_EOF_INT status, which indicate the DMA has sent a buffer whose + // descriptor has the 'EOF' field set to 1. + // in the case of this code, the second to last state descriptor + static void ICACHE_RAM_ATTR i2s_slc_isr(void) + { + ETS_SLC_INTR_DISABLE(); + + uint32_t slc_intr_status = SLCIS; + + SLCIC = 0xFFFFFFFF; + + if ((slc_intr_status & SLCIRXEOF) && s_this) + { + switch (s_this->_dmaState) + { + case NeoDmaState_Idle: + break; + + case NeoDmaState_Pending: + { + slc_queue_item* finished_item = (slc_queue_item*)SLCRXEDA; + + // data block has pending data waiting to send, prepare it + // point last state block to top + (finished_item + 1)->next_link_ptr = (uint32_t)(s_this->_i2sBufDesc); + + s_this->_dmaState = NeoDmaState_Sending; + } + break; + + case NeoDmaState_Sending: + { + slc_queue_item* finished_item = (slc_queue_item*)SLCRXEDA; + + // the data block had actual data sent + // point last state block to first state block thus + // just looping and not sending the data blocks + (finished_item + 1)->next_link_ptr = (uint32_t)(finished_item); + + s_this->_dmaState = NeoDmaState_Zeroing; + } + break; + + case NeoDmaState_Zeroing: + s_this->_dmaState = NeoDmaState_Idle; + break; + } + } + + ETS_SLC_INTR_ENABLE(); + } + + void FillBuffers() + { + uint16_t* pDma = (uint16_t*)_i2sBuffer; + uint8_t* pEnd = _data + _sizeData; + for (uint8_t* pData = _data; pData < pEnd; pData++) + { + *(pDma++) = T_SPEED::Convert(((*pData) & 0x0f)); + *(pDma++) = T_SPEED::Convert(((*pData) >> 4) & 0x0f); + } + } + + void StopDma() + { + ETS_SLC_INTR_DISABLE(); + + // Disable any I2S send or receive + I2SC &= ~(I2STXS | I2SRXS); + + // Reset I2S + I2SC &= ~(I2SRST); + I2SC |= I2SRST; + I2SC &= ~(I2SRST); + + + SLCIC = 0xFFFFFFFF; + SLCIE = 0; + SLCTXL &= ~(SLCTXLAM << SLCTXLA); // clear TX descriptor address + SLCRXL &= ~(SLCRXLAM << SLCRXLA); // clear RX descriptor address + + pinMode(c_I2sPin, INPUT); + } + + uint32_t getPixelTime() const + { + return (T_SPEED::ByteSendTimeUs * this->_sizeData); + }; + +}; + + +template +NeoEsp8266DmaMethodBase* NeoEsp8266DmaMethodBase::s_this; + +// normal +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaWs2812xMethod; +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaSk6812Method; +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaTm1814Method; +typedef NeoEsp8266DmaMethodBase NeoEsp8266Dma800KbpsMethod; +typedef NeoEsp8266DmaMethodBase NeoEsp8266Dma400KbpsMethod; +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaApa106Method; + +// inverted +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInvertedWs2812xMethod; +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInvertedSk6812Method; +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInvertedTm1814Method; +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInverted800KbpsMethod; +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInverted400KbpsMethod; +typedef NeoEsp8266DmaMethodBase NeoEsp8266DmaInvertedApa106Method; + +// Dma method is the default method for Esp8266 +typedef NeoEsp8266DmaWs2812xMethod NeoWs2813Method; +typedef NeoEsp8266DmaWs2812xMethod NeoWs2812xMethod; +typedef NeoEsp8266Dma800KbpsMethod NeoWs2812Method; +typedef NeoEsp8266DmaWs2812xMethod NeoWs2811Method; +typedef NeoEsp8266DmaSk6812Method NeoSk6812Method; +typedef NeoEsp8266DmaTm1814Method NeoTm1814Method; +typedef NeoEsp8266DmaSk6812Method NeoLc8812Method; +typedef NeoEsp8266DmaApa106Method NeoApa106Method; + +typedef NeoEsp8266DmaWs2812xMethod Neo800KbpsMethod; +typedef NeoEsp8266Dma400KbpsMethod Neo400KbpsMethod; + +// inverted +typedef NeoEsp8266DmaInvertedWs2812xMethod NeoWs2813InvertedMethod; +typedef NeoEsp8266DmaInvertedWs2812xMethod NeoWs2812xInvertedMethod; +typedef NeoEsp8266DmaInverted800KbpsMethod NeoWs2812InvertedMethod; +typedef NeoEsp8266DmaInvertedWs2812xMethod NeoWs2811InvertedMethod; +typedef NeoEsp8266DmaInvertedSk6812Method NeoSk6812InvertedMethod; +typedef NeoEsp8266DmaInvertedTm1814Method NeoTm1814InvertedMethod; +typedef NeoEsp8266DmaInvertedSk6812Method NeoLc8812InvertedMethod; +typedef NeoEsp8266DmaInvertedApa106Method NeoApa106InvertedMethod; + +typedef NeoEsp8266DmaInvertedWs2812xMethod Neo800KbpsInvertedMethod; +typedef NeoEsp8266DmaInverted400KbpsMethod Neo400KbpsInvertedMethod; +#endif diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266UartMethod.cpp b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266UartMethod.cpp new file mode 100644 index 0000000..dab9a57 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266UartMethod.cpp @@ -0,0 +1,171 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp8266 UART hardware + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#ifdef ARDUINO_ARCH_ESP8266 +#include "NeoEsp8266UartMethod.h" +#include +extern "C" +{ + #include +} + +const volatile uint8_t* ICACHE_RAM_ATTR NeoEsp8266UartContext::FillUartFifo(uint8_t uartNum, + const volatile uint8_t* start, + const volatile uint8_t* end) +{ + // Remember: UARTs send less significant bit (LSB) first so + // pushing ABCDEF byte will generate a 0FEDCBA1 signal, + // including a LOW(0) start & a HIGH(1) stop bits. + // Also, we have configured UART to invert logic levels, so: + const uint8_t _uartData[4] = { + 0b110111, // On wire: 1 000 100 0 [Neopixel reads 00] + 0b000111, // On wire: 1 000 111 0 [Neopixel reads 01] + 0b110100, // On wire: 1 110 100 0 [Neopixel reads 10] + 0b000100, // On wire: 1 110 111 0 [NeoPixel reads 11] + }; + uint8_t avail = (UART_TX_FIFO_SIZE - GetTxFifoLength(uartNum)) / 4; + if (end - start > avail) + { + end = start + avail; + } + while (start < end) + { + uint8_t subpix = *start++; + Enqueue(uartNum, _uartData[(subpix >> 6) & 0x3]); + Enqueue(uartNum, _uartData[(subpix >> 4) & 0x3]); + Enqueue(uartNum, _uartData[(subpix >> 2) & 0x3]); + Enqueue(uartNum, _uartData[subpix & 0x3]); + } + return start; +} + +volatile NeoEsp8266UartInterruptContext* NeoEsp8266UartInterruptContext::s_uartInteruptContext[] = { nullptr, nullptr }; + +void NeoEsp8266UartInterruptContext::StartSending(uint8_t uartNum, uint8_t* start, uint8_t* end) +{ + // send the pixels asynchronously + _asyncBuff = start; + _asyncBuffEnd = end; + + // enable the transmit interrupt + USIE(uartNum) |= (1 << UIFE); +} + +void NeoEsp8266UartInterruptContext::Attach(uint8_t uartNum) +{ + // Disable all interrupts + ETS_UART_INTR_DISABLE(); + + // Clear the RX & TX FIFOS + const uint32_t fifoResetFlags = (1 << UCTXRST) | (1 << UCRXRST); + USC0(uartNum) |= fifoResetFlags; + USC0(uartNum) &= ~(fifoResetFlags); + + // attach the ISR if needed + if (s_uartInteruptContext[0] == nullptr && + s_uartInteruptContext[1] == nullptr) + { + ETS_UART_INTR_ATTACH(Isr, s_uartInteruptContext); + } + + // attach the context + s_uartInteruptContext[uartNum] = this; + + // Set tx fifo trigger. 80 bytes gives us 200 microsecs to refill the FIFO + USC1(uartNum) = (80 << UCFET); + + // Disable RX & TX interrupts. It maybe still enabled by uart.c in the SDK + USIE(uartNum) &= ~((1 << UIFF) | (1 << UIFE)); + + // Clear all pending interrupts in UART1 + USIC(uartNum) = 0xffff; + + // Reenable interrupts + ETS_UART_INTR_ENABLE(); +} + +void NeoEsp8266UartInterruptContext::Detach(uint8_t uartNum) +{ + // Disable interrupts + ETS_UART_INTR_DISABLE(); + + if (s_uartInteruptContext[uartNum] != nullptr) + { + // turn off uart + USC1(uartNum) = 0; + USIC(uartNum) = 0xffff; + USIE(uartNum) = 0; + + s_uartInteruptContext[uartNum] = nullptr; + + if (s_uartInteruptContext[0] == nullptr && + s_uartInteruptContext[1] == nullptr) + { + // detach our ISR + ETS_UART_INTR_ATTACH(NULL, NULL); + + // return so we don't enable interrupts since there is no ISR anymore + return; + } + } + + // Reenable interrupts + ETS_UART_INTR_ENABLE(); +} + +void ICACHE_RAM_ATTR NeoEsp8266UartInterruptContext::Isr(void* param) +{ + // make sure this is for us + if (param == s_uartInteruptContext) + { + // Interrupt handler is shared between UART0 & UART1 + // so we need to test for both + for (uint8_t uartNum = 0; uartNum < 2; uartNum++) + { + if (USIS(uartNum) && s_uartInteruptContext[uartNum] != nullptr) + { + // Fill the FIFO with new data + s_uartInteruptContext[uartNum]->_asyncBuff = FillUartFifo( + uartNum, + s_uartInteruptContext[uartNum]->_asyncBuff, + s_uartInteruptContext[uartNum]->_asyncBuffEnd); + + // Disable TX interrupt when done + if (s_uartInteruptContext[uartNum]->_asyncBuff == s_uartInteruptContext[uartNum]->_asyncBuffEnd) + { + // clear the TX FIFO Empty + USIE(uartNum) &= ~(1 << UIFE); + } + + // Clear all interrupts flags (just in case) + USIC(uartNum) = 0xffff; + } + } + } +} + +#endif + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266UartMethod.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266UartMethod.h new file mode 100644 index 0000000..3be17ba --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEsp8266UartMethod.h @@ -0,0 +1,514 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp8266 UART hardware + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#ifdef ARDUINO_ARCH_ESP8266 +#include + +// this template method class is used to track the data being sent on the uart +// when using the default serial ISR installed by the core +// used with NeoEsp8266Uart and NeoEsp8266AsyncUart classes +// +class NeoEsp8266UartContext +{ +public: + // Gets the number of bytes waiting in the TX FIFO + static inline uint8_t ICACHE_RAM_ATTR GetTxFifoLength(uint8_t uartNum) + { + return (USS(uartNum) >> USTXC) & 0xff; + } + // Append a byte to the TX FIFO + static inline void ICACHE_RAM_ATTR Enqueue(uint8_t uartNum, uint8_t value) + { + USF(uartNum) = value; + } + + static const volatile uint8_t* ICACHE_RAM_ATTR FillUartFifo(uint8_t uartNum, + const volatile uint8_t* start, + const volatile uint8_t* end); +}; + +// this template method class is used to track the data being sent on the uart +// when using our own UART ISR +// used with NeoEsp8266Uart and NeoEsp8266AsyncUart classes +// +class NeoEsp8266UartInterruptContext : NeoEsp8266UartContext +{ +public: + NeoEsp8266UartInterruptContext() : + _asyncBuff(nullptr), + _asyncBuffEnd(nullptr) + { + } + + bool IsSending() + { + return (_asyncBuff != _asyncBuffEnd); + } + + void StartSending(uint8_t uartNum, uint8_t* start, uint8_t* end); + void Attach(uint8_t uartNum); + void Detach(uint8_t uartNum); + +private: + volatile const uint8_t* _asyncBuff; + volatile const uint8_t* _asyncBuffEnd; + volatile static NeoEsp8266UartInterruptContext* s_uartInteruptContext[2]; + + static void ICACHE_RAM_ATTR Isr(void* param); +}; + +// this template feature class is used a base for all others and contains +// common methods +// +class UartFeatureBase +{ +protected: + static void ConfigUart(uint8_t uartNum, bool invert) + { + // clear all invert bits + USC0(uartNum) &= ~((1 << UCDTRI) | (1 << UCRTSI) | (1 << UCTXI) | (1 << UCDSRI) | (1 << UCCTSI) | (1 << UCRXI)); + + if (!invert) + { + // For normal operations, + // Invert the TX voltage associated with logic level so: + // - A logic level 0 will generate a Vcc signal + // - A logic level 1 will generate a Gnd signal + USC0(uartNum) |= (1 << UCTXI); + } + } +}; + +// this template feature class is used to define the specifics for uart0 +// used with NeoEsp8266Uart and NeoEsp8266AsyncUart classes +// +class UartFeature0 : UartFeatureBase +{ +public: + static const uint32_t Index = 0; + static void Init(uint32_t baud, bool invert) + { + // Configure the serial line with 1 start bit (0), 6 data bits and 1 stop bit (1) + Serial.begin(baud, SERIAL_6N1, SERIAL_TX_ONLY); + ConfigUart(Index, invert); + } +}; + +// this template feature class is used to define the specifics for uart1 +// used with NeoEsp8266Uart and NeoEsp8266AsyncUart classes +// +class UartFeature1 : UartFeatureBase +{ +public: + static const uint32_t Index = 1; + static void Init(uint32_t baud, bool invert) + { + // Configure the serial line with 1 start bit (0), 6 data bits and 1 stop bit (1) + Serial1.begin(baud, SERIAL_6N1, SERIAL_TX_ONLY); + ConfigUart(Index, invert); + } +}; + +// this template method class is used a base for all others and contains +// common properties and methods +// +// used by NeoEsp8266Uart and NeoEsp8266AsyncUart +// +class NeoEsp8266UartBase +{ +protected: + const size_t _sizeData; // Size of '_data' buffer below + uint8_t* _data; // Holds LED color values + uint32_t _startTime; // Microsecond count when last update started + + NeoEsp8266UartBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize) + { + _data = static_cast(malloc(_sizeData)); + memset(_data, 0x00, _sizeData); + } + + ~NeoEsp8266UartBase() + { + free(_data); + } + +}; + +// this template method class is used to glue uart feature and context for +// synchronous uart method +// +// used by NeoEsp8266UartMethodBase +// +template class NeoEsp8266Uart : public NeoEsp8266UartBase +{ +protected: + NeoEsp8266Uart(uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + NeoEsp8266UartBase(pixelCount, elementSize, settingsSize) + { + } + + ~NeoEsp8266Uart() + { + // Wait until the TX fifo is empty. This way we avoid broken frames + // when destroying & creating a NeoPixelBus to change its length. + while (T_UARTCONTEXT::GetTxFifoLength(T_UARTFEATURE::Index) > 0) + { + yield(); + } + } + + void InitializeUart(uint32_t uartBaud, bool invert) + { + T_UARTFEATURE::Init(uartBaud, invert); + } + + void UpdateUart(bool) + { + // Since the UART can finish sending queued bytes in the FIFO in + // the background, instead of waiting for the FIFO to flush + // we annotate the start time of the frame so we can calculate + // when it will finish. + _startTime = micros(); + + // Then keep filling the FIFO until done + const uint8_t* ptr = _data; + const uint8_t* end = ptr + _sizeData; + while (ptr != end) + { + ptr = const_cast(T_UARTCONTEXT::FillUartFifo(T_UARTFEATURE::Index, ptr, end)); + } + } +}; + +// this template method class is used to glue uart feature and context for +// asynchronously uart method +// +// This UART controller uses two buffers that are swapped in every call to +// NeoPixelBus.Show(). One buffer contains the data that is being sent +// asynchronosly and another buffer contains the data that will be send +// in the next call to NeoPixelBus.Show(). +// +// Therefore, the result of NeoPixelBus.Pixels() is invalidated after +// every call to NeoPixelBus.Show() and must not be cached. +// +// used by NeoEsp8266UartMethodBase +// +template class NeoEsp8266AsyncUart : public NeoEsp8266UartBase +{ +protected: + NeoEsp8266AsyncUart(uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + NeoEsp8266UartBase(pixelCount, elementSize, settingsSize) + { + _dataSending = static_cast(malloc(_sizeData)); + } + + ~NeoEsp8266AsyncUart() + { + // Remember: the UART interrupt can be sending data from _dataSending in the background + while (_context.IsSending()) + { + yield(); + } + // detach context, which will disable intr, may disable ISR + _context.Detach(T_UARTFEATURE::Index); + + free(_dataSending); + } + + void ICACHE_RAM_ATTR InitializeUart(uint32_t uartBaud, bool invert) + { + T_UARTFEATURE::Init(uartBaud, invert); + + // attach the context, which will enable the ISR + _context.Attach(T_UARTFEATURE::Index); + } + + void UpdateUart(bool maintainBufferConsistency) + { + // Instruct ESP8266 hardware uart to send the pixels asynchronously + _context.StartSending(T_UARTFEATURE::Index, + _data, + _data + _sizeData); + + // Annotate when we started to send bytes, so we can calculate when we are ready to send again + _startTime = micros(); + + if (maintainBufferConsistency) + { + // copy editing to sending, + // this maintains the contract that "colors present before will + // be the same after", otherwise GetPixelColor will be inconsistent + memcpy(_dataSending, _data, _sizeData); + } + + // swap so the user can modify without affecting the async operation + std::swap(_dataSending, _data); + } + +private: + T_UARTCONTEXT _context; + + uint8_t* _dataSending; // Holds a copy of LED color values taken when UpdateUart began +}; + +class NeoEsp8266UartSpeed800KbpsBase +{ +public: + static const uint32_t ByteSendTimeUs = 10; // us it takes to send a single pixel element at 800khz speed + static const uint32_t UartBaud = 3200000; // 800mhz, 4 serial bytes per NeoByte +}; + +// NeoEsp8266UartSpeedWs2813 contains the timing constants used to get NeoPixelBus running with the Ws2813 +class NeoEsp8266UartSpeedWs2812x : public NeoEsp8266UartSpeed800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 300; // us between data send bursts to reset for next update +}; + +class NeoEsp8266UartSpeedSk6812 : public NeoEsp8266UartSpeed800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 80; // us between data send bursts to reset for next update +}; + +class NeoEsp8266UartSpeedTm1814 : public NeoEsp8266UartSpeed800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 200; // us between data send bursts to reset for next update +}; + +// NeoEsp8266UartSpeed800Kbps contains the timing constant used to get NeoPixelBus running at 800Khz +class NeoEsp8266UartSpeed800Kbps : public NeoEsp8266UartSpeed800KbpsBase +{ +public: + static const uint32_t ResetTimeUs = 50; // us between data send bursts to reset for next update +}; + +// NeoEsp8266UartSpeed400Kbps contains the timing constant used to get NeoPixelBus running at 400Khz +class NeoEsp8266UartSpeed400Kbps +{ +public: + static const uint32_t ByteSendTimeUs = 20; // us it takes to send a single pixel element at 400khz speed + static const uint32_t UartBaud = 1600000; // 400mhz, 4 serial bytes per NeoByte + static const uint32_t ResetTimeUs = 50; // us between data send bursts to reset for next update +}; + +// NeoEsp8266UartSpeedApa106 contains the timing constant used to get NeoPixelBus running for Apa106 +// Pulse cycle = 1.71 = 1.368 longer than normal, 0.731 slower, NeoEsp8266UartSpeedApa1066 +class NeoEsp8266UartSpeedApa106 +{ +public: + static const uint32_t ByteSendTimeUs = 14; // us it takes to send a single pixel element at 400khz speed + static const uint32_t UartBaud = 2339181; // APA106 pulse cycle of 1.71us, 4 serial bytes per NeoByte + static const uint32_t ResetTimeUs = 50; // us between data send bursts to reset for next update +}; + +class NeoEsp8266UartNotInverted +{ +public: + const static bool Inverted = false; +}; + +class NeoEsp8266UartInverted +{ +public: + const static bool Inverted = true; +}; + +// NeoEsp8266UartMethodBase is a light shell arround NeoEsp8266Uart or NeoEsp8266AsyncUart that +// implements the methods needed to operate as a NeoPixelBus method. +template +class NeoEsp8266UartMethodBase: public T_BASE +{ +public: + NeoEsp8266UartMethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) + : T_BASE(pixelCount, elementSize, settingsSize) + { + } + NeoEsp8266UartMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) + : T_BASE(pixelCount, elementSize, settingsSize) + { + } + + bool IsReadyToUpdate() const + { + uint32_t delta = micros() - this->_startTime; + return delta >= getPixelTime() + T_SPEED::ResetTimeUs; + } + + void Initialize() + { + this->InitializeUart(T_SPEED::UartBaud, T_INVERT::Inverted); + + // Inverting logic levels can generate a phantom bit in the led strip bus + // We need to delay 50+ microseconds the output stream to force a data + // latch and discard this bit. Otherwise, that bit would be prepended to + // the first frame corrupting it. + this->_startTime = micros() - getPixelTime(); + } + + void Update(bool maintainBufferConsistency) + { + // Data latch = 50+ microsecond pause in the output stream. Rather than + // put a delay at the end of the function, the ending time is noted and + // the function will simply hold off (if needed) on issuing the + // subsequent round of data until the latch time has elapsed. This + // allows the mainline code to start generating the next frame of data + // rather than stalling for the latch. + while (!this->IsReadyToUpdate()) + { + yield(); + } + this->UpdateUart(maintainBufferConsistency); + } + + uint8_t* getData() const + { + return this->_data; + }; + + size_t getDataSize() const + { + return this->_sizeData; + }; + +private: + uint32_t getPixelTime() const + { + return (T_SPEED::ByteSendTimeUs * this->_sizeData); + }; +}; + +// uart 0 +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Ws2812xMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Sk6812Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart0Tm1814Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Apa106Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart0800KbpsMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart0400KbpsMethod; + +typedef NeoEsp8266Uart0Ws2812xMethod NeoEsp8266Uart0Ws2813Method; +typedef NeoEsp8266Uart0800KbpsMethod NeoEsp8266Uart0Ws2812Method; +typedef NeoEsp8266Uart0Ws2812xMethod NeoEsp8266Uart0Ws2811Method; +typedef NeoEsp8266Uart0Sk6812Method NeoEsp8266Uart0Lc8812Method; + +// uart 1 +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Ws2812xMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Sk6812Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart1Tm1814Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Apa106Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart1800KbpsMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart1400KbpsMethod; + +typedef NeoEsp8266Uart1Ws2812xMethod NeoEsp8266Uart1Ws2813Method; +typedef NeoEsp8266Uart1800KbpsMethod NeoEsp8266Uart1Ws2812Method; +typedef NeoEsp8266Uart1Ws2812xMethod NeoEsp8266Uart1Ws2811Method; +typedef NeoEsp8266Uart1Sk6812Method NeoEsp8266Uart1Lc8812Method; + +// uart 0 async +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Ws2812xMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Sk6812Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Tm1814Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Apa106Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0800KbpsMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0400KbpsMethod; + +typedef NeoEsp8266AsyncUart0Ws2812xMethod NeoEsp8266AsyncUart0Ws2813Method; +typedef NeoEsp8266AsyncUart0800KbpsMethod NeoEsp8266AsyncUart0Ws2812Method; +typedef NeoEsp8266AsyncUart0Ws2812xMethod NeoEsp8266AsyncUart0Ws2811Method; +typedef NeoEsp8266AsyncUart0Sk6812Method NeoEsp8266AsyncUart0Lc8812Method; + +// uart 1 async +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Ws2812xMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Sk6812Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Tm1814Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Apa106Method; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1800KbpsMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1400KbpsMethod; + +typedef NeoEsp8266AsyncUart1Ws2812xMethod NeoEsp8266AsyncUart1Ws2813Method; +typedef NeoEsp8266AsyncUart1800KbpsMethod NeoEsp8266AsyncUart1Ws2812Method; +typedef NeoEsp8266AsyncUart1Ws2812xMethod NeoEsp8266AsyncUart1Ws2811Method; +typedef NeoEsp8266AsyncUart1Sk6812Method NeoEsp8266AsyncUart1Lc8812Method; + +// inverted +// +// uart 0 +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart0Ws2812xInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart0Sk6812InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart0Tm1814InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart0Apa106InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart0800KbpsInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart0400KbpsInvertedMethod; + +typedef NeoEsp8266Uart0Ws2812xInvertedMethod NeoEsp8266Uart0Ws2813InvertedMethod; +typedef NeoEsp8266Uart0800KbpsInvertedMethod NeoEsp8266Uart0Ws2812InvertedMethod; +typedef NeoEsp8266Uart0Ws2812xInvertedMethod NeoEsp8266Uart0Ws2811InvertedMethod; +typedef NeoEsp8266Uart0Sk6812InvertedMethod NeoEsp8266Uart0Lc8812InvertedMethod; + +// uart 1 +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart1Ws2812xInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart1Sk6812InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266Uart1Tm1814InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart1Apa106InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart1800KbpsInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266Uart1400KbpsInvertedMethod; + +typedef NeoEsp8266Uart1Ws2812xInvertedMethod NeoEsp8266Uart1Ws2813InvertedMethod; +typedef NeoEsp8266Uart1800KbpsInvertedMethod NeoEsp8266Uart1Ws2812InvertedMethod; +typedef NeoEsp8266Uart1Ws2812xInvertedMethod NeoEsp8266Uart1Ws2811InvertedMethod; +typedef NeoEsp8266Uart1Sk6812InvertedMethod NeoEsp8266Uart1Lc8812InvertedMethod; + +// uart 0 async +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Ws2812xInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Sk6812InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart0Tm1814InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0Apa106InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0800KbpsInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart0400KbpsInvertedMethod; + +typedef NeoEsp8266AsyncUart0Ws2812xInvertedMethod NeoEsp8266AsyncUart0Ws2813InvertedMethod; +typedef NeoEsp8266AsyncUart0800KbpsInvertedMethod NeoEsp8266AsyncUart0Ws2812InvertedMethod; +typedef NeoEsp8266AsyncUart0Ws2812xInvertedMethod NeoEsp8266AsyncUart0Ws2811InvertedMethod; +typedef NeoEsp8266AsyncUart0Sk6812InvertedMethod NeoEsp8266AsyncUart0Lc8812InvertedMethod; + +// uart 1 async +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Ws2812xInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Sk6812InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartNotInverted> NeoEsp8266AsyncUart1Tm1814InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1Apa106InvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1800KbpsInvertedMethod; +typedef NeoEsp8266UartMethodBase, NeoEsp8266UartInverted> NeoEsp8266AsyncUart1400KbpsInvertedMethod; + +typedef NeoEsp8266AsyncUart1Ws2812xInvertedMethod NeoEsp8266AsyncUart1Ws2813InvertedMethod; +typedef NeoEsp8266AsyncUart1800KbpsInvertedMethod NeoEsp8266AsyncUart1Ws2812InvertedMethod; +typedef NeoEsp8266AsyncUart1Ws2812xInvertedMethod NeoEsp8266AsyncUart1Ws2811InvertedMethod; +typedef NeoEsp8266AsyncUart1Sk6812InvertedMethod NeoEsp8266AsyncUart1Lc8812InvertedMethod; +#endif + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoEspBitBangMethod.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEspBitBangMethod.h new file mode 100644 index 0000000..506adb7 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoEspBitBangMethod.h @@ -0,0 +1,401 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp8266 and Esp32 + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) + +#if defined(ARDUINO_ARCH_ESP8266) +#include +#endif + +// ESP32 doesn't define ICACHE_RAM_ATTR +#ifndef ICACHE_RAM_ATTR +#define ICACHE_RAM_ATTR IRAM_ATTR +#endif + +#define CYCLES_LOOPTEST (4) // adjustment due to loop exit test instruction cycles + +class NeoEspSpeedWs2811 +{ +public: + const static uint32_t T0H = (F_CPU / 3333333 - CYCLES_LOOPTEST); // 0.3us + const static uint32_t T1H = (F_CPU / 1052632 - CYCLES_LOOPTEST); // 0.95us + const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit +}; + +class NeoEspSpeedTm1814 +{ +public: + const static uint32_t T0H = (F_CPU / 2916666 - CYCLES_LOOPTEST); // 0.35us + const static uint32_t T1H = (F_CPU / 1666666 - CYCLES_LOOPTEST); // 0.75us + const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit +}; + +class NeoEspSpeed800Mhz +{ +public: + const static uint32_t T0H = (F_CPU / 2500000 - CYCLES_LOOPTEST); // 0.4us + const static uint32_t T1H = (F_CPU / 1250000 - CYCLES_LOOPTEST); // 0.8us + const static uint32_t Period = (F_CPU / 800000 - CYCLES_LOOPTEST); // 1.25us per bit +}; + +class NeoEspSpeed400Mhz +{ +public: + const static uint32_t T0H = (F_CPU / 2000000 - CYCLES_LOOPTEST); + const static uint32_t T1H = (F_CPU / 833333 - CYCLES_LOOPTEST); + const static uint32_t Period = (F_CPU / 400000 - CYCLES_LOOPTEST); +}; + +class NeoEspPinset +{ +public: + const static uint8_t IdleLevel = LOW; + + inline static void setPin(const uint32_t pinRegister) + { +#if defined(ARDUINO_ARCH_ESP32) + GPIO.out_w1ts = pinRegister; +#else + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister); +#endif + } + + inline static void resetPin(const uint32_t pinRegister) + { +#if defined(ARDUINO_ARCH_ESP32) + GPIO.out_w1tc = pinRegister; +#else + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister); +#endif + } +}; + +class NeoEspPinsetInverted +{ +public: + const static uint8_t IdleLevel = HIGH; + + inline static void setPin(const uint32_t pinRegister) + { +#if defined(ARDUINO_ARCH_ESP32) + GPIO.out_w1tc = pinRegister; +#else + GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, pinRegister); +#endif + } + + inline static void resetPin(const uint32_t pinRegister) + { +#if defined(ARDUINO_ARCH_ESP32) + GPIO.out_w1ts = pinRegister; +#else + GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, pinRegister); +#endif + } +}; + +template class NeoEspBitBangBase +{ +public: + __attribute__((noinline)) static void ICACHE_RAM_ATTR send_pixels(uint8_t* pixels, uint8_t* end, uint8_t pin) + { + const uint32_t pinRegister = _BV(pin); + uint8_t mask = 0x80; + uint8_t subpix = *pixels++; + uint32_t cyclesStart = 0; // trigger emediately + uint32_t cyclesNext = 0; + + for (;;) + { + // do the checks here while we are waiting on time to pass + uint32_t cyclesBit = T_SPEED::T0H; + if (subpix & mask) + { + cyclesBit = T_SPEED::T1H; + } + + // after we have done as much work as needed for this next bit + // now wait for the HIGH + while (((cyclesStart = getCycleCount()) - cyclesNext) < T_SPEED::Period); + + // set pin state + T_PINSET::setPin(pinRegister); + + // wait for the LOW + while ((getCycleCount() - cyclesStart) < cyclesBit); + + // reset pin start + T_PINSET::resetPin(pinRegister); + + cyclesNext = cyclesStart; + + // next bit + mask >>= 1; + if (mask == 0) + { + // no more bits to send in this byte + // check for another byte + if (pixels >= end) + { + // no more bytes to send so stop + break; + } + // reset mask to first bit and get the next byte + mask = 0x80; + subpix = *pixels++; + } + } + } + +protected: + static inline uint32_t getCycleCount(void) + { + uint32_t ccount; + __asm__ __volatile__("rsr %0,ccount":"=a" (ccount)); + return ccount; + } +}; + +class NeoEspBitBangSpeedWs2811 : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 300; +}; + +class NeoEspBitBangSpeedWs2812x : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 300; +}; + +class NeoEspBitBangSpeedSk6812 : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 80; +}; + +// normal is inverted signal +class NeoEspBitBangSpeedTm1814 : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 200; +}; + +class NeoEspBitBangSpeed800Kbps : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 50; +}; + +class NeoEspBitBangSpeed400Kbps : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 50; +}; + + +class NeoEspBitBangInvertedSpeedWs2811 : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 300; +}; + +class NeoEspBitBangInvertedSpeedWs2812x : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 300; +}; + +class NeoEspBitBangInvertedSpeedSk6812 : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 80; +}; + +// normal is inverted signal, so inverted is normal +class NeoEspBitBangInvertedSpeedTm1814 : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 200; +}; + +class NeoEspBitBangInvertedSpeed800Kbps : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 50; +}; + +class NeoEspBitBangInvertedSpeed400Kbps : public NeoEspBitBangBase +{ +public: + static const uint32_t ResetTimeUs = 50; +}; + +template class NeoEspBitBangMethodBase +{ +public: + NeoEspBitBangMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + _pin(pin) + { + pinMode(pin, OUTPUT); + + _data = static_cast(malloc(_sizeData)); + memset(_data, 0, _sizeData); + } + + ~NeoEspBitBangMethodBase() + { + pinMode(_pin, INPUT); + + free(_data); + } + + bool IsReadyToUpdate() const + { + uint32_t delta = micros() - _endTime; + + return (delta >= T_SPEED::ResetTimeUs); + } + + void Initialize() + { + digitalWrite(_pin, T_PINSET::IdleLevel); + + _endTime = micros(); + } + + void Update(bool) + { + // Data latch = 50+ microsecond pause in the output stream. Rather than + // put a delay at the end of the function, the ending time is noted and + // the function will simply hold off (if needed) on issuing the + // subsequent round of data until the latch time has elapsed. This + // allows the mainline code to start generating the next frame of data + // rather than stalling for the latch. + while (!IsReadyToUpdate()) + { + yield(); // allows for system yield if needed + } + + // Need 100% focus on instruction timing +#if defined(ARDUINO_ARCH_ESP32) + delay(1); // required + portMUX_TYPE updateMux = portMUX_INITIALIZER_UNLOCKED; + + portENTER_CRITICAL(&updateMux); +#else + noInterrupts(); +#endif + + T_SPEED::send_pixels(_data, _data + _sizeData, _pin); + +#if defined(ARDUINO_ARCH_ESP32) + portEXIT_CRITICAL(&updateMux); +#else + interrupts(); +#endif + + // save EOD time for latch on next call + _endTime = micros(); + } + + uint8_t* getData() const + { + return _data; + }; + + size_t getDataSize() const + { + return _sizeData; + }; + +private: + const size_t _sizeData; // Size of '_data' buffer below + const uint8_t _pin; // output pin number + + uint32_t _endTime; // Latch timing reference + uint8_t* _data; // Holds LED color values +}; + + +#if defined(ARDUINO_ARCH_ESP32) + +typedef NeoEspBitBangMethodBase NeoEsp32BitBangWs2811Method; +typedef NeoEspBitBangMethodBase NeoEsp32BitBangWs2812xMethod; +typedef NeoEspBitBangMethodBase NeoEsp32BitBangSk6812Method; +typedef NeoEspBitBangMethodBase NeoEsp32BitBangTm1814Method; +typedef NeoEspBitBangMethodBase NeoEsp32BitBang800KbpsMethod; +typedef NeoEspBitBangMethodBase NeoEsp32BitBang400KbpsMethod; + +typedef NeoEsp32BitBangWs2812xMethod NeoEsp32BitBangWs2813Method; +typedef NeoEsp32BitBang800KbpsMethod NeoEsp32BitBangWs2812Method; +typedef NeoEsp32BitBangSk6812Method NeoEsp32BitBangLc8812Method; +typedef NeoEsp32BitBang400KbpsMethod NeoEsp32BitBangApa106Method; + +typedef NeoEspBitBangMethodBase NeoEsp32BitBangWs2811InvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp32BitBangWs2812xInvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp32BitBangSk6812InvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp32BitBangTm1814InvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp32BitBang800KbpsInvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp32BitBang400KbpsInvertedMethod; + +typedef NeoEsp32BitBangWs2812xInvertedMethod NeoEsp32BitBangWs2813InvertedMethod; +typedef NeoEsp32BitBang800KbpsInvertedMethod NeoEsp32BitBangWs2812InvertedMethod; +typedef NeoEsp32BitBangSk6812InvertedMethod NeoEsp32BitBangLc8812InvertedMethod; +typedef NeoEsp32BitBang400KbpsInvertedMethod NeoEsp32BitBangApa106InvertedMethod; + +#else + +typedef NeoEspBitBangMethodBase NeoEsp8266BitBangWs2811Method; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBangWs2812xMethod; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBangSk6812Method; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBangTm1814Method; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBang800KbpsMethod; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBang400KbpsMethod; + +typedef NeoEsp8266BitBangWs2812xMethod NeoEsp8266BitBangWs2813Method; +typedef NeoEsp8266BitBang800KbpsMethod NeoEsp8266BitBangWs2812Method; +typedef NeoEsp8266BitBangSk6812Method NeoEsp8266BitBangLc8812Method; +typedef NeoEsp8266BitBang400KbpsMethod NeoEsp8266BitBangApa106Method; + +typedef NeoEspBitBangMethodBase NeoEsp8266BitBangWs2811InvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBangWs2812xInvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBangSk6812InvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBangTm1814InvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBang800KbpsInvertedMethod; +typedef NeoEspBitBangMethodBase NeoEsp8266BitBang400KbpsInvertedMethod; + +typedef NeoEsp8266BitBangWs2812xInvertedMethod NeoEsp8266BitBangWs2813InvertedMethod; +typedef NeoEsp8266BitBang800KbpsInvertedMethod NeoEsp8266BitBangWs2812InvertedMethod; +typedef NeoEsp8266BitBangSk6812InvertedMethod NeoEsp8266BitBangLc8812InvertedMethod; +typedef NeoEsp8266BitBang400KbpsInvertedMethod NeoEsp8266BitBangApa106InvertedMethod; +#endif + +// ESP bitbang doesn't have defaults and should avoided except for testing +#endif \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoGamma.cpp b/lib/NeoPixelBus_by_Makuna/src/internal/NeoGamma.cpp new file mode 100644 index 0000000..fdff9e7 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoGamma.cpp @@ -0,0 +1,47 @@ +/*------------------------------------------------------------------------- +NeoPixelGamma class is used to correct RGB colors for human eye gamma levels + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#include +#include "NeoPixelBus.h" + +const uint8_t NeoGammaTableMethod::_table[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, + 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, + 12, 12, 13, 13, 14, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, + 19, 20, 20, 21, 22, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, + 29, 30, 30, 31, 32, 33, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40, + 41, 42, 43, 43, 44, 45, 46, 47, 48, 49, 50, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, + 72, 73, 74, 75, 76, 77, 78, 80, 81, 82, 83, 84, 86, 87, 88, 89, + 91, 92, 93, 94, 96, 97, 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, + 112, 113, 115, 116, 118, 119, 121, 122, 123, 125, 126, 128, 130, 131, 133, 134, + 136, 137, 139, 140, 142, 144, 145, 147, 149, 150, 152, 154, 155, 157, 159, 160, + 162, 164, 166, 167, 169, 171, 173, 175, 176, 178, 180, 182, 184, 186, 187, 189, + 191, 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, + 223, 225, 227, 229, 231, 233, 235, 238, 240, 242, 244, 246, 248, 251, 253, 255 +}; \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoGamma.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoGamma.h new file mode 100644 index 0000000..4aaf68e --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoGamma.h @@ -0,0 +1,74 @@ +/*------------------------------------------------------------------------- +NeoGamma class is used to correct RGB colors for human eye gamma levels equally +across all color channels + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +// NeoGammaEquationMethod uses no memory but is slower than NeoGammaTableMethod +class NeoGammaEquationMethod +{ +public: + static uint8_t Correct(uint8_t value) + { + return static_cast(255.0f * NeoEase::Gamma(value / 255.0f) + 0.5f); + } +}; + +// NeoGammaTableMethod uses 256 bytes of memory, but is significantly faster +class NeoGammaTableMethod +{ +public: + static uint8_t Correct(uint8_t value) + { + return _table[value]; + } + +private: + static const uint8_t _table[256]; +}; + + +// use one of the method classes above as a converter for this template class +template class NeoGamma +{ +public: + RgbColor Correct(const RgbColor& original) + { + return RgbColor(T_METHOD::Correct(original.R), + T_METHOD::Correct(original.G), + T_METHOD::Correct(original.B)); + } + + RgbwColor Correct(const RgbwColor& original) + { + return RgbwColor(T_METHOD::Correct(original.R), + T_METHOD::Correct(original.G), + T_METHOD::Correct(original.B), + T_METHOD::Correct(original.W) ); + } +}; + + + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoHueBlend.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoHueBlend.h new file mode 100644 index 0000000..d77a58f --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoHueBlend.h @@ -0,0 +1,118 @@ +/*------------------------------------------------------------------------- +NeoHueBlend provides method objects that can be directly consumed by +blend template functions in HslColor and HsbColor + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +class NeoHueBlendBase +{ +protected: + static float FixWrap(float value) + { + if (value < 0.0f) + { + value += 1.0f; + } + else if (value > 1.0f) + { + value -= 1.0f; + } + return value; + } +}; + +class NeoHueBlendShortestDistance : NeoHueBlendBase +{ +public: + static float HueBlend(float left, float right, float progress) + { + float delta = right - left; + float base = left; + if (delta > 0.5f) + { + base = right; + delta = 1.0f - delta; + progress = 1.0f - progress; + } + else if (delta < -0.5f) + { + delta = 1.0f + delta; + } + return FixWrap(base + (delta) * progress); + }; +}; + +class NeoHueBlendLongestDistance : NeoHueBlendBase +{ +public: + static float HueBlend(float left, float right, float progress) + { + float delta = right - left; + float base = left; + if (delta < 0.5f && delta >= 0.0f) + { + base = right; + delta = 1.0f - delta; + progress = 1.0f - progress; + } + else if (delta > -0.5f && delta < 0.0f) + { + delta = 1.0f + delta; + } + return FixWrap(base + delta * progress); + }; +}; + +class NeoHueBlendClockwiseDirection : NeoHueBlendBase +{ +public: + static float HueBlend(float left, float right, float progress) + { + float delta = right - left; + float base = left; + if (delta < 0.0f) + { + delta = 1.0f + delta; + } + + return FixWrap(base + delta * progress); + }; +}; + +class NeoHueBlendCounterClockwiseDirection : NeoHueBlendBase +{ +public: + static float HueBlend(float left, float right, float progress) + { + float delta = right - left; + float base = left; + if (delta > 0.0f) + { + delta = delta - 1.0f; + } + + return FixWrap(base + delta * progress); + }; +}; diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoMosaic.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoMosaic.h new file mode 100644 index 0000000..551bd53 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoMosaic.h @@ -0,0 +1,191 @@ +#pragma once + +/*------------------------------------------------------------------------- +Mosiac provides a mapping feature of a 2d cordinate to linear 1d cordinate +It is used to map tiles of matricies of NeoPixels to a index on the NeoPixelBus +where the the matricies use a set of prefered topology and the tiles of +those matricies use the RowMajorAlternating layout + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + + +//----------------------------------------------------------------------------- +// class NeoMosaic +// Complex Tile layout class that reduces distance of the interconnects between +// the tiles by using different rotations of the layout at specific locations +// +// T_LAYOUT = the layout used for matrix panel (rotation is ignored) +// +// NOTE: The tiles in the mosaic are always laid out using RowMajorAlternating +// +//----------------------------------------------------------------------------- + +template class NeoMosaic +{ +public: + NeoMosaic(uint16_t topoWidth, uint16_t topoHeight, + uint16_t mosaicWidth, uint16_t mosaicHeight) : + _topoWidth(topoWidth), + _topoHeight(topoHeight), + _mosaicWidth(mosaicWidth), + _mosaicHeight(mosaicHeight) + { + } + + uint16_t Map(int16_t x, int16_t y) const + { + uint16_t totalWidth = getWidth(); + uint16_t totalHeight = getHeight(); + + if (x >= totalWidth) + { + x = totalWidth - 1; + } + else if (x < 0) + { + x = 0; + } + + if (y >= totalHeight) + { + y = totalHeight - 1; + } + else if (y < 0) + { + y = 0; + } + + uint16_t localIndex; + uint16_t tileOffset; + + calculate(x, y, &localIndex, &tileOffset); + + return localIndex + tileOffset; + } + + uint16_t MapProbe(int16_t x, int16_t y) const + { + uint16_t totalWidth = getWidth(); + uint16_t totalHeight = getHeight(); + + if (x < 0 || x >= totalWidth || y < 0 || y >= totalHeight) + { + return totalWidth * totalHeight; // count, out of bounds + } + + uint16_t localIndex; + uint16_t tileOffset; + + calculate(x, y, &localIndex, &tileOffset); + + return localIndex + tileOffset; + } + + NeoTopologyHint TopologyHint(int16_t x, int16_t y) const + { + uint16_t totalWidth = getWidth(); + uint16_t totalHeight = getHeight(); + + if (x < 0 || x >= totalWidth || y < 0 || y >= totalHeight) + { + return NeoTopologyHint_OutOfBounds; + } + + uint16_t localIndex; + uint16_t tileOffset; + NeoTopologyHint result; + + calculate(x, y, &localIndex, &tileOffset); + + if (localIndex == 0) + { + result = NeoTopologyHint_FirstOnPanel; + } + else if (localIndex == (_topoWidth * _topoHeight - 1)) + { + result = NeoTopologyHint_LastOnPanel; + } + else + { + result = NeoTopologyHint_InPanel; + } + + return result; + } + + uint16_t getWidth() const + { + return _topoWidth * _mosaicWidth; + } + + uint16_t getHeight() const + { + return _topoHeight * _mosaicHeight; + } + +private: + const uint16_t _topoWidth; + const uint16_t _topoHeight; + const uint16_t _mosaicWidth; + const uint16_t _mosaicHeight; + + void calculate(uint16_t x, uint16_t y, uint16_t* pLocalIndex, uint16_t* pTileOffset) const + { + uint16_t tileX = x / _topoWidth; + uint16_t topoX = x % _topoWidth; + + uint16_t tileY = y / _topoHeight; + uint16_t topoY = y % _topoHeight; + + *pTileOffset = RowMajorAlternatingLayout::Map(_mosaicWidth, + _mosaicHeight, + tileX, + tileY) * _topoWidth * _topoHeight; + + if (tileX & 0x0001) + { + // odd columns + if (tileY & 0x0001) + { + *pLocalIndex = T_LAYOUT::OddRowOddColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY); + } + else + { + *pLocalIndex = T_LAYOUT::EvenRowOddColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY); + } + } + else + { + // even columns + if (tileY & 0x0001) + { + *pLocalIndex = T_LAYOUT::OddRowEvenColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY); + } + else + { + *pLocalIndex = T_LAYOUT::EvenRowEvenColumnLayout::Map(_topoWidth, _topoHeight, topoX, topoY); + } + } + } +}; \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoNrf52xMethod.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoNrf52xMethod.h new file mode 100644 index 0000000..b8810ea --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoNrf52xMethod.h @@ -0,0 +1,490 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper classes for Nrf52* MCUs. +Nano 33 BLE + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. +The contents of this file were taken from the Adafruit NeoPixel library +and modified only to fit within individual calling functions. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#if defined(ARDUINO_ARCH_NRF52840) + +const uint16_t c_dmaBytesPerDataByte = 8 * sizeof(nrf_pwm_values_common_t); // bits * bytes to represent pulse + +// for Bit* variables +// count 1 = 0.0625us, so max count (32768) is 2048us + +class NeoNrf52xPwmSpeedWs2811 +{ +public: + const static uint32_t CountTop = 20UL; // 1.25us + const static nrf_pwm_values_common_t Bit0 = 5 | 0x8000; // ~0.3us + const static nrf_pwm_values_common_t Bit1 = 14 | 0x8000; // ~0.9us + const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW + const static uint16_t CountReset = 240; // 300 us / 1.25us + const static PinStatus IdleLevel = LOW; +}; + +class NeoNrf52xPwmSpeedWs2812x +{ +public: + const static uint32_t CountTop = 20UL; // 1.25us + const static nrf_pwm_values_common_t Bit0 = 6 | 0x8000; // ~0.4us + const static nrf_pwm_values_common_t Bit1 = 13 | 0x8000; // ~0.8us + const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW + const static uint32_t CountReset = 240 ; // 300us / 1.25us pulse width + const static PinStatus IdleLevel = LOW; +}; + +class NeoNrf52xPwmSpeedSk6812 +{ +public: + const static uint32_t CountTop = 20UL; // 1.25us + const static nrf_pwm_values_common_t Bit0 = 6 | 0x8000; // ~0.4us + const static nrf_pwm_values_common_t Bit1 = 13 | 0x8000; // ~0.8us + const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW + const static uint32_t CountReset = 64; // 80us / 1.25us pulse width + const static PinStatus IdleLevel = LOW; +}; + +class NeoNrf52xPwmSpeedTm1814 +{ +public: + const static uint32_t CountTop = 20UL; // 1.25us + const static nrf_pwm_values_common_t Bit0 = 5; // ~0.3us + const static nrf_pwm_values_common_t Bit1 = 12; // ~0.7us + const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH + const static uint32_t CountReset = 160; // 200us / 1.25us pulse width + const static PinStatus IdleLevel = HIGH; +}; + +class NeoNrf52xPwmSpeed800Kbps +{ +public: + const static uint32_t CountTop = 20UL; // 1.25us + const static nrf_pwm_values_common_t Bit0 = 6 | 0x8000; // ~0.4us + const static nrf_pwm_values_common_t Bit1 = 13 | 0x8000; // ~0.8us + const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW + const static uint32_t CountReset = 40; // 50us / 1.25us pulse width + const static PinStatus IdleLevel = LOW; +}; + +class NeoNrf52xPwmSpeed400Kbps +{ +public: + const static uint32_t CountTop = 40UL; // 2.5us + const static nrf_pwm_values_common_t Bit0 = 13 | 0x8000; // ~0.8us + const static nrf_pwm_values_common_t Bit1 = 26 | 0x8000; // ~1.6us + const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW + const static uint16_t CountReset = 20; // 50 us / 2.5us + const static PinStatus IdleLevel = LOW; +}; + +class NeoNrf52xPwmSpeedApa106 +{ +public: + const static uint32_t CountTop = 26UL; // 1.65us + const static nrf_pwm_values_common_t Bit0 = 6 | 0x8000; // ~0.4us + const static nrf_pwm_values_common_t Bit1 = 20 | 0x8000; // ~1.25us + const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW + const static uint32_t CountReset = 40; // 50us / 1.25us pulse width + const static PinStatus IdleLevel = LOW; +}; + +class NeoNrf52xPwmInvertedSpeedWs2811 +{ +public: + const static uint32_t CountTop = 20UL; // 1.25us + const static nrf_pwm_values_common_t Bit0 = 5; // ~0.3us + const static nrf_pwm_values_common_t Bit1 = 14; // ~0.9us + const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH + const static uint16_t CountReset = 240; // 300 us / 1.25us + const static PinStatus IdleLevel = HIGH; +}; + +class NeoNrf52xPwmInvertedSpeedWs2812x +{ +public: + const static uint32_t CountTop = 20UL; // 1.25us + const static nrf_pwm_values_common_t Bit0 = 6; // ~0.4us + const static nrf_pwm_values_common_t Bit1 = 13; // ~0.8us + const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH + const static uint32_t CountReset = 240; // 300us / 1.25us pulse width + const static PinStatus IdleLevel = HIGH; +}; + +class NeoNrf52xPwmInvertedSpeedSk6812 +{ +public: + const static uint32_t CountTop = 20UL; // 1.25us + const static nrf_pwm_values_common_t Bit0 = 6; // ~0.4us + const static nrf_pwm_values_common_t Bit1 = 13; // ~0.8us + const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH + const static uint32_t CountReset = 64; // 80us / 1.25us pulse width + const static PinStatus IdleLevel = HIGH; +}; + +class NeoNrf52xPwmInvertedSpeedTm1814 +{ +public: + const static uint32_t CountTop = 20UL; // 1.25us + const static nrf_pwm_values_common_t Bit0 = 5 | 0x8000; // ~0.3us + const static nrf_pwm_values_common_t Bit1 = 12 | 0x8000; // ~0.7us + const static nrf_pwm_values_common_t BitReset = 0x8000; // LOW + const static uint32_t CountReset = 160; // 200us / 1.25us pulse width + const static PinStatus IdleLevel = LOW; +}; + +class NeoNrf52xPwmInvertedSpeed800Kbps +{ +public: + const static uint32_t CountTop = 20UL; // 1.25us + const static nrf_pwm_values_common_t Bit0 = 6; // ~0.4us + const static nrf_pwm_values_common_t Bit1 = 13; // ~0.8us + const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH + const static uint32_t CountReset = 40; // 50us / 1.25us pulse width + const static PinStatus IdleLevel = HIGH; +}; + +class NeoNrf52xPwmInvertedSpeed400Kbps +{ +public: + const static uint32_t CountTop = 40UL; // 2.5us + const static nrf_pwm_values_common_t Bit0 = 13; // ~0.8us + const static nrf_pwm_values_common_t Bit1 = 26; // ~1.6us + const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH + const static uint16_t CountReset = 20; // 50 us / 2.5us + const static PinStatus IdleLevel = HIGH; +}; + +class NeoNrf52xPwmInvertedSpeedApa106 +{ +public: + const static uint32_t CountTop = 26UL; // 1.65us + const static nrf_pwm_values_common_t Bit0 = 6; // ~0.4us + const static nrf_pwm_values_common_t Bit1 = 20; // ~1.25us + const static nrf_pwm_values_common_t BitReset = 0x0000; // HIGH + const static uint32_t CountReset = 40; // 50us / 1.25us pulse width + const static PinStatus IdleLevel = HIGH; +}; + +class NeoNrf52xPwm0 +{ +public: + inline static NRF_PWM_Type* Pwm() + { + return NRF_PWM0; + } +}; + +class NeoNrf52xPwm1 +{ +public: + inline static NRF_PWM_Type* Pwm() + { + return NRF_PWM1; + } +}; + +class NeoNrf52xPwm2 +{ +public: + inline static NRF_PWM_Type* Pwm() + { + return NRF_PWM2; + } +}; + +#if defined(NRF_PWM3) +class NeoNrf52xPwm3 +{ +public: + inline static NRF_PWM_Type* Pwm() + { + return NRF_PWM3; + } +}; +#endif + +template class NeoNrf52xMethodBase +{ +public: + NeoNrf52xMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + _pin(pin) + { + pinMode(pin, OUTPUT); + + _data = static_cast(malloc(_sizeData)); + memset(_data, 0, _sizeData); + + _dmaBufferSize = c_dmaBytesPerDataByte * _sizeData + sizeof(nrf_pwm_values_common_t); + _dmaBuffer = static_cast(malloc(_dmaBufferSize)); + } + + ~NeoNrf52xMethodBase() + { + while (!IsReadyToUpdate()) + { + yield(); + } + + dmaDeinit(); + + pinMode(_pin, INPUT); + + free(_data); + free(_dmaBuffer); + } + + bool IsReadyToUpdate() const + { + return (T_BUS::Pwm()->EVENTS_STOPPED); + } + + void Initialize() + { + digitalWrite(_pin, T_SPEED::IdleLevel); + + dmaInit(); + + // must force a first update so the EVENTS_SEQEND gets set as + // you can't set it manually + FillBuffer(); + dmaStart(); + } + + void Update(bool) + { + // Data latch = 50+ microsecond pause in the output stream. Rather than + // put a delay at the end of the function, the ending time is noted and + // the function will simply hold off (if needed) on issuing the + // subsequent round of data until the latch time has elapsed. This + // allows the mainline code to start generating the next frame of data + // rather than stalling for the latch. + while (!IsReadyToUpdate()) + { + yield(); // allows for system yield if needed + } + + FillBuffer(); + dmaStart(); + } + + uint8_t* getData() const + { + return _data; + }; + + size_t getDataSize() const + { + return _sizeData; + }; + +private: + const size_t _sizeData; // Size of '_data' buffer below + const uint8_t _pin; // output pin number + + uint8_t* _data; // Holds LED color values + size_t _dmaBufferSize; // total size of _dmaBuffer + nrf_pwm_values_common_t* _dmaBuffer; // Holds pixel data in native format for PWM hardware + + void dmaInit() + { + // only use channel zero + T_BUS::Pwm()->PSEL.OUT[0] = digitalPinToPinName(_pin); + T_BUS::Pwm()->PSEL.OUT[1] = NC; + T_BUS::Pwm()->PSEL.OUT[2] = NC; + T_BUS::Pwm()->PSEL.OUT[3] = NC; + + T_BUS::Pwm()->ENABLE = 1; + T_BUS::Pwm()->MODE = NRF_PWM_MODE_UP; + T_BUS::Pwm()->PRESCALER = NRF_PWM_CLK_16MHz; + T_BUS::Pwm()->COUNTERTOP = T_SPEED::CountTop; + T_BUS::Pwm()->LOOP = 1; // single fire so events get set + T_BUS::Pwm()->DECODER = NRF_PWM_LOAD_COMMON; + + // sequence zero is the primary data with a BitReset entry on the end for + // the delay repeating + T_BUS::Pwm()->SEQ[0].PTR = reinterpret_cast(_dmaBuffer); + T_BUS::Pwm()->SEQ[0].CNT = _dmaBufferSize / sizeof(nrf_pwm_values_common_t); + T_BUS::Pwm()->SEQ[0].REFRESH = 0; // ignored + T_BUS::Pwm()->SEQ[0].ENDDELAY = T_SPEED::CountReset; // ignored still? + + // sequence one is pointing to the BitReset entry at the end of the primary data + T_BUS::Pwm()->SEQ[1].PTR = reinterpret_cast(_dmaBuffer + (T_BUS::Pwm()->SEQ[0].CNT - 1)); + T_BUS::Pwm()->SEQ[1].CNT = 1; + T_BUS::Pwm()->SEQ[1].REFRESH = 0; // ignored + T_BUS::Pwm()->SEQ[1].ENDDELAY = 0; // ignored + + // stop when the loop finishes + T_BUS::Pwm()->SHORTS = PWM_SHORTS_LOOPSDONE_STOP_Msk; + T_BUS::Pwm()->INTEN = 0; + + dmaResetEvents(); + } + + void dmaDeinit() + { + T_BUS::Pwm()->ENABLE = 0; + T_BUS::Pwm()->PSEL.OUT[0] = NC; + } + + void FillBuffer() + { + nrf_pwm_values_common_t* pDma = _dmaBuffer; + nrf_pwm_values_common_t* pDmaEnd = _dmaBuffer + (_dmaBufferSize / sizeof(nrf_pwm_values_common_t)); + uint8_t* pEnd = _data + _sizeData; + + for (uint8_t* pData = _data; pData < pEnd; pData++) + { + uint8_t data = *pData; + + for (uint8_t bit = 0; bit < 8; bit++) + { + *(pDma++) = (data & 0x80) ? T_SPEED::Bit1 : T_SPEED::Bit0; + data <<= 1; + } + } + + // fill the rest with BitReset as it will get repeated when delaying or + // at the end before being stopped + while (pDma < pDmaEnd) + { + *(pDma++) = T_SPEED::BitReset; + } + } + + void dmaResetEvents() + { + T_BUS::Pwm()->EVENTS_LOOPSDONE = 0; + T_BUS::Pwm()->EVENTS_SEQEND[0] = 0; + T_BUS::Pwm()->EVENTS_SEQEND[1] = 0; + T_BUS::Pwm()->EVENTS_STOPPED = 0; + } + + void dmaStart() + { + dmaResetEvents(); + T_BUS::Pwm()->TASKS_SEQSTART[0] = 1; + } +}; + +// normal +typedef NeoNrf52xMethodBase NeoNrf52xPwm0Ws2811Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm0Ws2812xMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm0Sk6812Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm0Tm1814Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm0Apa106Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm0800KbpsMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm0400KbpsMethod; + +typedef NeoNrf52xMethodBase NeoNrf52xPwm1Ws2811Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm1Ws2812xMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm1Sk6812Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm1Tm1814Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm1Apa106Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm1800KbpsMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm1400KbpsMethod; + +typedef NeoNrf52xMethodBase NeoNrf52xPwm2Ws2811Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm2Ws2812xMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm2Sk6812Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm2Tm1814Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm2Apa106Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm2800KbpsMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm2400KbpsMethod; + +#if defined(NRF_PWM3) +typedef NeoNrf52xMethodBase NeoNrf52xPwm3Ws2811Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm3Ws2812xMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm3Sk6812Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm3Tm1814Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm3Apa106Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwm3800KbpsMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm3400KbpsMethod; +#endif + +// inverted +typedef NeoNrf52xMethodBase NeoNrf52xPwm0Ws2811InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm0Ws2812xInvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm0Sk6812InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm0Tm1814InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm0Apa106InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm0800KbpsInvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm0400KbpsInvertedMethod; + +typedef NeoNrf52xMethodBase NeoNrf52xPwm1Ws2811InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm1Ws2812xInvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm1Sk6812InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm1Tm1814InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm1Apa106InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm1800KbpsInvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm1400KbpsInvertedMethod; + +typedef NeoNrf52xMethodBase NeoNrf52xPwm2Ws2811InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm2Ws2812xInvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm2Sk6812InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm2Tm1814InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm2Apa106InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm2800KbpsInvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm2400KbpsInvertedMethod; + +#if defined(NRF_PWM3) +typedef NeoNrf52xMethodBase NeoNrf52xPwm3Ws2811InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm3Ws2812xInvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm3Sk6812InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm3Tm1814InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm3Apa106InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm3800KbpsInvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwm3400KbpsInvertedMethod; +#endif + +// defaults +typedef NeoNrf52xPwm2Ws2812xMethod NeoWs2813Method; +typedef NeoNrf52xPwm2Ws2812xMethod NeoWs2812xMethod; +typedef NeoNrf52xPwm2800KbpsMethod NeoWs2812Method; +typedef NeoNrf52xPwm2Ws2812xMethod NeoWs2811Method; +typedef NeoNrf52xPwm2Sk6812Method NeoSk6812Method; +typedef NeoNrf52xPwm2Tm1814Method NeoTm1814Method; +typedef NeoNrf52xPwm2Sk6812Method NeoLc8812Method; +typedef NeoNrf52xPwm2Apa106Method NeoApa106Method; + +typedef NeoNrf52xPwm2Ws2812xMethod Neo800KbpsMethod; +typedef NeoNrf52xPwm2400KbpsMethod Neo400KbpsMethod; + +typedef NeoNrf52xPwm2Ws2812xInvertedMethod NeoWs2813InvertedMethod; +typedef NeoNrf52xPwm2Ws2812xInvertedMethod NeoWs2812xInvertedMethod; +typedef NeoNrf52xPwm2Ws2812xInvertedMethod NeoWs2811InvertedMethod; +typedef NeoNrf52xPwm2800KbpsInvertedMethod NeoWs2812InvertedMethod; +typedef NeoNrf52xPwm2Sk6812InvertedMethod NeoSk6812InvertedMethod; +typedef NeoNrf52xPwm2Tm1814InvertedMethod NeoTm1814InvertedMethod; +typedef NeoNrf52xPwm2Sk6812InvertedMethod NeoLc8812InvertedMethod; +typedef NeoNrf52xPwm2Apa106InvertedMethod NeoApa106InvertedMethod; + +typedef NeoNrf52xPwm2Ws2812xInvertedMethod Neo800KbpsInvertedMethod; +typedef NeoNrf52xPwm2400KbpsInvertedMethod Neo400KbpsInvertedMethod; + +#endif diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoPixelAnimator.cpp b/lib/NeoPixelBus_by_Makuna/src/internal/NeoPixelAnimator.cpp new file mode 100644 index 0000000..55e74ae --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoPixelAnimator.cpp @@ -0,0 +1,197 @@ +/*------------------------------------------------------------------------- +NeoPixelAnimator provides animation timing support. + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#include "NeoPixelBus.h" +#include "NeoPixelAnimator.h" + +NeoPixelAnimator::NeoPixelAnimator(uint16_t countAnimations, uint16_t timeScale) : + _countAnimations(countAnimations), + _animationLastTick(0), + _activeAnimations(0), + _isRunning(true) +{ + setTimeScale(timeScale); + _animations = new AnimationContext[_countAnimations]; +} + +NeoPixelAnimator::~NeoPixelAnimator() +{ + delete[] _animations; +} + +bool NeoPixelAnimator::NextAvailableAnimation(uint16_t* indexAvailable, uint16_t indexStart) +{ + if (indexStart >= _countAnimations) + { + // last one + indexStart = _countAnimations - 1; + } + + uint16_t next = indexStart; + + do + { + if (!IsAnimationActive(next)) + { + if (indexAvailable) + { + *indexAvailable = next; + } + return true; + } + next = (next + 1) % _countAnimations; + } while (next != indexStart); + return false; +} + +void NeoPixelAnimator::StartAnimation(uint16_t indexAnimation, + uint16_t duration, + AnimUpdateCallback animUpdate) +{ + if (indexAnimation >= _countAnimations || animUpdate == NULL) + { + return; + } + + if (_activeAnimations == 0) + { + _animationLastTick = millis(); + } + + StopAnimation(indexAnimation); + + // all animations must have at least non zero duration, otherwise + // they are considered stopped + if (duration == 0) + { + duration = 1; + } + + _animations[indexAnimation].StartAnimation(duration, animUpdate); + + _activeAnimations++; +} + +void NeoPixelAnimator::StopAnimation(uint16_t indexAnimation) +{ + if (indexAnimation >= _countAnimations) + { + return; + } + + if (IsAnimationActive(indexAnimation)) + { + _activeAnimations--; + _animations[indexAnimation].StopAnimation(); + } +} + +void NeoPixelAnimator::StopAll() +{ + for (uint16_t indexAnimation = 0; indexAnimation < _countAnimations; ++indexAnimation) + { + _animations[indexAnimation].StopAnimation(); + } + _activeAnimations = 0; +} + + +void NeoPixelAnimator::UpdateAnimations() +{ + if (_isRunning) + { + uint32_t currentTick = millis(); + uint32_t delta = currentTick - _animationLastTick; + + if (delta >= _timeScale) + { + AnimationContext* pAnim; + + delta /= _timeScale; // scale delta into animation time + + for (uint16_t iAnim = 0; iAnim < _countAnimations; iAnim++) + { + pAnim = &_animations[iAnim]; + AnimUpdateCallback fnUpdate = pAnim->_fnCallback; + AnimationParam param; + + param.index = iAnim; + + if (pAnim->_remaining > delta) + { + param.state = (pAnim->_remaining == pAnim->_duration) ? AnimationState_Started : AnimationState_Progress; + param.progress = pAnim->CurrentProgress(); + + fnUpdate(param); + + pAnim->_remaining -= delta; + } + else if (pAnim->_remaining > 0) + { + param.state = AnimationState_Completed; + param.progress = 1.0f; + + _activeAnimations--; + pAnim->StopAnimation(); + + fnUpdate(param); + } + } + + _animationLastTick = currentTick; + } + } +} + +void NeoPixelAnimator::ChangeAnimationDuration(uint16_t indexAnimation, uint16_t newDuration) +{ + if (indexAnimation >= _countAnimations) + { + return; + } + + AnimationContext* pAnim = &_animations[indexAnimation]; + + // calc the current animation progress + float progress = pAnim->CurrentProgress(); + + // keep progress in range just in case + if (progress < 0.0f) + { + progress = 0.0f; + } + else if (progress > 1.0f) + { + progress = 1.0f; + } + + // change the duration + pAnim->_duration = newDuration; + + // _remaining time must also be reset after a duration change; + // use the progress to recalculate it + pAnim->_remaining = uint16_t(pAnim->_duration * (1.0f - progress)); +} \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoPixelAvr.c b/lib/NeoPixelBus_by_Makuna/src/internal/NeoPixelAvr.c new file mode 100644 index 0000000..84e9893 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoPixelAvr.c @@ -0,0 +1,648 @@ +/*------------------------------------------------------------------------- +Arduino library to control a wide variety of WS2811- and WS2812-based RGB +LED devices such as Adafruit FLORA RGB Smart Pixels and NeoPixel strips. +Currently handles 400 and 800 KHz bitstreams on 8, 12 and 16 MHz ATmega +MCUs, with LEDs wired for various color orders. 8 MHz MCUs provide +output on PORTB and PORTD, while 16 MHz chips can handle most output pins +(possible exception with upper PORT registers on the Arduino Mega). + +Written by Phil Burgess / Paint Your Dragon for Adafruit Industries, +contributions by PJRC, Michael Miller and other members of the open +source community. + +Adafruit invests time and resources providing this open source code, +please support Adafruit and open-source hardware by purchasing products +from Adafruit! + +------------------------------------------------------------------------- +The contents of this file were taken from the Adafruit NeoPixel library +and modified only to fit within individual calling functions. + +NeoPixel is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixel 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set +#if (defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)) && !defined(__arm__) + +#include + +// Hand-tuned assembly code issues data to the LED drivers at a specific +// rate. There's separate code for different CPU speeds (8, 12, 16 MHz) +// for both the WS2811 (400 KHz) and WS2812 (800 KHz) drivers. The +// datastream timing for the LED drivers allows a little wiggle room each +// way (listed in the datasheets), so the conditions for compiling each +// case are set up for a range of frequencies rather than just the exact +// 8, 12 or 16 MHz values, permitting use with some close-but-not-spot-on +// devices (e.g. 16.5 MHz DigiSpark). The ranges were arrived at based +// on the datasheet figures and have not been extensively tested outside +// the canonical 8/12/16 MHz speeds; there's no guarantee these will work +// close to the extremes (or possibly they could be pushed further). +// Keep in mind only one CPU speed case actually gets compiled; the +// resulting program isn't as massive as it might look from source here. + +#if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) // 8Mhz CPU + +#ifdef PORTD // PORTD isn't present on ATtiny85, etc. +void send_data_8mhz_800_PortD(uint8_t* data, size_t sizeData, uint8_t pinMask) +{ + volatile size_t i = sizeData; // Loop counter + volatile uint8_t* ptr = data; // Pointer to next byte + volatile uint8_t b = *ptr++; // Current byte value + volatile uint8_t hi; // PORT w/output bit set high + volatile uint8_t lo; // PORT w/output bit set low + + volatile uint8_t n1; + volatile uint8_t n2 = 0; // First, next bits out + + // Squeezing an 800 KHz stream out of an 8 MHz chip requires code + // specific to each PORT register. At present this is only written + // to work with pins on PORTD or PORTB, the most likely use case -- + // this covers all the pins on the Adafruit Flora and the bulk of + // digital pins on the Arduino Pro 8 MHz (keep in mind, this code + // doesn't even get compiled for 16 MHz boards like the Uno, Mega, + // Leonardo, etc., so don't bother extending this out of hand). + // Additional PORTs could be added if you really need them, just + // duplicate the else and loop and change the PORT. Each add'l + // PORT will require about 150(ish) bytes of program space. + + // 10 instruction clocks per bit: HHxxxxxLLL + // OUT instructions: ^ ^ ^ (T=0,2,7) + + hi = PORTD | pinMask; + lo = PORTD & ~pinMask; + n1 = lo; + + if (b & 0x80) + { + n1 = hi; + } + + // Dirty trick: RJMPs proceeding to the next instruction are used + // to delay two clock cycles in one instruction word (rather than + // using two NOPs). This was necessary in order to squeeze the + // loop down to exactly 64 words -- the maximum possible for a + // relative branch. + + asm volatile( + "headD:" "\n\t" // Clk Pseudocode + // Bit 7: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 6" "\n\t" // 1-2 if(b & 0x40) + "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 6: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 5" "\n\t" // 1-2 if(b & 0x20) + "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 5: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 4" "\n\t" // 1-2 if(b & 0x10) + "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 4: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 3" "\n\t" // 1-2 if(b & 0x08) + "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 3: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 2" "\n\t" // 1-2 if(b & 0x04) + "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 2: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 1" "\n\t" // 1-2 if(b & 0x02) + "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "rjmp .+0" "\n\t" // 2 nop nop + // Bit 1: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 + "rjmp .+0" "\n\t" // 2 nop nop + "sbrc %[byte] , 0" "\n\t" // 1-2 if(b & 0x01) + "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "sbiw %[count], 1" "\n\t" // 2 i-- (don't act on Z flag yet) + // Bit 0: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) + "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo + "brne headD" "\n" // 2 while(i) (Z flag set above) + : [byte] "+r" (b), + [n1] "+r" (n1), + [n2] "+r" (n2), + [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTD)), + [ptr] "e" (ptr), + [hi] "r" (hi), + [lo] "r" (lo) ); +} +#endif + +void send_data_8mhz_800_PortB(uint8_t* data, size_t sizeData, uint8_t pinMask) +{ + volatile size_t i = sizeData; // Loop counter + volatile uint8_t* ptr = data; // Pointer to next byte + volatile uint8_t b = *ptr++; // Current byte value + volatile uint8_t hi; // PORT w/output bit set high + volatile uint8_t lo; // PORT w/output bit set low + + volatile uint8_t n1; + volatile uint8_t n2 = 0; // First, next bits out + + // Same as above, just switched to PORTB and stripped of comments. + hi = PORTB | pinMask; + lo = PORTB & ~pinMask; + n1 = lo; + if (b & 0x80) + { + n1 = hi; + } + + asm volatile( + "headB:" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 6" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 5" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 4" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 3" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 2" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 1" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "rjmp .+0" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n2] , %[lo]" "\n\t" + "out %[port] , %[n1]" "\n\t" + "rjmp .+0" "\n\t" + "sbrc %[byte] , 0" "\n\t" + "mov %[n2] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "sbiw %[count], 1" "\n\t" + "out %[port] , %[hi]" "\n\t" + "mov %[n1] , %[lo]" "\n\t" + "out %[port] , %[n2]" "\n\t" + "ld %[byte] , %a[ptr]+" "\n\t" + "sbrc %[byte] , 7" "\n\t" + "mov %[n1] , %[hi]" "\n\t" + "out %[port] , %[lo]" "\n\t" + "brne headB" "\n" + : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), + [lo] "r" (lo)); +} + +void send_data_8mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask) +{ + volatile size_t i = sizeData; // Loop counter + volatile uint8_t* ptr = data; // Pointer to next byte + volatile uint8_t b = *ptr++; // Current byte value + volatile uint8_t hi; // PORT w/output bit set high + volatile uint8_t lo; // PORT w/output bit set low + + // Timing is more relaxed; unrolling the inner loop for each bit is + // not necessary. Still using the peculiar RJMPs as 2X NOPs, not out + // of need but just to trim the code size down a little. + // This 400-KHz-datastream-on-8-MHz-CPU code is not quite identical + // to the 800-on-16 code later -- the hi/lo timing between WS2811 and + // WS2812 is not simply a 2:1 scale! + + // 20 inst. clocks per bit: HHHHxxxxxxLLLLLLLLLL + // ST instructions: ^ ^ ^ (T=0,4,10) + + volatile uint8_t next, bit; + + hi = *port | pinMask; + lo = *port & ~pinMask; + next = lo; + bit = 8; + + asm volatile( + "head20:" "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) + "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) + "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 6) + "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7) + "dec %[bit]" "\n\t" // 1 bit-- (T = 8) + "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12) + "rjmp .+0" "\n\t" // 2 nop nop (T = 14) + "rjmp .+0" "\n\t" // 2 nop nop (T = 16) + "rjmp .+0" "\n\t" // 2 nop nop (T = 18) + "rjmp head20" "\n\t" // 2 -> head20 (next bit out) + "nextbyte20:" "\n\t" // (T = 10) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12) + "nop" "\n\t" // 1 nop (T = 13) + "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 14) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 16) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) + "brne head20" "\n" // 2 if(i != 0) -> (next byte) + : [port] "+e" (port), + [byte] "+r" (b), + [bit] "+r" (bit), + [next] "+r" (next), + [count] "+w" (i) + : [hi] "r" (hi), + [lo] "r" (lo), + [ptr] "e" (ptr)); +} + +#elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) // 12Mhz CPU + +#ifdef PORTD // PORTD isn't present on ATtiny85, etc. +void send_data_12mhz_800_PortD(uint8_t* data, size_t sizeData, uint8_t pinMask) +{ + volatile size_t i = sizeData; // Loop counter + volatile uint8_t* ptr = data; // Pointer to next byte + volatile uint8_t b = *ptr++; // Current byte value + volatile uint8_t hi; // PORT w/output bit set high + volatile uint8_t lo; // PORT w/output bit set low + + // In the 12 MHz case, an optimized 800 KHz datastream (no dead time + // between bytes) requires a PORT-specific loop similar to the 8 MHz + // code (but a little more relaxed in this case). + + // 15 instruction clocks per bit: HHHHxxxxxxLLLLL + // OUT instructions: ^ ^ ^ (T=0,4,10) + + volatile uint8_t next; + + hi = PORTD | pinMask; + lo = PORTD & ~pinMask; + next = lo; + if (b & 0x80) next = hi; + + // Don't "optimize" the OUT calls into the bitTime subroutine; + // we're exploiting the RCALL and RET as 3- and 4-cycle NOPs! + asm volatile( + "headD:" "\n\t" // (T = 0) + "out %[port], %[hi]" "\n\t" // (T = 1) + "rcall bitTimeD" "\n\t" // Bit 7 (T = 15) + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 6 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 5 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 4 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 3 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 2 + "out %[port], %[hi]" "\n\t" + "rcall bitTimeD" "\n\t" // Bit 1 + // Bit 0: + "out %[port] , %[hi]" "\n\t" // 1 PORT = hi (T = 1) + "rjmp .+0" "\n\t" // 2 nop nop (T = 3) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 5) + "out %[port] , %[next]" "\n\t" // 1 PORT = next (T = 6) + "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7) + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) (T = 8) + "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 9) + "nop" "\n\t" // 1 (T = 10) + "out %[port] , %[lo]" "\n\t" // 1 PORT = lo (T = 11) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 13) + "brne headD" "\n\t" // 2 if(i != 0) -> (next byte) + "rjmp doneD" "\n\t" + "bitTimeD:" "\n\t" // nop nop nop (T = 4) + "out %[port], %[next]" "\n\t" // 1 PORT = next (T = 5) + "mov %[next], %[lo]" "\n\t" // 1 next = lo (T = 6) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 7) + "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 0x80) (T = 8) + "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 9) + "nop" "\n\t" // 1 (T = 10) + "out %[port], %[lo]" "\n\t" // 1 PORT = lo (T = 11) + "ret" "\n\t" // 4 nop nop nop nop (T = 15) + "doneD:" "\n" + : [byte] "+r" (b), + [next] "+r" (next), + [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTD)), + [ptr] "e" (ptr), + [hi] "r" (hi), + [lo] "r" (lo)); +} +#endif + +void send_data_12mhz_800_PortB(uint8_t* data, size_t sizeData, uint8_t pinMask) +{ + volatile uint16_t i = (uint16_t)sizeData; // Loop counter + volatile uint8_t* ptr = data; // Pointer to next byte + volatile uint8_t b = *ptr++; // Current byte value + volatile uint8_t hi; // PORT w/output bit set high + volatile uint8_t lo; // PORT w/output bit set low + + volatile uint8_t next; + + hi = PORTB | pinMask; + lo = PORTB & ~pinMask; + next = lo; + if (b & 0x80) + { + next = hi; + } + + // Same as above, just set for PORTB & stripped of comments + asm volatile( + "headB:" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port], %[hi]" "\n\t" + "rcall bitTimeB" "\n\t" + "out %[port] , %[hi]" "\n\t" + "rjmp .+0" "\n\t" + "ld %[byte] , %a[ptr]+" "\n\t" + "out %[port] , %[next]" "\n\t" + "mov %[next] , %[lo]" "\n\t" + "sbrc %[byte] , 7" "\n\t" + "mov %[next] , %[hi]" "\n\t" + "nop" "\n\t" + "out %[port] , %[lo]" "\n\t" + "sbiw %[count], 1" "\n\t" + "brne headB" "\n\t" + "rjmp doneB" "\n\t" + "bitTimeB:" "\n\t" + "out %[port], %[next]" "\n\t" + "mov %[next], %[lo]" "\n\t" + "rol %[byte]" "\n\t" + "sbrc %[byte], 7" "\n\t" + "mov %[next], %[hi]" "\n\t" + "nop" "\n\t" + "out %[port], %[lo]" "\n\t" + "ret" "\n\t" + "doneB:" "\n" + : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i) + : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), + [lo] "r" (lo)); +} + +void send_data_12mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask) +{ + volatile uint16_t i = (uint16_t)sizeData; // Loop counter + volatile uint8_t* ptr = data; // Pointer to next byte + volatile uint8_t b = *ptr++; // Current byte value + volatile uint8_t hi; // PORT w/output bit set high + volatile uint8_t lo; // PORT w/output bit set low + + // 30 instruction clocks per bit: HHHHHHxxxxxxxxxLLLLLLLLLLLLLLL + // ST instructions: ^ ^ ^ (T=0,6,15) + + volatile uint8_t next, bit; + + hi = *port | pinMask; + lo = *port & ~pinMask; + next = lo; + bit = 8; + + asm volatile( + "head30:" "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) + "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) + "rjmp .+0" "\n\t" // 2 nop nop (T = 6) + "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 8) + "rjmp .+0" "\n\t" // 2 nop nop (T = 10) + "rjmp .+0" "\n\t" // 2 nop nop (T = 12) + "rjmp .+0" "\n\t" // 2 nop nop (T = 14) + "nop" "\n\t" // 1 nop (T = 15) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 17) + "rjmp .+0" "\n\t" // 2 nop nop (T = 19) + "dec %[bit]" "\n\t" // 1 bit-- (T = 20) + "breq nextbyte30" "\n\t" // 1-2 if(bit == 0) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 22) + "rjmp .+0" "\n\t" // 2 nop nop (T = 24) + "rjmp .+0" "\n\t" // 2 nop nop (T = 26) + "rjmp .+0" "\n\t" // 2 nop nop (T = 28) + "rjmp head30" "\n\t" // 2 -> head30 (next bit out) + "nextbyte30:" "\n\t" // (T = 22) + "nop" "\n\t" // 1 nop (T = 23) + "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 24) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 26) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 28) + "brne head30" "\n" // 1-2 if(i != 0) -> (next byte) + : [port] "+e" (port), + [byte] "+r" (b), + [bit] "+r" (bit), + [next] "+r" (next), + [count] "+w" (i) + : [hi] "r" (hi), + [lo] "r" (lo), + [ptr] "e" (ptr)); +} + +#elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) // 16Mhz CPU + +void send_data_16mhz_800(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask) +{ + volatile uint16_t i = (uint16_t)sizeData; // Loop counter + volatile uint8_t* ptr = data; // Pointer to next byte + volatile uint8_t b = *ptr++; // Current byte value + volatile uint8_t hi; // PORT w/output bit set high + volatile uint8_t lo; // PORT w/output bit set low + + // WS2811 and WS2812 have different hi/lo duty cycles; this is + // similar but NOT an exact copy of the prior 400-on-8 code. + + // 20 inst. clocks per bit: HHHHHxxxxxxxxLLLLLLL + // ST instructions: ^ ^ ^ (T=0,5,13) + + volatile uint8_t next; + volatile uint8_t bit; + + hi = *port | pinMask; + lo = *port & ~pinMask; + next = lo; + bit = 8; + + asm volatile( + "head20:" "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128) + "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) + "dec %[bit]" "\n\t" // 1 bit-- (T = 5) + "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7) + "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8) + "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) + "rjmp .+0" "\n\t" // 2 nop nop (T = 12) + "nop" "\n\t" // 1 nop (T = 13) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) + "nop" "\n\t" // 1 nop (T = 16) + "rjmp .+0" "\n\t" // 2 nop nop (T = 18) + "rjmp head20" "\n\t" // 2 -> head20 (next bit out) + "nextbyte20:" "\n\t" // (T = 10) + "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) + "nop" "\n\t" // 1 nop (T = 16) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) + "brne head20" "\n" // 2 if(i != 0) -> (next byte) + : [port] "+e" (port), + [byte] "+r" (b), + [bit] "+r" (bit), + [next] "+r" (next), + [count] "+w" (i) + : [ptr] "e" (ptr), + [hi] "r" (hi), + [lo] "r" (lo)); +} + +void send_data_16mhz_400(uint8_t* data, size_t sizeData, volatile uint8_t* port, uint8_t pinMask) +{ + volatile size_t i = sizeData; // Loop counter + volatile uint8_t* ptr = data; // Pointer to next byte + volatile uint8_t b = *ptr++; // Current byte value + volatile uint8_t hi; // PORT w/output bit set high + volatile uint8_t lo; // PORT w/output bit set low + + // The 400 KHz clock on 16 MHz MCU is the most 'relaxed' version. + + // 40 inst. clocks per bit: HHHHHHHHxxxxxxxxxxxxLLLLLLLLLLLLLLLLLLLL + // ST instructions: ^ ^ ^ (T=0,8,20) + + volatile uint8_t next, bit; + + hi = *port | pinMask; + lo = *port & ~pinMask; + next = lo; + bit = 8; + + asm volatile( + "head40:" "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) + "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 4) + "rjmp .+0" "\n\t" // 2 nop nop (T = 6) + "rjmp .+0" "\n\t" // 2 nop nop (T = 8) + "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 10) + "rjmp .+0" "\n\t" // 2 nop nop (T = 12) + "rjmp .+0" "\n\t" // 2 nop nop (T = 14) + "rjmp .+0" "\n\t" // 2 nop nop (T = 16) + "rjmp .+0" "\n\t" // 2 nop nop (T = 18) + "rjmp .+0" "\n\t" // 2 nop nop (T = 20) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 22) + "nop" "\n\t" // 1 nop (T = 23) + "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 24) + "dec %[bit]" "\n\t" // 1 bit-- (T = 25) + "breq nextbyte40" "\n\t" // 1-2 if(bit == 0) + "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 27) + "nop" "\n\t" // 1 nop (T = 28) + "rjmp .+0" "\n\t" // 2 nop nop (T = 30) + "rjmp .+0" "\n\t" // 2 nop nop (T = 32) + "rjmp .+0" "\n\t" // 2 nop nop (T = 34) + "rjmp .+0" "\n\t" // 2 nop nop (T = 36) + "rjmp .+0" "\n\t" // 2 nop nop (T = 38) + "rjmp head40" "\n\t" // 2 -> head40 (next bit out) + "nextbyte40:" "\n\t" // (T = 27) + "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 28) + "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 30) + "rjmp .+0" "\n\t" // 2 nop nop (T = 32) + "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 34) + "rjmp .+0" "\n\t" // 2 nop nop (T = 36) + "sbiw %[count], 1" "\n\t" // 2 i-- (T = 38) + "brne head40" "\n" // 1-2 if(i != 0) -> (next byte) + : [port] "+e" (port), + [byte] "+r" (b), + [bit] "+r" (bit), + [next] "+r" (next), + [count] "+w" (i) + : [ptr] "e" (ptr), + [hi] "r" (hi), + [lo] "r" (lo)); +} + +#else +#error "CPU SPEED NOT SUPPORTED" +#endif + +#endif diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoRingTopology.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoRingTopology.h new file mode 100644 index 0000000..e598fa4 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoRingTopology.h @@ -0,0 +1,116 @@ +#pragma once + +/*------------------------------------------------------------------------- +NeoRingTopology provides a mapping feature of a 2d polar cordinate to a +linear 1d cordinate. +It is used to map a series of concentric rings of NeoPixels to a index on +the NeoPixelBus. + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +template class NeoRingTopology : protected T_LAYOUT +{ +public: + NeoRingTopology() + { + } + + uint16_t Map(uint8_t ring, uint16_t pixel) const + { + if (pixel >= getPixelCountAtRing(ring)) + { + return 0; // invalid ring and/or pixel argument, always return a valid value, the first one + } + + return _map(ring, pixel); + } + + uint16_t MapProbe(uint8_t ring, uint16_t pixel) const + { + if (pixel >= getPixelCountAtRing(ring)) + { + return getPixelCount(); // total count, out of bounds + } + + return _map(ring, pixel); + } + + uint16_t RingPixelShift(uint8_t ring, uint16_t pixel, int16_t shift) + { + int32_t ringPixel = pixel; + ringPixel += shift; + + if (ringPixel < 0) + { + ringPixel = 0; + } + else + { + uint16_t count = getPixelCountAtRing(ring); + if (ringPixel >= count) + { + ringPixel = count - 1; + } + } + return ringPixel; + } + + uint16_t RingPixelRotate(uint8_t ring, uint16_t pixel, int16_t rotate) + { + int32_t ringPixel = pixel; + ringPixel += rotate; + return ringPixel % getPixelCountAtRing(ring); + } + + uint8_t getCountOfRings() const + { + return _ringCount() - 1; // minus one as the Rings includes the extra value + } + + uint16_t getPixelCountAtRing(uint8_t ring) const + { + if (ring >= getCountOfRings()) + { + return 0; // invalid, no pixels + } + + return T_LAYOUT::Rings[ring + 1] - T_LAYOUT::Rings[ring]; // using the extra value for count calc + } + + uint16_t getPixelCount() const + { + return T_LAYOUT::Rings[_ringCount() - 1]; // the last entry is the total count + } + +private: + uint16_t _map(uint8_t ring, uint16_t pixel) const + { + return T_LAYOUT::Rings[ring] + pixel; + } + + uint8_t _ringCount() const + { + return sizeof(T_LAYOUT::Rings) / sizeof(T_LAYOUT::Rings[0]); + } +}; diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoSegmentFeatures.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoSegmentFeatures.h new file mode 100644 index 0000000..f0118f6 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoSegmentFeatures.h @@ -0,0 +1,130 @@ +/*------------------------------------------------------------------------- +NeoSegmentFeatures provides feature classes to describe seven segment display +elements for NeoPixelBus template class + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +class Neo9Elements +{ +public: + static const size_t PixelSize = 9; // three 3 element + + static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + + static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + while (pPixelDest < pEnd) + { + for (uint8_t iElement = 0; iElement < PixelSize; iElement++) + { + *pPixelDest++ = pPixelSrc[iElement]; + } + } + } + + static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + while (pPixelDest < pEnd) + { + *pPixelDest++ = *pPixelSrc++; + } + } + + static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + const uint8_t* pSrc = (const uint8_t*)pPixelSrc; + while (pPixelDest < pEnd) + { + *pPixelDest++ = pgm_read_byte(pSrc++); + } + } + + static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pDestBack = pPixelDest + (count * PixelSize); + const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize); + while (pDestBack > pPixelDest) + { + *--pDestBack = *--pSrcBack; + } + } + + typedef SevenSegDigit ColorObject; +}; + +// Abcdefg byte order +class NeoAbcdefgSegmentFeature : public Neo9Elements +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + uint8_t commonSize = (PixelSize < color.SegmentCount) ? PixelSize : color.SegmentCount; + for (uint8_t iSegment = 0; iSegment < commonSize; iSegment++) + { + *p++ = color.Segment[iSegment]; + } + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + uint8_t commonSize = (PixelSize < color.SegmentCount) ? PixelSize : color.SegmentCount; + + for (uint8_t iSegment = 0; iSegment < commonSize; iSegment++) + { + color.Segment[iSegment] = *p++; + } + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + uint8_t commonSize = (PixelSize < color.SegmentCount) ? PixelSize : color.SegmentCount; + + for (uint8_t iSegment = 0; iSegment < commonSize; iSegment++) + { + color.Segment[iSegment] = pgm_read_byte(p++); + } + + return color; + } + +}; + +typedef NeoAbcdefgSegmentFeature SevenSegmentFeature; // Abcdefg order is default \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoSettings.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoSettings.h new file mode 100644 index 0000000..1af9f82 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoSettings.h @@ -0,0 +1,62 @@ +/*------------------------------------------------------------------------- +NeoSettings provides settings classes to describe settings + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +class NeoNoSettings +{ +}; + +class NeoRgbCurrentSettings +{ +public: + NeoRgbCurrentSettings(uint16_t red, uint16_t green, uint16_t blue) : + RedTenthMilliAmpere(red), + GreenTenthMilliAmpere(green), + BlueTenthMilliAmpere(blue) + { + } + + uint16_t RedTenthMilliAmpere; // in 1/10th ma + uint16_t GreenTenthMilliAmpere; // in 1/10th ma + uint16_t BlueTenthMilliAmpere; // in 1/10th ma +}; + +class NeoRgbwCurrentSettings +{ +public: + NeoRgbwCurrentSettings(uint16_t red, uint16_t green, uint16_t blue, uint16_t white) : + RedTenthMilliAmpere(red), + GreenTenthMilliAmpere(green), + BlueTenthMilliAmpere(blue), + WhiteCurrent(white) + { + } + + uint16_t RedTenthMilliAmpere; // in 1/10th ma + uint16_t GreenTenthMilliAmpere; // in 1/10th ma + uint16_t BlueTenthMilliAmpere; // in 1/10th ma + uint16_t WhiteCurrent; // in 1/10th ma +}; \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoSpriteSheet.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoSpriteSheet.h new file mode 100644 index 0000000..83fb978 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoSpriteSheet.h @@ -0,0 +1,163 @@ +/*------------------------------------------------------------------------- +NeoPixel library + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + + +template class NeoVerticalSpriteSheet +{ +public: + NeoVerticalSpriteSheet(uint16_t width, + uint16_t height, + uint16_t spriteHeight, + PGM_VOID_P pixels) : + _method(width, height, pixels), + _spriteHeight(spriteHeight), + _spriteCount(height / spriteHeight) + { + } + + operator NeoBufferContext() + { + return _method; + } + + uint16_t SpriteWidth() const + { + return _method.Width(); + }; + + uint16_t SpriteHeight() const + { + return _spriteHeight; + }; + + uint16_t SpriteCount() const + { + return _spriteCount; + } + + void SetPixelColor(uint16_t indexSprite, + int16_t x, + int16_t y, + typename T_BUFFER_METHOD::ColorObject color) + { + _method.SetPixelColor(pixelIndex(indexSprite, x, y), color); + }; + + typename T_BUFFER_METHOD::ColorObject GetPixelColor(uint16_t indexSprite, + int16_t x, + int16_t y) const + { + return _method.GetPixelColor(pixelIndex(indexSprite, x, y)); + }; + + void ClearTo(typename T_BUFFER_METHOD::ColorObject color) + { + _method.ClearTo(color); + }; + + void Blt(NeoBufferContext destBuffer, + uint16_t indexPixel, + uint16_t indexSprite) + { + uint16_t destPixelCount = destBuffer.PixelCount(); + // validate indexPixel + if (indexPixel >= destPixelCount) + { + return; + } + + // validate indexSprite + if (indexSprite >= _spriteCount) + { + return; + } + // calc how many we can copy + uint16_t copyCount = destPixelCount - indexPixel; + + if (copyCount > SpriteWidth()) + { + copyCount = SpriteWidth(); + } + + uint8_t* pDest = T_BUFFER_METHOD::ColorFeature::getPixelAddress(destBuffer.Pixels, indexPixel); + const uint8_t* pSrc = T_BUFFER_METHOD::ColorFeature::getPixelAddress(_method.Pixels(), pixelIndex(indexSprite, 0, 0)); + _method.CopyPixels(pDest, pSrc, copyCount); + } + + void Blt(NeoBufferContext destBuffer, + int16_t x, + int16_t y, + uint16_t indexSprite, + LayoutMapCallback layoutMap) + { + if (indexSprite >= _spriteCount) + { + return; + } + uint16_t destPixelCount = destBuffer.PixelCount(); + + for (int16_t srcY = 0; srcY < SpriteHeight(); srcY++) + { + for (int16_t srcX = 0; srcX < SpriteWidth(); srcX++) + { + uint16_t indexDest = layoutMap(srcX + x, srcY + y); + + if (indexDest < destPixelCount) + { + const uint8_t* pSrc = T_BUFFER_METHOD::ColorFeature::getPixelAddress(_method.Pixels(), pixelIndex(indexSprite, srcX, srcY)); + uint8_t* pDest = T_BUFFER_METHOD::ColorFeature::getPixelAddress(destBuffer.Pixels, indexDest); + + _method.CopyPixels(pDest, pSrc, 1); + } + } + } + + } + +private: + T_BUFFER_METHOD _method; + + const uint16_t _spriteHeight; + const uint16_t _spriteCount; + + uint16_t pixelIndex(uint16_t indexSprite, + int16_t x, + int16_t y) const + { + uint16_t result = PixelIndex_OutOfBounds; + + if (indexSprite < _spriteCount && + x >= 0 && + (uint16_t)x < SpriteWidth() && + y >= 0 && + (uint16_t)y < SpriteHeight()) + { + result = x + y * SpriteWidth() + indexSprite * _spriteHeight * SpriteWidth(); + } + return result; + } +}; \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoTiles.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoTiles.h new file mode 100644 index 0000000..2c0ca83 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoTiles.h @@ -0,0 +1,158 @@ +#pragma once + +/*------------------------------------------------------------------------- +NeoTiles provides a mapping feature of a 2d cordinate to linear 1d cordinate +It is used to map tiles of matricies of NeoPixels to a index on the NeoPixelBus +where the the matricies use one topology and the tiles of those matricies can +use another + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +//----------------------------------------------------------------------------- +// class NeoTiles +// Simple template Tile layout class +// T_MATRIX_LAYOUT = the layout used on the pixel matrix panel (a tile) +// T_TILE_LAYOUT = the layout used for the tiles. +// +//----------------------------------------------------------------------------- +template class NeoTiles +{ +public: + NeoTiles(uint16_t topoWidth, uint16_t topoHeight, + uint16_t tilesWidth, uint16_t tilesHeight) : + _topo(topoWidth, topoHeight), + _width(tilesWidth), + _height(tilesHeight) + { + } + + uint16_t Map(int16_t x, int16_t y) const + { + uint16_t totalWidth = getWidth(); + uint16_t totalHeight = getHeight(); + + if (x >= totalWidth) + { + x = totalWidth - 1; + } + else if (x < 0) + { + x = 0; + } + + if (y >= totalHeight) + { + y = totalHeight - 1; + } + else if (y < 0) + { + y = 0; + } + + uint16_t localIndex; + uint16_t tileOffset; + + calculate(x, y, &localIndex, &tileOffset); + + return localIndex + tileOffset; + } + + uint16_t MapProbe(int16_t x, int16_t y) const + { + uint16_t totalWidth = getWidth(); + uint16_t totalHeight = getHeight(); + + if (x < 0 || x >= totalWidth || y < 0 || y >= totalHeight) + { + return totalWidth * totalHeight; // count, out of bounds + } + + uint16_t localIndex; + uint16_t tileOffset; + + calculate(x, y, &localIndex, &tileOffset); + + return localIndex + tileOffset; + } + + NeoTopologyHint TopologyHint(int16_t x, int16_t y) const + { + uint16_t totalWidth = getWidth(); + uint16_t totalHeight = getHeight(); + + if (x < 0 || x >= totalWidth || y < 0 || y >= totalHeight) + { + return NeoTopologyHint_OutOfBounds; + } + + uint16_t localIndex; + uint16_t tileOffset; + NeoTopologyHint result; + + calculate(x, y, &localIndex, &tileOffset); + + if (localIndex == 0) + { + result = NeoTopologyHint_FirstOnPanel; + } + else if (localIndex == (_topo.getWidth() * _topo.getHeight() - 1)) + { + result = NeoTopologyHint_LastOnPanel; + } + else + { + result = NeoTopologyHint_InPanel; + } + + return result; + } + + uint16_t getWidth() const + { + return _width * _topo.getWidth(); + } + + uint16_t getHeight() const + { + return _height * _topo.getHeight(); + } + +private: + const NeoTopology _topo; + const uint16_t _width; + const uint16_t _height; + + void calculate(uint16_t x, uint16_t y, uint16_t* pLocalIndex, uint16_t* pTileOffset) const + { + uint16_t tileX = x / _topo.getWidth(); + uint16_t topoX = x % _topo.getWidth(); + + uint16_t tileY = y / _topo.getHeight(); + uint16_t topoY = y % _topo.getHeight(); + + *pTileOffset = T_TILE_LAYOUT::Map(_width, _height, tileX, tileY) * _topo.getWidth() * _topo.getHeight(); + *pLocalIndex = _topo.Map(topoX, topoY); + } +}; + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoTm1814ColorFeatures.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoTm1814ColorFeatures.h new file mode 100644 index 0000000..bc5035f --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoTm1814ColorFeatures.h @@ -0,0 +1,131 @@ +/*------------------------------------------------------------------------- +NeoTm1814ColorFeatures provides feature classes to describe color order and +color depth for NeoPixelBus template class specific to the TM1814 chip + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +class NeoTm1814Settings : public NeoRgbwCurrentSettings +{ +public: + NeoTm1814Settings(uint16_t red, uint16_t green, uint16_t blue, uint16_t white) : + NeoRgbwCurrentSettings(red, green, blue, white) + { + } + + const static uint16_t MinCurrent = 65; + const static uint16_t MaxCurrent = 380; + + static uint16_t LimitCurrent(uint16_t value) + { + if (value < MinCurrent) + { + value = MinCurrent; + } + else if (value > MaxCurrent) + { + value = MaxCurrent; + } + return value; + } +}; + +class Neo4ElementsTm1814Settings : public Neo4Elements +{ +public: + typedef NeoTm1814Settings SettingsObject; + static const size_t SettingsSize = 8; + + static void applySettings(uint8_t* pData, const SettingsObject& settings) + { + uint8_t* pSet = pData; + + // C1 + *pSet++ = (SettingsObject::LimitCurrent(settings.WhiteCurrent) - SettingsObject::MinCurrent) / 5; + *pSet++ = (SettingsObject::LimitCurrent(settings.RedTenthMilliAmpere) - SettingsObject::MinCurrent) / 5; + *pSet++ = (SettingsObject::LimitCurrent(settings.GreenTenthMilliAmpere) - SettingsObject::MinCurrent) / 5; + *pSet++ = (SettingsObject::LimitCurrent(settings.BlueTenthMilliAmpere) - SettingsObject::MinCurrent) / 5; + + uint8_t* pC1 = pData; + + // C2 + for (uint8_t elem = 0; elem < 4; elem++) + { + *pSet++ = ~(*pC1++); + } + } + + static uint8_t* pixels(uint8_t* pData) + { + return pData + SettingsSize; + } + + static const uint8_t* pixels(const uint8_t* pData) + { + return pData; + } +}; + + +class NeoWrgbTm1814Feature : public Neo4ElementsTm1814Settings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = color.W; + *p++ = color.R; + *p++ = color.G; + *p = color.B; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + color.W = *p++; + color.R = *p++; + color.G = *p++; + color.B = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + color.W = pgm_read_byte(p++); + color.R = pgm_read_byte(p++); + color.G = pgm_read_byte(p++); + color.B = pgm_read_byte(p); + + return color; + } + +}; + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/NeoTopology.h b/lib/NeoPixelBus_by_Makuna/src/internal/NeoTopology.h new file mode 100644 index 0000000..224c1db --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/NeoTopology.h @@ -0,0 +1,91 @@ +#pragma once + +/*------------------------------------------------------------------------- +NeoTopology provides a mapping feature of a 2d cordinate to linear 1d cordinate +It is used to map a matrix of NeoPixels to a index on the NeoPixelBus + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +enum NeoTopologyHint +{ + NeoTopologyHint_FirstOnPanel, + NeoTopologyHint_InPanel, + NeoTopologyHint_LastOnPanel, + NeoTopologyHint_OutOfBounds +}; + +template class NeoTopology +{ +public: + NeoTopology(uint16_t width, uint16_t height) : + _width(width), + _height(height) + { + + } + + uint16_t Map(int16_t x, int16_t y) const + { + if (x >= _width) + { + x = _width - 1; + } + else if (x < 0) + { + x = 0; + } + if (y >= _height) + { + y = _height - 1; + } + else if (y < 0) + { + y = 0; + } + return T_LAYOUT::Map(_width, _height, x, y); + } + + uint16_t MapProbe(int16_t x, int16_t y) const + { + if (x < 0 || x >= _width || y < 0 || y >= _height) + { + return _width * _height; // count, out of bounds + } + return T_LAYOUT::Map(_width, _height, x, y); + } + + uint16_t getWidth() const + { + return _width; + } + + uint16_t getHeight() const + { + return _height; + } + +private: + const uint16_t _width; + const uint16_t _height; +}; diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/P9813ColorFeatures.h b/lib/NeoPixelBus_by_Makuna/src/internal/P9813ColorFeatures.h new file mode 100644 index 0000000..2212e1f --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/P9813ColorFeatures.h @@ -0,0 +1,162 @@ +/*------------------------------------------------------------------------- +P9813ColorFeatures provides feature classes to describe color order and +color depth for NeoPixelBus template class when used with P9813s + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +class P98133Elements +{ +public: + static const size_t PixelSize = 4; // still requires 4 to be sent + + static uint8_t* getPixelAddress(uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + static const uint8_t* getPixelAddress(const uint8_t* pPixels, uint16_t indexPixel) + { + return pPixels + indexPixel * PixelSize; + } + + static void replicatePixel(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + while (pPixelDest < pEnd) + { + *pPixelDest++ = pPixelSrc[0]; + *pPixelDest++ = pPixelSrc[1]; + *pPixelDest++ = pPixelSrc[2]; + *pPixelDest++ = pPixelSrc[3]; + } + } + + static void movePixelsInc(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + while (pPixelDest < pEnd) + { + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + *pPixelDest++ = *pPixelSrc++; + } + } + + static void movePixelsInc_P(uint8_t* pPixelDest, PGM_VOID_P pPixelSrc, uint16_t count) + { + uint8_t* pEnd = pPixelDest + (count * PixelSize); + const uint8_t* pSrc = (const uint8_t*)pPixelSrc; + while (pPixelDest < pEnd) + { + *pPixelDest++ = pgm_read_byte(pSrc++); + *pPixelDest++ = pgm_read_byte(pSrc++); + *pPixelDest++ = pgm_read_byte(pSrc++); + *pPixelDest++ = pgm_read_byte(pSrc++); + } + } + + static void movePixelsDec(uint8_t* pPixelDest, const uint8_t* pPixelSrc, uint16_t count) + { + uint8_t* pDestBack = pPixelDest + (count * PixelSize); + const uint8_t* pSrcBack = pPixelSrc + (count * PixelSize); + while (pDestBack > pPixelDest) + { + *--pDestBack = *--pSrcBack; + *--pDestBack = *--pSrcBack; + *--pDestBack = *--pSrcBack; + *--pDestBack = *--pSrcBack; + } + } + + typedef RgbColor ColorObject; +}; + +class P98133ElementsNoSettings : public P98133Elements +{ +public: + typedef NeoNoSettings SettingsObject; + static const size_t SettingsSize = 0; + + static void applySettings(uint8_t*, const SettingsObject&) + { + } + + static uint8_t* pixels(uint8_t* pData) + { + return pData; + } + + static const uint8_t* pixels(const uint8_t* pData) + { + return pData; + } +}; + +class P9813BgrFeature : public P98133ElementsNoSettings +{ +public: + static void applyPixelColor(uint8_t* pPixels, uint16_t indexPixel, ColorObject color) + { + uint8_t* p = getPixelAddress(pPixels, indexPixel); + + *p++ = 0xC0 | ((~color.B & 0xC0) >> 2) | ((~color.G & 0xC0) >> 4) | ((~color.R & 0xC0) >> 6); + *p++ = color.B; + *p++ = color.G; + *p = color.R; + } + + static ColorObject retrievePixelColor(const uint8_t* pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress(pPixels, indexPixel); + + p++; // ignore the first byte + color.B = *p++; + color.G = *p++; + color.R = *p; + + return color; + } + + static ColorObject retrievePixelColor_P(PGM_VOID_P pPixels, uint16_t indexPixel) + { + ColorObject color; + const uint8_t* p = getPixelAddress((const uint8_t*)pPixels, indexPixel); + + pgm_read_byte(p++); // ignore the first byte + color.B = pgm_read_byte(p++); + color.G = pgm_read_byte(p++); + color.R = pgm_read_byte(p); + + return color; + } + +}; + + + + + + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/P9813GenericMethod.h b/lib/NeoPixelBus_by_Makuna/src/internal/P9813GenericMethod.h new file mode 100644 index 0000000..37a15f6 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/P9813GenericMethod.h @@ -0,0 +1,126 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for P9813s using general Pins (APA102). + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set +#if defined(ARDUINO_ARCH_AVR) && !defined(__arm__) +#include "TwoWireBitBangImpleAvr.h" +#else +#include "TwoWireBitBangImple.h" +#endif + + +template class P9813MethodBase +{ +public: + P9813MethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + _sizeEndFrame((pixelCount + 15) / 16), // 16 = div 2 (bit for every two pixels) div 8 (bits to bytes) + _wire(pinClock, pinData) + { + _data = static_cast(malloc(_sizeData)); + memset(_data, 0, _sizeData); + } + +#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny) + P9813MethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + P9813MethodBase(SCK, MOSI, pixelCount, elementSize, settingsSize) + { + } +#endif + + ~P9813MethodBase() + { + free(_data); + } + + bool IsReadyToUpdate() const + { + return true; // dot stars don't have a required delay + } + +#if defined(ARDUINO_ARCH_ESP32) + void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) + { + _wire.begin(sck, miso, mosi, ss); + } +#endif + + void Initialize() + { + _wire.begin(); + } + + void Update(bool) + { + const uint8_t startFrame[4] = { 0x00 }; + const uint8_t endFrame[4] = { 0x00 }; + + _wire.beginTransaction(); + + // start frame + _wire.transmitBytes(startFrame, sizeof(startFrame)); + + // data + _wire.transmitBytes(_data, _sizeData); + + // end frame + _wire.transmitBytes(endFrame, sizeof(endFrame)); + + _wire.endTransaction(); + } + + uint8_t* getData() const + { + return _data; + }; + + size_t getDataSize() const + { + return _sizeData; + }; + +private: + const size_t _sizeData; // Size of '_data' buffer below + const size_t _sizeEndFrame; + + T_TWOWIRE _wire; + uint8_t* _data; // Holds LED color values +}; + +typedef P9813MethodBase P9813Method; + +#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny) +#include "TwoWireSpiImple.h" +typedef P9813MethodBase> P9813Spi20MhzMethod; +typedef P9813MethodBase> P9813Spi10MhzMethod; +typedef P9813MethodBase> P9813Spi2MhzMethod; +typedef P9813Spi10MhzMethod P9813SpiMethod; +#endif + + + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/RgbColor.cpp b/lib/NeoPixelBus_by_Makuna/src/internal/RgbColor.cpp new file mode 100644 index 0000000..30a7811 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/RgbColor.cpp @@ -0,0 +1,261 @@ +/*------------------------------------------------------------------------- +RgbColor provides a color object that can be directly consumed by NeoPixelBus + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#include "RgbColor.h" +#include "HslColor.h" +#include "HsbColor.h" +#include "HtmlColor.h" + +static float _CalcColor(float p, float q, float t) +{ + if (t < 0.0f) + t += 1.0f; + if (t > 1.0f) + t -= 1.0f; + + if (t < 1.0f / 6.0f) + return p + (q - p) * 6.0f * t; + + if (t < 0.5f) + return q; + + if (t < 2.0f / 3.0f) + return p + ((q - p) * (2.0f / 3.0f - t) * 6.0f); + + return p; +} + +RgbColor::RgbColor(const HtmlColor& color) +{ + uint32_t temp = color.Color; + + B = (temp & 0xff); + temp = temp >> 8; + G = (temp & 0xff); + temp = temp >> 8; + R = (temp & 0xff); +}; + +RgbColor::RgbColor(const HslColor& color) +{ + float r; + float g; + float b; + + float h = color.H; + float s = color.S; + float l = color.L; + + + if (color.S == 0.0f || color.L == 0.0f) + { + r = g = b = l; // achromatic or black + } + else + { + float q = l < 0.5f ? l * (1.0f + s) : l + s - (l * s); + float p = 2.0f * l - q; + r = _CalcColor(p, q, h + 1.0f / 3.0f); + g = _CalcColor(p, q, h); + b = _CalcColor(p, q, h - 1.0f / 3.0f); + } + + R = (uint8_t)(r * 255.0f); + G = (uint8_t)(g * 255.0f); + B = (uint8_t)(b * 255.0f); +} + +RgbColor::RgbColor(const HsbColor& color) +{ + float r; + float g; + float b; + + float h = color.H; + float s = color.S; + float v = color.B; + + if (color.S == 0.0f) + { + r = g = b = v; // achromatic or black + } + else + { + if (h < 0.0f) + { + h += 1.0f; + } + else if (h >= 1.0f) + { + h -= 1.0f; + } + h *= 6.0f; + int i = (int)h; + float f = h - i; + float q = v * (1.0f - s * f); + float p = v * (1.0f - s); + float t = v * (1.0f - s * (1.0f - f)); + switch (i) + { + case 0: + r = v; + g = t; + b = p; + break; + case 1: + r = q; + g = v; + b = p; + break; + case 2: + r = p; + g = v; + b = t; + break; + case 3: + r = p; + g = q; + b = v; + break; + case 4: + r = t; + g = p; + b = v; + break; + default: + r = v; + g = p; + b = q; + break; + } + } + + R = (uint8_t)(r * 255.0f); + G = (uint8_t)(g * 255.0f); + B = (uint8_t)(b * 255.0f); +} + +uint8_t RgbColor::CalculateBrightness() const +{ + return (uint8_t)(((uint16_t)R + (uint16_t)G + (uint16_t)B) / 3); +} + +RgbColor RgbColor::Dim(uint8_t ratio) const +{ + // specifically avoids float math + return RgbColor(_elementDim(R, ratio), _elementDim(G, ratio), _elementDim(B, ratio)); +} + +RgbColor RgbColor::Brighten(uint8_t ratio) const +{ + // specifically avoids float math + return RgbColor(_elementBrighten(R, ratio), _elementBrighten(G, ratio), _elementBrighten(B, ratio)); +} + +void RgbColor::Darken(uint8_t delta) +{ + if (R > delta) + { + R -= delta; + } + else + { + R = 0; + } + + if (G > delta) + { + G -= delta; + } + else + { + G = 0; + } + + if (B > delta) + { + B -= delta; + } + else + { + B = 0; + } +} + +void RgbColor::Lighten(uint8_t delta) +{ + if (R < 255 - delta) + { + R += delta; + } + else + { + R = 255; + } + + if (G < 255 - delta) + { + G += delta; + } + else + { + G = 255; + } + + if (B < 255 - delta) + { + B += delta; + } + else + { + B = 255; + } +} + +RgbColor RgbColor::LinearBlend(const RgbColor& left, const RgbColor& right, float progress) +{ + return RgbColor( left.R + ((right.R - left.R) * progress), + left.G + ((right.G - left.G) * progress), + left.B + ((right.B - left.B) * progress)); +} + +RgbColor RgbColor::BilinearBlend(const RgbColor& c00, + const RgbColor& c01, + const RgbColor& c10, + const RgbColor& c11, + float x, + float y) +{ + float v00 = (1.0f - x) * (1.0f - y); + float v10 = x * (1.0f - y); + float v01 = (1.0f - x) * y; + float v11 = x * y; + + return RgbColor( + c00.R * v00 + c10.R * v10 + c01.R * v01 + c11.R * v11, + c00.G * v00 + c10.G * v10 + c01.G * v01 + c11.G * v11, + c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11); +} \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/RgbColor.h b/lib/NeoPixelBus_by_Makuna/src/internal/RgbColor.h new file mode 100644 index 0000000..b50857b --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/RgbColor.h @@ -0,0 +1,199 @@ +/*------------------------------------------------------------------------- +RgbColor provides a color object that can be directly consumed by NeoPixelBus + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +#include +#include "NeoSettings.h" + +struct HslColor; +struct HsbColor; +struct HtmlColor; + +// ------------------------------------------------------------------------ +// RgbColor represents a color object that is represented by Red, Green, Blue +// component values. It contains helpful color routines to manipulate the +// color. +// ------------------------------------------------------------------------ +struct RgbColor +{ + typedef NeoRgbCurrentSettings SettingsObject; + + // ------------------------------------------------------------------------ + // Construct a RgbColor using R, G, B values (0-255) + // ------------------------------------------------------------------------ + RgbColor(uint8_t r, uint8_t g, uint8_t b) : + R(r), G(g), B(b) + { + }; + + // ------------------------------------------------------------------------ + // Construct a RgbColor using a single brightness value (0-255) + // This works well for creating gray tone colors + // (0) = black, (255) = white, (128) = gray + // ------------------------------------------------------------------------ + RgbColor(uint8_t brightness) : + R(brightness), G(brightness), B(brightness) + { + }; + + // ------------------------------------------------------------------------ + // Construct a RgbColor using HtmlColor + // ------------------------------------------------------------------------ + RgbColor(const HtmlColor& color); + + // ------------------------------------------------------------------------ + // Construct a RgbColor using HslColor + // ------------------------------------------------------------------------ + RgbColor(const HslColor& color); + + // ------------------------------------------------------------------------ + // Construct a RgbColor using HsbColor + // ------------------------------------------------------------------------ + RgbColor(const HsbColor& color); + + // ------------------------------------------------------------------------ + // Construct a RgbColor that will have its values set in latter operations + // CAUTION: The R,G,B members are not initialized and may not be consistent + // ------------------------------------------------------------------------ + RgbColor() + { + }; + + // ------------------------------------------------------------------------ + // Comparison operators + // ------------------------------------------------------------------------ + bool operator==(const RgbColor& other) const + { + return (R == other.R && G == other.G && B == other.B); + }; + + bool operator!=(const RgbColor& other) const + { + return !(*this == other); + }; + + // ------------------------------------------------------------------------ + // CalculateBrightness will calculate the overall brightness + // NOTE: This is a simple linear brightness + // ------------------------------------------------------------------------ + uint8_t CalculateBrightness() const; + + // ------------------------------------------------------------------------ + // Dim will return a new color that is blended to black with the given ratio + // ratio - (0-255) where 255 will return the original color and 0 will return black + // + // NOTE: This is a simple linear blend + // ------------------------------------------------------------------------ + RgbColor Dim(uint8_t ratio) const; + + // ------------------------------------------------------------------------ + // Brighten will return a new color that is blended to white with the given ratio + // ratio - (0-255) where 255 will return the original color and 0 will return white + // + // NOTE: This is a simple linear blend + // ------------------------------------------------------------------------ + RgbColor Brighten(uint8_t ratio) const; + + // ------------------------------------------------------------------------ + // Darken will adjust the color by the given delta toward black + // NOTE: This is a simple linear change + // delta - (0-255) the amount to dim the color + // ------------------------------------------------------------------------ + void Darken(uint8_t delta); + + // ------------------------------------------------------------------------ + // Lighten will adjust the color by the given delta toward white + // NOTE: This is a simple linear change + // delta - (0-255) the amount to lighten the color + // ------------------------------------------------------------------------ + void Lighten(uint8_t delta); + + // ------------------------------------------------------------------------ + // LinearBlend between two colors by the amount defined by progress variable + // left - the color to start the blend at + // right - the color to end the blend at + // progress - (0.0 - 1.0) value where 0 will return left and 1.0 will return right + // and a value between will blend the color weighted linearly between them + // ------------------------------------------------------------------------ + static RgbColor LinearBlend(const RgbColor& left, const RgbColor& right, float progress); + + // ------------------------------------------------------------------------ + // BilinearBlend between four colors by the amount defined by 2d variable + // c00 - upper left quadrant color + // c01 - upper right quadrant color + // c10 - lower left quadrant color + // c11 - lower right quadrant color + // x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space + // y - unit value (0.0 - 1.0) that defines the blend progress in vertical space + // ------------------------------------------------------------------------ + static RgbColor BilinearBlend(const RgbColor& c00, + const RgbColor& c01, + const RgbColor& c10, + const RgbColor& c11, + float x, + float y); + + uint32_t CalcTotalTenthMilliAmpere(const SettingsObject& settings) + { + auto total = 0; + + total += R * settings.RedTenthMilliAmpere / 255; + total += G * settings.GreenTenthMilliAmpere / 255; + total += B * settings.BlueTenthMilliAmpere / 255; + + return total; + } + + // ------------------------------------------------------------------------ + // Red, Green, Blue color members (0-255) where + // (0,0,0) is black and (255,255,255) is white + // ------------------------------------------------------------------------ + uint8_t R; + uint8_t G; + uint8_t B; + +private: + inline static uint8_t _elementDim(uint8_t value, uint8_t ratio) + { + return (static_cast(value) * (static_cast(ratio) + 1)) >> 8; + } + + inline static uint8_t _elementBrighten(uint8_t value, uint8_t ratio) + { + uint16_t element = ((static_cast(value) + 1) << 8) / (static_cast(ratio) + 1); + + if (element > 255) + { + element = 255; + } + else + { + element -= 1; + } + return element; + } +}; + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/RgbwColor.cpp b/lib/NeoPixelBus_by_Makuna/src/internal/RgbwColor.cpp new file mode 100644 index 0000000..cb9681f --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/RgbwColor.cpp @@ -0,0 +1,190 @@ +/*------------------------------------------------------------------------- +RgbwColor provides a color object that can be directly consumed by NeoPixelBus + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#include "RgbColor.h" +#include "HslColor.h" +#include "HsbColor.h" +#include "RgbwColor.h" +#include "HtmlColor.h" + +RgbwColor::RgbwColor(const HtmlColor& color) +{ + uint32_t temp = color.Color; + B = (temp & 0xff); + temp = temp >> 8; + G = (temp & 0xff); + temp = temp >> 8; + R = (temp & 0xff); + temp = temp >> 8; + W = (temp & 0xff); +}; + +RgbwColor::RgbwColor(const HslColor& color) +{ + RgbColor rgbColor(color); + *this = rgbColor; +} + +RgbwColor::RgbwColor(const HsbColor& color) +{ + RgbColor rgbColor(color); + *this = rgbColor; +} + +uint8_t RgbwColor::CalculateBrightness() const +{ + uint8_t colorB = (uint8_t)(((uint16_t)R + (uint16_t)G + (uint16_t)B) / 3); + if (W > colorB) + { + return W; + } + else + { + return colorB; + } +} + +RgbwColor RgbwColor::Dim(uint8_t ratio) const +{ + // specifically avoids float math + return RgbwColor(_elementDim(R, ratio), _elementDim(G, ratio), _elementDim(B, ratio), _elementDim(W, ratio)); +} + +RgbwColor RgbwColor::Brighten(uint8_t ratio) const +{ + // specifically avoids float math + return RgbwColor(_elementBrighten(R, ratio), _elementBrighten(G, ratio), _elementBrighten(B, ratio), _elementBrighten(W, ratio)); +} + +void RgbwColor::Darken(uint8_t delta) +{ + if (R > delta) + { + R -= delta; + } + else + { + R = 0; + } + + if (G > delta) + { + G -= delta; + } + else + { + G = 0; + } + + if (B > delta) + { + B -= delta; + } + else + { + B = 0; + } + + if (W > delta) + { + W -= delta; + } + else + { + W = 0; + } +} + +void RgbwColor::Lighten(uint8_t delta) +{ + if (IsColorLess()) + { + if (W < 255 - delta) + { + W += delta; + } + else + { + W = 255; + } + } + else + { + if (R < 255 - delta) + { + R += delta; + } + else + { + R = 255; + } + + if (G < 255 - delta) + { + G += delta; + } + else + { + G = 255; + } + + if (B < 255 - delta) + { + B += delta; + } + else + { + B = 255; + } + } +} + +RgbwColor RgbwColor::LinearBlend(const RgbwColor& left, const RgbwColor& right, float progress) +{ + return RgbwColor( left.R + ((right.R - left.R) * progress), + left.G + ((right.G - left.G) * progress), + left.B + ((right.B - left.B) * progress), + left.W + ((right.W - left.W) * progress) ); +} + +RgbwColor RgbwColor::BilinearBlend(const RgbwColor& c00, + const RgbwColor& c01, + const RgbwColor& c10, + const RgbwColor& c11, + float x, + float y) +{ + float v00 = (1.0f - x) * (1.0f - y); + float v10 = x * (1.0f - y); + float v01 = (1.0f - x) * y; + float v11 = x * y; + + return RgbwColor( + c00.R * v00 + c10.R * v10 + c01.R * v01 + c11.R * v11, + c00.G * v00 + c10.G * v10 + c01.G * v01 + c11.G * v11, + c00.B * v00 + c10.B * v10 + c01.B * v01 + c11.B * v11, + c00.W * v00 + c10.W * v10 + c01.W * v01 + c11.W * v11 ); +} \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/RgbwColor.h b/lib/NeoPixelBus_by_Makuna/src/internal/RgbwColor.h new file mode 100644 index 0000000..73732b5 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/RgbwColor.h @@ -0,0 +1,229 @@ +/*------------------------------------------------------------------------- +RgbwColor provides a color object that can be directly consumed by NeoPixelBus + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +#include + +struct RgbColor; +struct HslColor; +struct HsbColor; + +// ------------------------------------------------------------------------ +// RgbwColor represents a color object that is represented by Red, Green, Blue +// component values and an extra White component. It contains helpful color +// routines to manipulate the color. +// ------------------------------------------------------------------------ +struct RgbwColor +{ + typedef NeoRgbwCurrentSettings SettingsObject; + + // ------------------------------------------------------------------------ + // Construct a RgbwColor using R, G, B, W values (0-255) + // ------------------------------------------------------------------------ + RgbwColor(uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0) : + R(r), G(g), B(b), W(w) + { + }; + + // ------------------------------------------------------------------------ + // Construct a RgbColor using a single brightness value (0-255) + // This works well for creating gray tone colors + // (0) = black, (255) = white, (128) = gray + // ------------------------------------------------------------------------ + RgbwColor(uint8_t brightness) : + R(0), G(0), B(0), W(brightness) + { + }; + + // ------------------------------------------------------------------------ + // Construct a RgbwColor using RgbColor + // ------------------------------------------------------------------------ + RgbwColor(const RgbColor& color) : + R(color.R), + G(color.G), + B(color.B), + W(0) + { + }; + + // ------------------------------------------------------------------------ + // Construct a RgbwColor using HtmlColor + // ------------------------------------------------------------------------ + RgbwColor(const HtmlColor& color); + + // ------------------------------------------------------------------------ + // Construct a RgbwColor using HslColor + // ------------------------------------------------------------------------ + RgbwColor(const HslColor& color); + + // ------------------------------------------------------------------------ + // Construct a RgbwColor using HsbColor + // ------------------------------------------------------------------------ + RgbwColor(const HsbColor& color); + + // ------------------------------------------------------------------------ + // Construct a RgbwColor that will have its values set in latter operations + // CAUTION: The R,G,B, W members are not initialized and may not be consistent + // ------------------------------------------------------------------------ + RgbwColor() + { + }; + + // ------------------------------------------------------------------------ + // Comparison operators + // ------------------------------------------------------------------------ + bool operator==(const RgbwColor& other) const + { + return (R == other.R && G == other.G && B == other.B && W == other.W); + }; + + bool operator!=(const RgbwColor& other) const + { + return !(*this == other); + }; + + // ------------------------------------------------------------------------ + // Returns if the color is grey, all values are equal other than white + // ------------------------------------------------------------------------ + bool IsMonotone() const + { + return (R == B && R == G); + }; + + // ------------------------------------------------------------------------ + // Returns if the color components are all zero, the white component maybe + // anything + // ------------------------------------------------------------------------ + bool IsColorLess() const + { + return (R == 0 && B == 0 && G == 0); + }; + + // ------------------------------------------------------------------------ + // CalculateBrightness will calculate the overall brightness + // NOTE: This is a simple linear brightness + // ------------------------------------------------------------------------ + uint8_t CalculateBrightness() const; + + // ------------------------------------------------------------------------ + // Dim will return a new color that is blended to black with the given ratio + // ratio - (0-255) where 255 will return the original color and 0 will return black + // + // NOTE: This is a simple linear blend + // ------------------------------------------------------------------------ + RgbwColor Dim(uint8_t ratio) const; + + // ------------------------------------------------------------------------ + // Brighten will return a new color that is blended to white with the given ratio + // ratio - (0-255) where 255 will return the original color and 0 will return white + // + // NOTE: This is a simple linear blend + // ------------------------------------------------------------------------ + RgbwColor Brighten(uint8_t ratio) const; + + // ------------------------------------------------------------------------ + // Darken will adjust the color by the given delta toward black + // NOTE: This is a simple linear change + // delta - (0-255) the amount to dim the color + // ------------------------------------------------------------------------ + void Darken(uint8_t delta); + + // ------------------------------------------------------------------------ + // Lighten will adjust the color by the given delta toward white + // NOTE: This is a simple linear change + // delta - (0-255) the amount to lighten the color + // ------------------------------------------------------------------------ + void Lighten(uint8_t delta); + + // ------------------------------------------------------------------------ + // LinearBlend between two colors by the amount defined by progress variable + // left - the color to start the blend at + // right - the color to end the blend at + // progress - (0.0 - 1.0) value where 0 will return left and 1.0 will return right + // and a value between will blend the color weighted linearly between them + // ------------------------------------------------------------------------ + static RgbwColor LinearBlend(const RgbwColor& left, const RgbwColor& right, float progress); + + // ------------------------------------------------------------------------ + // BilinearBlend between four colors by the amount defined by 2d variable + // c00 - upper left quadrant color + // c01 - upper right quadrant color + // c10 - lower left quadrant color + // c11 - lower right quadrant color + // x - unit value (0.0 - 1.0) that defines the blend progress in horizontal space + // y - unit value (0.0 - 1.0) that defines the blend progress in vertical space + // ------------------------------------------------------------------------ + static RgbwColor BilinearBlend(const RgbwColor& c00, + const RgbwColor& c01, + const RgbwColor& c10, + const RgbwColor& c11, + float x, + float y); + + uint16_t CalcTotalTenthMilliAmpere(const SettingsObject& settings) + { + auto total = 0; + + total += R * settings.RedTenthMilliAmpere / 255; + total += G * settings.GreenTenthMilliAmpere / 255; + total += B * settings.BlueTenthMilliAmpere / 255; + total += W * settings.WhiteCurrent / 255; + + return total; + } + + // ------------------------------------------------------------------------ + // Red, Green, Blue, White color members (0-255) where + // (0,0,0,0) is black and (255,255,255, 0) and (0,0,0,255) is white + // Note (255,255,255,255) is extreme bright white + // ------------------------------------------------------------------------ + uint8_t R; + uint8_t G; + uint8_t B; + uint8_t W; + +private: + inline static uint8_t _elementDim(uint8_t value, uint8_t ratio) + { + return (static_cast(value) * (static_cast(ratio) + 1)) >> 8; + } + + inline static uint8_t _elementBrighten(uint8_t value, uint8_t ratio) + { + uint16_t element = ((static_cast(value) + 1) << 8) / (static_cast(ratio) + 1); + + if (element > 255) + { + element = 255; + } + else + { + element -= 1; + } + return element; + } +}; + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/SegmentDigit.cpp b/lib/NeoPixelBus_by_Makuna/src/internal/SegmentDigit.cpp new file mode 100644 index 0000000..9149597 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/SegmentDigit.cpp @@ -0,0 +1,153 @@ +/*------------------------------------------------------------------------- +SegmentDigit provides a color object that can be directly consumed by NeoPixelBus + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#include "SegmentDigit.h" + +// +// https://en.wikichip.org/wiki/seven-segment_display/representing_letters +// +const uint8_t SevenSegDigit::DecodeNumbers[] = { + // 0 1 2 3 4 5 6 7 8 9 + 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F }; + +const uint8_t SevenSegDigit::DecodeAlphaCaps[] = { + // A B C D E F G + 0x77, 0x00, 0x39, 0x00, 0x79, 0x71, 0x3D, + // H I J K L M N + 0x76, 0x30, 0x1E, 0x00, 0x38, 0x00, 0x00, + // O P Q R S + 0x3F, 0x73, 0x00, 0x00, 0x6D, + // T U V W X Y Z + 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +const uint8_t SevenSegDigit::DecodeAlpha[] = { + // a b c d e f g + 0x00, 0x7C, 0x58, 0x5E, 0x00, 0x00, 0x00, + // h i j k l m n + 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, + // o p q r s + 0x5C, 0x00, 0x67, 0x50, 0x00, + // t u v w x y z + 0x78, 0x1C, 0x00, 0x00, 0x00, 0x6E, 0x00 }; + +const uint8_t SevenSegDigit::DecodeSpecial[] = { + // , - . / + 0x80, 0x40, 0x80, 0x40 }; + +void SevenSegDigit::init(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness) +{ + for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++) + { + Segment[iSegment] = (bitmask & 0x01) ? brightness : defaultBrightness; + bitmask >>= 1; + } +} + +SevenSegDigit::SevenSegDigit(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness) +{ + init(bitmask, brightness, defaultBrightness); +}; + +SevenSegDigit::SevenSegDigit(char letter, uint8_t brightness, uint8_t defaultBrightness) +{ + if (letter >= '0' && letter <= '9') + { + init(DecodeNumbers[letter - '0'], brightness, defaultBrightness); + } + else if (letter >= 'a' && letter <= 'z') + { + init(DecodeAlpha[letter - 'a'], brightness, defaultBrightness); + } + else if (letter >= 'A' && letter <= 'Z') + { + init(DecodeAlphaCaps[letter - 'A'], brightness, defaultBrightness); + } + else if (letter >= ',' && letter <= '/') + { + init(DecodeSpecial[letter - ','], brightness, defaultBrightness); + } + else + { + memset(Segment, defaultBrightness, sizeof(Segment)); + } +}; + +uint8_t SevenSegDigit::CalculateBrightness() const +{ + uint16_t sum = 0; + + for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++) + { + sum += Segment[iSegment]; + } + + return (uint8_t)(sum / SegmentCount); +} + +void SevenSegDigit::Darken(uint8_t delta) +{ + for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++) + { + uint8_t element = Segment[iSegment]; + if (element > delta) + { + element -= delta; + } + else + { + element = 0; + } + Segment[iSegment] = element; + } +} + +void SevenSegDigit::Lighten(uint8_t delta) +{ + for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++) + { + uint8_t element = Segment[iSegment]; + if (element < 255 - delta) + { + element += delta; + } + else + { + element = 255; + } + Segment[iSegment] = element; + } +} + +SevenSegDigit SevenSegDigit::LinearBlend(const SevenSegDigit& left, const SevenSegDigit& right, float progress) +{ + SevenSegDigit result; + + for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++) + { + result.Segment[iSegment] = left.Segment[iSegment] + ((right.Segment[iSegment] - left.Segment[iSegment]) * progress); + } + return result; +} diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/SegmentDigit.h b/lib/NeoPixelBus_by_Makuna/src/internal/SegmentDigit.h new file mode 100644 index 0000000..826044c --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/SegmentDigit.h @@ -0,0 +1,202 @@ +/*------------------------------------------------------------------------- +SegmentDigit provides a color object that can be directly consumed by NeoPixelBus + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ +#pragma once + +#include + +enum LedSegment +{ + LedSegment_A, + LedSegment_B, + LedSegment_C, + LedSegment_D, + LedSegment_E, + LedSegment_F, + LedSegment_G, + LedSegment_Decimal, + LedSegment_COUNT +}; + +// ------------------------------------------------------------------------ +// SevenSegDigit represents a color object that is represented by the segments +// of a 7 segment LED display digit. It contains helpful routines to manipulate +// and set the elements. +// +// The order represents the physical LED location starting at A, through to G, then +// ending at the decimal point +// "abcdefg." +// ------------------------------------------------------------------------ +struct SevenSegDigit +{ + // ------------------------------------------------------------------------ + // Construct a SevenSegDigit using + // the default brightness to apply to all segments + // ------------------------------------------------------------------------ + SevenSegDigit(uint8_t defaultBrightness) + { + memset(Segment, defaultBrightness, sizeof(Segment)); + } + + // ------------------------------------------------------------------------ + // Construct a SevenSegDigit using + // a bitmask for the segment (bit order is ".gfedcba") + // the brightness to apply to them, (0-255) + // the default brightness to apply to those not set in the bitmask (0-255) + // ------------------------------------------------------------------------ + SevenSegDigit(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness = 0); + + // ------------------------------------------------------------------------ + // Construct a SevenSegDigit using + // a char that will get mapped to the segments, + // the brightness to apply to them, (0-255) + // the default brightness to apply to those not set in the bitmask (0-255) + // ------------------------------------------------------------------------ + SevenSegDigit(char letter, uint8_t brightness, uint8_t defaultBrightness = 0); + + // ------------------------------------------------------------------------ + // Construct a SevenSegDigit that will have its values set in latter operations + // CAUTION: The members are not initialized and may not be consistent + // ------------------------------------------------------------------------ + SevenSegDigit() + { + }; + + // ------------------------------------------------------------------------ + // Comparison operators + // ------------------------------------------------------------------------ + bool operator==(const SevenSegDigit& other) const + { + for (uint8_t iSegment = 0; iSegment < SegmentCount; iSegment++) + { + if (Segment[iSegment] != other.Segment[iSegment]) + { + return false; + } + } + return true; + }; + + bool operator!=(const SevenSegDigit& other) const + { + return !(*this == other); + }; + + // ------------------------------------------------------------------------ + // CalculateBrightness will calculate the overall brightness + // NOTE: This is a simple linear brightness + // ------------------------------------------------------------------------ + uint8_t CalculateBrightness() const; + + // ------------------------------------------------------------------------ + // Darken will adjust the color by the given delta toward black + // NOTE: This is a simple linear change + // delta - (0-255) the amount to dim the segment + // ------------------------------------------------------------------------ + void Darken(uint8_t delta); + + // ------------------------------------------------------------------------ + // Lighten will adjust the color by the given delta toward white + // NOTE: This is a simple linear change + // delta - (0-255) the amount to lighten the segment + // ------------------------------------------------------------------------ + void Lighten(uint8_t delta); + + // ------------------------------------------------------------------------ + // LinearBlend between two colors by the amount defined by progress variable + // left - the segment to start the blend at + // right - the segment to end the blend at + // progress - (0.0 - 1.0) value where 0 will return left and 1.0 will return right + // and a value between will blend the brightness of each element + // weighted linearly between them + // ------------------------------------------------------------------------ + static SevenSegDigit LinearBlend(const SevenSegDigit& left, const SevenSegDigit& right, float progress); + + template + static void SetString(T_SET_TARGET& target, uint16_t indexDigit, const char* str, uint8_t brightness, uint8_t defaultBrightness = 0) + { + if (str == nullptr) + { + return; + } + + const char* pFirst = str; + const char* pIter = str; + + // digits are right to left + // so find the end + while (*pIter != '\0') + { + pIter++; + } + pIter--; + + + while (pIter >= pFirst) + { + bool decimal = false; + char value = *pIter; + + // check if merging a decimal is required + if (pIter > pFirst && (*pIter == '.' || *pIter == ',')) + { + // merge a decimal as long as they aren't the same + if (*(pIter - 1) != *pIter) + { + decimal = true; + pIter--; + value = *pIter; // use the next char + } + } + + SevenSegDigit digit(value, brightness, defaultBrightness); + if (decimal) + { + digit.Segment[LedSegment_Decimal] = brightness; + } + target.SetPixelColor(indexDigit, digit); + indexDigit++; + } + } + + // ------------------------------------------------------------------------ + // segment members (0-255) where each represents the segment location + // and the value defines the brightnes (0) is off and (255) is full brightness + // ------------------------------------------------------------------------ + static const uint8_t SegmentCount = 9; + uint8_t Segment[SegmentCount]; + + + // segment decode maps from ascii relative first char in map to a bitmask of segments + // + static const uint8_t DecodeNumbers[10]; // 0-9 + static const uint8_t DecodeAlphaCaps[26]; // A-Z + static const uint8_t DecodeAlpha[26]; // a-z + static const uint8_t DecodeSpecial[4]; // , - . / + +protected: + void init(uint8_t bitmask, uint8_t brightness, uint8_t defaultBrightness); +}; + diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/TwoWireBitBangImple.h b/lib/NeoPixelBus_by_Makuna/src/internal/TwoWireBitBangImple.h new file mode 100644 index 0000000..4a784ae --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/TwoWireBitBangImple.h @@ -0,0 +1,92 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for DotStars using general Pins (APA102/LPD8806). + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + + +class TwoWireBitBangImple +{ +public: + TwoWireBitBangImple(uint8_t pinClock, uint8_t pinData) : + _pinClock(pinClock), + _pinData(pinData) + { + pinMode(pinClock, OUTPUT); + pinMode(pinData, OUTPUT); + } + + ~TwoWireBitBangImple() + { + pinMode(_pinClock, INPUT); + pinMode(_pinData, INPUT); + } + + void begin() + { + digitalWrite(_pinClock, LOW); + digitalWrite(_pinData, LOW); + } + + void beginTransaction() + { + + } + + void endTransaction() + { + digitalWrite(_pinData, LOW); + } + + void transmitByte(uint8_t data) + { + for (int bit = 7; bit >= 0; bit--) + { + // set data bit on pin + digitalWrite(_pinData, (data & 0x80) == 0x80 ? HIGH : LOW); + + // set clock high as data is ready + digitalWrite(_pinClock, HIGH); + + data <<= 1; + + // set clock low as data pin is changed + digitalWrite(_pinClock, LOW); + } + } + + void transmitBytes(const uint8_t* data, size_t dataSize) + { + const uint8_t* endData = data + dataSize; + while (data < endData) + { + transmitByte(*data++); + } + } + +private: + const uint8_t _pinClock; // output pin number for clock line + const uint8_t _pinData; // output pin number for data line +}; \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/TwoWireBitBangImpleAvr.h b/lib/NeoPixelBus_by_Makuna/src/internal/TwoWireBitBangImpleAvr.h new file mode 100644 index 0000000..8c0be74 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/TwoWireBitBangImpleAvr.h @@ -0,0 +1,112 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for DotStars using general Pins (APA102/LPD8806). + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + + +class TwoWireBitBangImple +{ +public: + TwoWireBitBangImple(uint8_t pinClock, uint8_t pinData) : + _pinClock(pinClock), + _pinData(pinData) + { + pinMode(pinClock, OUTPUT); + pinMode(pinData, OUTPUT); + + _portClock = portOutputRegister(digitalPinToPort(_pinClock)); + _pinMaskClock = digitalPinToBitMask(_pinClock); + _portData = portOutputRegister(digitalPinToPort(_pinData)); + _pinMaskData = digitalPinToBitMask(_pinData); + } + + ~TwoWireBitBangImple() + { + pinMode(_pinClock, INPUT); + pinMode(_pinData, INPUT); + } + + void begin() + { + digitalWrite(_pinClock, LOW); + digitalWrite(_pinData, LOW); + } + + void beginTransaction() + { + + } + + void endTransaction() + { + digitalWrite(_pinData, LOW); + } + + void transmitByte(uint8_t data) + { + for (int bit = 7; bit >= 0; bit--) + { + // set data bit on pin + // digitalWrite(_pinData, (data & 0x80) == 0x80 ? HIGH : LOW); + if (data & 0x80) + { + *_portData |= _pinMaskData; + } + else + { + *_portData &= ~_pinMaskData; + } + + // set clock high as data is ready + // digitalWrite(_pinClock, HIGH); + *_portClock |= _pinMaskClock; + + data <<= 1; + + // set clock low as data pin is changed + // digitalWrite(_pinClock, LOW); + *_portClock &= ~_pinMaskClock; + } + } + + void transmitBytes(const uint8_t* data, size_t dataSize) + { + const uint8_t* endData = data + dataSize; + while (data < endData) + { + transmitByte(*data++); + } + } + +private: + const uint8_t _pinClock; // output pin number for clock line + const uint8_t _pinData; // output pin number for data line + + volatile uint8_t* _portData; // Output PORT register + uint8_t _pinMaskData; // Output PORT bitmask + volatile uint8_t* _portClock; // Output PORT register + uint8_t _pinMaskClock; // Output PORT bitmask +}; \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/TwoWireSpiImple.h b/lib/NeoPixelBus_by_Makuna/src/internal/TwoWireSpiImple.h new file mode 100644 index 0000000..9838f7b --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/TwoWireSpiImple.h @@ -0,0 +1,115 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for DotStars using general Pins (APA102/LPD8806). + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#include + +class SpiSpeed40Mhz +{ +public: + static const uint32_t Clock = 40000000L; +}; + +class SpiSpeed20Mhz +{ +public: + static const uint32_t Clock = 20000000L; +}; + +class SpiSpeed10Mhz +{ +public: + static const uint32_t Clock = 10000000L; +}; + +class SpiSpeed2Mhz +{ +public: + static const uint32_t Clock = 2000000L; +}; + +template class TwoWireSpiImple +{ +public: + TwoWireSpiImple(uint8_t, uint8_t) // clock and data pins ignored for hardware SPI + { + } + + ~TwoWireSpiImple() + { + SPI.end(); + } + +#if defined(ARDUINO_ARCH_ESP32) + // for cases where hardware SPI can have pins changed + void begin(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) + { + SPI.begin(sck, miso, mosi, ss); + } +#endif + + void begin() + { + SPI.begin(); + } + + void beginTransaction() + { + SPI.beginTransaction(SPISettings(T_SPISPEED::Clock, MSBFIRST, SPI_MODE0)); + } + + void endTransaction() + { + SPI.endTransaction(); + } + + void transmitByte(uint8_t data) + { + SPI.transfer(data); + } + + void transmitBytes(const uint8_t* data, size_t dataSize) + { +#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) + // ESPs have a method to write without inplace overwriting the send buffer + // since we don't care what gets received, use it for performance + // FIX: but for what ever reason on Esp32, its not const + SPI.writeBytes(const_cast(data), dataSize); + +#else + // default ARDUINO transfer inplace overwrites the send buffer + // which is bad in this case, so we have to send one byte at a time + const uint8_t* endData = data + dataSize; + while (data < endData) + { + SPI.transfer(*data++); + } +#endif + } + +private: +}; \ No newline at end of file diff --git a/lib/NeoPixelBus_by_Makuna/src/internal/Ws2801GenericMethod.h b/lib/NeoPixelBus_by_Makuna/src/internal/Ws2801GenericMethod.h new file mode 100644 index 0000000..0127108 --- /dev/null +++ b/lib/NeoPixelBus_by_Makuna/src/internal/Ws2801GenericMethod.h @@ -0,0 +1,130 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for WS2801 + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus 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 Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +// must also check for arm due to Teensy incorrectly having ARDUINO_ARCH_AVR set +#if defined(ARDUINO_ARCH_AVR) && !defined(__arm__) +#include "TwoWireBitBangImpleAvr.h" +#else +#include "TwoWireBitBangImple.h" +#endif + + +template class Ws2801MethodBase +{ +public: + Ws2801MethodBase(uint8_t pinClock, uint8_t pinData, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + _wire(pinClock, pinData) + { + _data = static_cast(malloc(_sizeData)); + memset(_data, 0, _sizeData); + } + +#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny) + Ws2801MethodBase(uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + Ws2801MethodBase(SCK, MOSI, pixelCount, elementSize, settingsSize) + { + } +#endif + + ~Ws2801MethodBase() + { + free(_data); + } + + bool IsReadyToUpdate() const + { + uint32_t delta = micros() - _endTime; + + return (delta >= 500); + } + +#if defined(ARDUINO_ARCH_ESP32) + void Initialize(int8_t sck, int8_t miso, int8_t mosi, int8_t ss) + { + _wire.begin(sck, miso, mosi, ss); + } +#endif + + void Initialize() + { + _wire.begin(); + + _endTime = micros(); + } + + void Update(bool) + { + while (!IsReadyToUpdate()) + { +#if !defined(ARDUINO_TEEONARDU_LEO) && !defined(ARDUINO_TEEONARDU_FLORA) + yield(); // allows for system yield if needed +#endif + } + + _wire.beginTransaction(); + + // data + _wire.transmitBytes(_data, _sizeData); + + _wire.endTransaction(); + + // save EOD time for latch on next call + _endTime = micros(); + } + + uint8_t* getData() const + { + return _data; + }; + + size_t getDataSize() const + { + return _sizeData; + }; + +private: + const size_t _sizeData; // Size of '_data' buffer below + + uint32_t _endTime; // Latch timing reference + T_TWOWIRE _wire; + uint8_t* _data; // Holds LED color values +}; + +typedef Ws2801MethodBase NeoWs2801Method; + +#if !defined(__AVR_ATtiny85__) && !defined(ARDUINO_attiny) +#include "TwoWireSpiImple.h" +typedef Ws2801MethodBase> NeoWs2801Spi20MhzMethod; +typedef Ws2801MethodBase> NeoWs2801Spi10MhzMethod; +typedef Ws2801MethodBase> NeoWs2801Spi2MhzMethod; +typedef NeoWs2801Spi10MhzMethod NeoWs2801SpiMethod; +#endif + + + diff --git a/lib/OneWire/OneWire.cpp b/lib/OneWire/OneWire.cpp new file mode 100644 index 0000000..38bf4ee --- /dev/null +++ b/lib/OneWire/OneWire.cpp @@ -0,0 +1,580 @@ +/* +Copyright (c) 2007, Jim Studt (original old version - many contributors since) + +The latest version of this library may be found at: + http://www.pjrc.com/teensy/td_libs_OneWire.html + +OneWire has been maintained by Paul Stoffregen (paul@pjrc.com) since +January 2010. + +DO NOT EMAIL for technical support, especially not for ESP chips! +All project support questions must be posted on public forums +relevant to the board or chips used. If using Arduino, post on +Arduino's forum. If using ESP, post on the ESP community forums. +There is ABSOLUTELY NO TECH SUPPORT BY PRIVATE EMAIL! + +Github's issue tracker for OneWire should be used only to report +specific bugs. DO NOT request project support via Github. All +project and tech support questions must be posted on forums, not +github issues. If you experience a problem and you are not +absolutely sure it's an issue with the library, ask on a forum +first. Only use github to report issues after experts have +confirmed the issue is with OneWire rather than your project. + +Back in 2010, OneWire was in need of many bug fixes, but had +been abandoned the original author (Jim Studt). None of the known +contributors were interested in maintaining OneWire. Paul typically +works on OneWire every 6 to 12 months. Patches usually wait that +long. If anyone is interested in more actively maintaining OneWire, +please contact Paul (this is pretty much the only reason to use +private email about OneWire). + +OneWire is now very mature code. No changes other than adding +definitions for newer hardware support are anticipated. + +Version 2.3: + Unknown chip fallback mode, Roger Clark + Teensy-LC compatibility, Paul Stoffregen + Search bug fix, Love Nystrom + +Version 2.2: + Teensy 3.0 compatibility, Paul Stoffregen, paul@pjrc.com + Arduino Due compatibility, http://arduino.cc/forum/index.php?topic=141030 + Fix DS18B20 example negative temperature + Fix DS18B20 example's low res modes, Ken Butcher + Improve reset timing, Mark Tillotson + Add const qualifiers, Bertrik Sikken + Add initial value input to crc16, Bertrik Sikken + Add target_search() function, Scott Roberts + +Version 2.1: + Arduino 1.0 compatibility, Paul Stoffregen + Improve temperature example, Paul Stoffregen + DS250x_PROM example, Guillermo Lovato + PIC32 (chipKit) compatibility, Jason Dangel, dangel.jason AT gmail.com + Improvements from Glenn Trewitt: + - crc16() now works + - check_crc16() does all of calculation/checking work. + - Added read_bytes() and write_bytes(), to reduce tedious loops. + - Added ds2408 example. + Delete very old, out-of-date readme file (info is here) + +Version 2.0: Modifications by Paul Stoffregen, January 2010: +http://www.pjrc.com/teensy/td_libs_OneWire.html + Search fix from Robin James + http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27 + Use direct optimized I/O in all cases + Disable interrupts during timing critical sections + (this solves many random communication errors) + Disable interrupts during read-modify-write I/O + Reduce RAM consumption by eliminating unnecessary + variables and trimming many to 8 bits + Optimize both crc8 - table version moved to flash + +Modified to work with larger numbers of devices - avoids loop. +Tested in Arduino 11 alpha with 12 sensors. +26 Sept 2008 -- Robin James +http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1238032295/27#27 + +Updated to work with arduino-0008 and to include skip() as of +2007/07/06. --RJL20 + +Modified to calculate the 8-bit CRC directly, avoiding the need for +the 256-byte lookup table to be loaded in RAM. Tested in arduino-0010 +-- Tom Pollard, Jan 23, 2008 + +Jim Studt's original library was modified by Josh Larios. + +Tom Pollard, pollard@alum.mit.edu, contributed around May 20, 2008 + +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. + +Much of the code was inspired by Derek Yerger's code, though I don't +think much of that remains. In any event that was.. + (copyleft) 2006 by Derek Yerger - Free to distribute freely. + +The CRC code was excerpted and inspired by the Dallas Semiconductor +sample code bearing this copyright. +//--------------------------------------------------------------------------- +// Copyright (C) 2000 Dallas Semiconductor Corporation, All Rights Reserved. +// +// 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 DALLAS SEMICONDUCTOR 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. +// +// Except as contained in this notice, the name of Dallas Semiconductor +// shall not be used except as stated in the Dallas Semiconductor +// Branding Policy. +//-------------------------------------------------------------------------- +*/ + +#include +#include "OneWire.h" +#include "util/OneWire_direct_gpio.h" + + +void OneWire::begin(uint8_t pin) +{ + pinMode(pin, INPUT); + bitmask = PIN_TO_BITMASK(pin); + baseReg = PIN_TO_BASEREG(pin); +#if ONEWIRE_SEARCH + reset_search(); +#endif +} + + +// Perform the onewire reset function. We will wait up to 250uS for +// the bus to come high, if it doesn't then it is broken or shorted +// and we return a 0; +// +// Returns 1 if a device asserted a presence pulse, 0 otherwise. +// +uint8_t OneWire::reset(void) +{ + IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask; + volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg; + uint8_t r; + uint8_t retries = 125; + + noInterrupts(); + DIRECT_MODE_INPUT(reg, mask); + interrupts(); + // wait until the wire is high... just in case + do { + if (--retries == 0) return 0; + delayMicroseconds(2); + } while ( !DIRECT_READ(reg, mask)); + + noInterrupts(); + DIRECT_WRITE_LOW(reg, mask); + DIRECT_MODE_OUTPUT(reg, mask); // drive output low + interrupts(); + delayMicroseconds(480); + noInterrupts(); + DIRECT_MODE_INPUT(reg, mask); // allow it to float + delayMicroseconds(70); + r = !DIRECT_READ(reg, mask); + interrupts(); + delayMicroseconds(410); + return r; +} + +// +// Write a bit. Port and bit is used to cut lookup time and provide +// more certain timing. +// +void OneWire::write_bit(uint8_t v) +{ + IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask; + volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg; + + if (v & 1) { + noInterrupts(); + DIRECT_WRITE_LOW(reg, mask); + DIRECT_MODE_OUTPUT(reg, mask); // drive output low + delayMicroseconds(10); + DIRECT_WRITE_HIGH(reg, mask); // drive output high + interrupts(); + delayMicroseconds(55); + } else { + noInterrupts(); + DIRECT_WRITE_LOW(reg, mask); + DIRECT_MODE_OUTPUT(reg, mask); // drive output low + delayMicroseconds(65); + DIRECT_WRITE_HIGH(reg, mask); // drive output high + interrupts(); + delayMicroseconds(5); + } +} + +// +// Read a bit. Port and bit is used to cut lookup time and provide +// more certain timing. +// +uint8_t OneWire::read_bit(void) +{ + IO_REG_TYPE mask IO_REG_MASK_ATTR = bitmask; + volatile IO_REG_TYPE *reg IO_REG_BASE_ATTR = baseReg; + uint8_t r; + + noInterrupts(); + DIRECT_MODE_OUTPUT(reg, mask); + DIRECT_WRITE_LOW(reg, mask); + delayMicroseconds(3); + DIRECT_MODE_INPUT(reg, mask); // let pin float, pull up will raise + delayMicroseconds(10); + r = DIRECT_READ(reg, mask); + interrupts(); + delayMicroseconds(53); + return r; +} + +// +// Write a byte. The writing code uses the active drivers to raise the +// pin high, if you need power after the write (e.g. DS18S20 in +// parasite power mode) then set 'power' to 1, otherwise the pin will +// go tri-state at the end of the write to avoid heating in a short or +// other mishap. +// +void OneWire::write(uint8_t v, uint8_t power /* = 0 */) { + uint8_t bitMask; + + for (bitMask = 0x01; bitMask; bitMask <<= 1) { + OneWire::write_bit( (bitMask & v)?1:0); + } + if ( !power) { + noInterrupts(); + DIRECT_MODE_INPUT(baseReg, bitmask); + DIRECT_WRITE_LOW(baseReg, bitmask); + interrupts(); + } +} + +void OneWire::write_bytes(const uint8_t *buf, uint16_t count, bool power /* = 0 */) { + for (uint16_t i = 0 ; i < count ; i++) + write(buf[i]); + if (!power) { + noInterrupts(); + DIRECT_MODE_INPUT(baseReg, bitmask); + DIRECT_WRITE_LOW(baseReg, bitmask); + interrupts(); + } +} + +// +// Read a byte +// +uint8_t OneWire::read() { + uint8_t bitMask; + uint8_t r = 0; + + for (bitMask = 0x01; bitMask; bitMask <<= 1) { + if ( OneWire::read_bit()) r |= bitMask; + } + return r; +} + +void OneWire::read_bytes(uint8_t *buf, uint16_t count) { + for (uint16_t i = 0 ; i < count ; i++) + buf[i] = read(); +} + +// +// Do a ROM select +// +void OneWire::select(const uint8_t rom[8]) +{ + uint8_t i; + + write(0x55); // Choose ROM + + for (i = 0; i < 8; i++) write(rom[i]); +} + +// +// Do a ROM skip +// +void OneWire::skip() +{ + write(0xCC); // Skip ROM +} + +void OneWire::depower() +{ + noInterrupts(); + DIRECT_MODE_INPUT(baseReg, bitmask); + interrupts(); +} + +#if ONEWIRE_SEARCH + +// +// You need to use this function to start a search again from the beginning. +// You do not need to do it for the first search, though you could. +// +void OneWire::reset_search() +{ + // reset the search state + LastDiscrepancy = 0; + LastDeviceFlag = false; + LastFamilyDiscrepancy = 0; + for(int i = 7; ; i--) { + ROM_NO[i] = 0; + if ( i == 0) break; + } +} + +// Setup the search to find the device type 'family_code' on the next call +// to search(*newAddr) if it is present. +// +void OneWire::target_search(uint8_t family_code) +{ + // set the search state to find SearchFamily type devices + ROM_NO[0] = family_code; + for (uint8_t i = 1; i < 8; i++) + ROM_NO[i] = 0; + LastDiscrepancy = 64; + LastFamilyDiscrepancy = 0; + LastDeviceFlag = false; +} + +// +// Perform a search. If this function returns a '1' then it has +// enumerated the next device and you may retrieve the ROM from the +// OneWire::address variable. If there are no devices, no further +// devices, or something horrible happens in the middle of the +// enumeration then a 0 is returned. If a new device is found then +// its address is copied to newAddr. Use OneWire::reset_search() to +// start over. +// +// --- Replaced by the one from the Dallas Semiconductor web site --- +//-------------------------------------------------------------------------- +// Perform the 1-Wire Search Algorithm on the 1-Wire bus using the existing +// search state. +// Return TRUE : device found, ROM number in ROM_NO buffer +// FALSE : device not found, end of search +// +bool OneWire::search(uint8_t *newAddr, bool search_mode /* = true */) +{ + uint8_t id_bit_number; + uint8_t last_zero, rom_byte_number; + bool search_result; + uint8_t id_bit, cmp_id_bit; + + unsigned char rom_byte_mask, search_direction; + + // initialize for search + id_bit_number = 1; + last_zero = 0; + rom_byte_number = 0; + rom_byte_mask = 1; + search_result = false; + + // if the last call was not the last one + if (!LastDeviceFlag) { + // 1-Wire reset + if (!reset()) { + // reset the search + LastDiscrepancy = 0; + LastDeviceFlag = false; + LastFamilyDiscrepancy = 0; + return false; + } + + // issue the search command + if (search_mode == true) { + write(0xF0); // NORMAL SEARCH + } else { + write(0xEC); // CONDITIONAL SEARCH + } + + // loop to do the search + do + { + // read a bit and its complement + id_bit = read_bit(); + cmp_id_bit = read_bit(); + + // check for no devices on 1-wire + if ((id_bit == 1) && (cmp_id_bit == 1)) { + break; + } else { + // all devices coupled have 0 or 1 + if (id_bit != cmp_id_bit) { + search_direction = id_bit; // bit write value for search + } else { + // if this discrepancy if before the Last Discrepancy + // on a previous next then pick the same as last time + if (id_bit_number < LastDiscrepancy) { + search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0); + } else { + // if equal to last pick 1, if not then pick 0 + search_direction = (id_bit_number == LastDiscrepancy); + } + // if 0 was picked then record its position in LastZero + if (search_direction == 0) { + last_zero = id_bit_number; + + // check for Last discrepancy in family + if (last_zero < 9) + LastFamilyDiscrepancy = last_zero; + } + } + + // set or clear the bit in the ROM byte rom_byte_number + // with mask rom_byte_mask + if (search_direction == 1) + ROM_NO[rom_byte_number] |= rom_byte_mask; + else + ROM_NO[rom_byte_number] &= ~rom_byte_mask; + + // serial number search direction write bit + write_bit(search_direction); + + // increment the byte counter id_bit_number + // and shift the mask rom_byte_mask + id_bit_number++; + rom_byte_mask <<= 1; + + // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask + if (rom_byte_mask == 0) { + rom_byte_number++; + rom_byte_mask = 1; + } + } + } + while(rom_byte_number < 8); // loop until through all ROM bytes 0-7 + + // if the search was successful then + if (!(id_bit_number < 65)) { + // search successful so set LastDiscrepancy,LastDeviceFlag,search_result + LastDiscrepancy = last_zero; + + // check for last device + if (LastDiscrepancy == 0) { + LastDeviceFlag = true; + } + search_result = true; + } + } + + // if no device found then reset counters so next 'search' will be like a first + if (!search_result || !ROM_NO[0]) { + LastDiscrepancy = 0; + LastDeviceFlag = false; + LastFamilyDiscrepancy = 0; + search_result = false; + } else { + for (int i = 0; i < 8; i++) newAddr[i] = ROM_NO[i]; + } + return search_result; + } + +#endif + +#if ONEWIRE_CRC +// The 1-Wire CRC scheme is described in Maxim Application Note 27: +// "Understanding and Using Cyclic Redundancy Checks with Maxim iButton Products" +// + +#if ONEWIRE_CRC8_TABLE +// Dow-CRC using polynomial X^8 + X^5 + X^4 + X^0 +// Tiny 2x16 entry CRC table created by Arjen Lentz +// See http://lentz.com.au/blog/calculating-crc-with-a-tiny-32-entry-lookup-table +static const uint8_t PROGMEM dscrc2x16_table[] = { + 0x00, 0x5E, 0xBC, 0xE2, 0x61, 0x3F, 0xDD, 0x83, + 0xC2, 0x9C, 0x7E, 0x20, 0xA3, 0xFD, 0x1F, 0x41, + 0x00, 0x9D, 0x23, 0xBE, 0x46, 0xDB, 0x65, 0xF8, + 0x8C, 0x11, 0xAF, 0x32, 0xCA, 0x57, 0xE9, 0x74 +}; + +// Compute a Dallas Semiconductor 8 bit CRC. These show up in the ROM +// and the registers. (Use tiny 2x16 entry CRC table) +uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len) +{ + uint8_t crc = 0; + + while (len--) { + crc = *addr++ ^ crc; // just re-using crc as intermediate + crc = pgm_read_byte(dscrc2x16_table + (crc & 0x0f)) ^ + pgm_read_byte(dscrc2x16_table + 16 + ((crc >> 4) & 0x0f)); + } + + return crc; +} +#else +// +// Compute a Dallas Semiconductor 8 bit CRC directly. +// this is much slower, but a little smaller, than the lookup table. +// +uint8_t OneWire::crc8(const uint8_t *addr, uint8_t len) +{ + uint8_t crc = 0; + + while (len--) { +#if defined(__AVR__) + crc = _crc_ibutton_update(crc, *addr++); +#else + uint8_t inbyte = *addr++; + for (uint8_t i = 8; i; i--) { + uint8_t mix = (crc ^ inbyte) & 0x01; + crc >>= 1; + if (mix) crc ^= 0x8C; + inbyte >>= 1; + } +#endif + } + return crc; +} +#endif + +#if ONEWIRE_CRC16 +bool OneWire::check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc) +{ + crc = ~crc16(input, len, crc); + return (crc & 0xFF) == inverted_crc[0] && (crc >> 8) == inverted_crc[1]; +} + +uint16_t OneWire::crc16(const uint8_t* input, uint16_t len, uint16_t crc) +{ +#if defined(__AVR__) + for (uint16_t i = 0 ; i < len ; i++) { + crc = _crc16_update(crc, input[i]); + } +#else + static const uint8_t oddparity[16] = + { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; + + for (uint16_t i = 0 ; i < len ; i++) { + // Even though we're just copying a byte from the input, + // we'll be doing 16-bit computation with it. + uint16_t cdata = input[i]; + cdata = (cdata ^ crc) & 0xff; + crc >>= 8; + + if (oddparity[cdata & 0x0F] ^ oddparity[cdata >> 4]) + crc ^= 0xC001; + + cdata <<= 6; + crc ^= cdata; + cdata <<= 1; + crc ^= cdata; + } +#endif + return crc; +} +#endif + +#endif diff --git a/lib/OneWire/OneWire.h b/lib/OneWire/OneWire.h new file mode 100644 index 0000000..a7bfab7 --- /dev/null +++ b/lib/OneWire/OneWire.h @@ -0,0 +1,182 @@ +#ifndef OneWire_h +#define OneWire_h + +#ifdef __cplusplus + +#include + +#if defined(__AVR__) +#include +#endif + +#if ARDUINO >= 100 +#include // for delayMicroseconds, digitalPinToBitMask, etc +#else +#include "WProgram.h" // for delayMicroseconds +#include "pins_arduino.h" // for digitalPinToBitMask, etc +#endif + +// You can exclude certain features from OneWire. In theory, this +// might save some space. In practice, the compiler automatically +// removes unused code (technically, the linker, using -fdata-sections +// and -ffunction-sections when compiling, and Wl,--gc-sections +// when linking), so most of these will not result in any code size +// reduction. Well, unless you try to use the missing features +// and redesign your program to not need them! ONEWIRE_CRC8_TABLE +// is the exception, because it selects a fast but large algorithm +// or a small but slow algorithm. + +// you can exclude onewire_search by defining that to 0 +#ifndef ONEWIRE_SEARCH +#define ONEWIRE_SEARCH 1 +#endif + +// You can exclude CRC checks altogether by defining this to 0 +#ifndef ONEWIRE_CRC +#define ONEWIRE_CRC 1 +#endif + +// Select the table-lookup method of computing the 8-bit CRC +// by setting this to 1. The lookup table enlarges code size by +// about 250 bytes. It does NOT consume RAM (but did in very +// old versions of OneWire). If you disable this, a slower +// but very compact algorithm is used. +#ifndef ONEWIRE_CRC8_TABLE +#define ONEWIRE_CRC8_TABLE 1 +#endif + +// You can allow 16-bit CRC checks by defining this to 1 +// (Note that ONEWIRE_CRC must also be 1.) +#ifndef ONEWIRE_CRC16 +#define ONEWIRE_CRC16 1 +#endif + +// Board-specific macros for direct GPIO +#include "util/OneWire_direct_regtype.h" + +class OneWire +{ + private: + IO_REG_TYPE bitmask; + volatile IO_REG_TYPE *baseReg; + +#if ONEWIRE_SEARCH + // global search state + unsigned char ROM_NO[8]; + uint8_t LastDiscrepancy; + uint8_t LastFamilyDiscrepancy; + bool LastDeviceFlag; +#endif + + public: + OneWire() { } + OneWire(uint8_t pin) { begin(pin); } + void begin(uint8_t pin); + + // Perform a 1-Wire reset cycle. Returns 1 if a device responds + // with a presence pulse. Returns 0 if there is no device or the + // bus is shorted or otherwise held low for more than 250uS + uint8_t reset(void); + + // Issue a 1-Wire rom select command, you do the reset first. + void select(const uint8_t rom[8]); + + // Issue a 1-Wire rom skip command, to address all on bus. + void skip(void); + + // Write a byte. If 'power' is one then the wire is held high at + // the end for parasitically powered devices. You are responsible + // for eventually depowering it by calling depower() or doing + // another read or write. + void write(uint8_t v, uint8_t power = 0); + + void write_bytes(const uint8_t *buf, uint16_t count, bool power = 0); + + // Read a byte. + uint8_t read(void); + + void read_bytes(uint8_t *buf, uint16_t count); + + // Write a bit. The bus is always left powered at the end, see + // note in write() about that. + void write_bit(uint8_t v); + + // Read a bit. + uint8_t read_bit(void); + + // Stop forcing power onto the bus. You only need to do this if + // you used the 'power' flag to write() or used a write_bit() call + // and aren't about to do another read or write. You would rather + // not leave this powered if you don't have to, just in case + // someone shorts your bus. + void depower(void); + +#if ONEWIRE_SEARCH + // Clear the search state so that if will start from the beginning again. + void reset_search(); + + // Setup the search to find the device type 'family_code' on the next call + // to search(*newAddr) if it is present. + void target_search(uint8_t family_code); + + // Look for the next device. Returns 1 if a new address has been + // returned. A zero might mean that the bus is shorted, there are + // no devices, or you have already retrieved all of them. It + // might be a good idea to check the CRC to make sure you didn't + // get garbage. The order is deterministic. You will always get + // the same devices in the same order. + bool search(uint8_t *newAddr, bool search_mode = true); +#endif + +#if ONEWIRE_CRC + // Compute a Dallas Semiconductor 8 bit CRC, these are used in the + // ROM and scratchpad registers. + static uint8_t crc8(const uint8_t *addr, uint8_t len); + +#if ONEWIRE_CRC16 + // Compute the 1-Wire CRC16 and compare it against the received CRC. + // Example usage (reading a DS2408): + // // Put everything in a buffer so we can compute the CRC easily. + // uint8_t buf[13]; + // buf[0] = 0xF0; // Read PIO Registers + // buf[1] = 0x88; // LSB address + // buf[2] = 0x00; // MSB address + // WriteBytes(net, buf, 3); // Write 3 cmd bytes + // ReadBytes(net, buf+3, 10); // Read 6 data bytes, 2 0xFF, 2 CRC16 + // if (!CheckCRC16(buf, 11, &buf[11])) { + // // Handle error. + // } + // + // @param input - Array of bytes to checksum. + // @param len - How many bytes to use. + // @param inverted_crc - The two CRC16 bytes in the received data. + // This should just point into the received data, + // *not* at a 16-bit integer. + // @param crc - The crc starting value (optional) + // @return True, iff the CRC matches. + static bool check_crc16(const uint8_t* input, uint16_t len, const uint8_t* inverted_crc, uint16_t crc = 0); + + // Compute a Dallas Semiconductor 16 bit CRC. This is required to check + // the integrity of data received from many 1-Wire devices. Note that the + // CRC computed here is *not* what you'll get from the 1-Wire network, + // for two reasons: + // 1) The CRC is transmitted bitwise inverted. + // 2) Depending on the endian-ness of your processor, the binary + // representation of the two-byte return value may have a different + // byte order than the two bytes you get from 1-Wire. + // @param input - Array of bytes to checksum. + // @param len - How many bytes to use. + // @param crc - The crc starting value (optional) + // @return The CRC16, as defined by Dallas Semiconductor. + static uint16_t crc16(const uint8_t* input, uint16_t len, uint16_t crc = 0); +#endif +#endif +}; + +// Prevent this name from leaking into Arduino sketches +#ifdef IO_REG_TYPE +#undef IO_REG_TYPE +#endif + +#endif // __cplusplus +#endif // OneWire_h diff --git a/lib/OneWire/docs/issue_template.md b/lib/OneWire/docs/issue_template.md new file mode 100644 index 0000000..0610992 --- /dev/null +++ b/lib/OneWire/docs/issue_template.md @@ -0,0 +1,64 @@ +Please use this form only to report code defects or bugs. + +For any question, even questions directly pertaining to this code, post your question on the forums related to the board you are using. + +Arduino: forum.arduino.cc +Teensy: forum.pjrc.com +ESP8266: www.esp8266.com +ESP32: www.esp32.com +Adafruit Feather/Metro/Trinket: forums.adafruit.com +Particle Photon: community.particle.io + +If you are experiencing trouble but not certain of the cause, or need help using this code, ask on the appropriate forum. This is not the place to ask for support or help, even directly related to this code. Only use this form you are certain you have discovered a defect in this code! + +Please verify the problem occurs when using the very latest version, using the newest version of Arduino and any other related software. + + +----------------------------- Remove above ----------------------------- + + + +### Description + +Describe your problem. + + + +### Steps To Reproduce Problem + +Please give detailed instructions needed for anyone to attempt to reproduce the problem. + + + +### Hardware & Software + +Board +Shields / modules used +Arduino IDE version +Teensyduino version (if using Teensy) +Version info & package name (from Tools > Boards > Board Manager) +Operating system & version +Any other software or hardware? + + +### Arduino Sketch + +```cpp +// Change the code below by your sketch (please try to give the smallest code which demonstrates the problem) +#include + +// libraries: give links/details so anyone can compile your code for the same result + +void setup() { +} + +void loop() { +} +``` + + +### Errors or Incorrect Output + +If you see any errors or incorrect output, please show it here. Please use copy & paste to give an exact copy of the message. Details matter, so please show (not merely describe) the actual message or error exactly as it appears. + + diff --git a/lib/OneWire/examples/DS18x20_Temperature/DS18x20_Temperature.ino b/lib/OneWire/examples/DS18x20_Temperature/DS18x20_Temperature.ino new file mode 100644 index 0000000..34a5e44 --- /dev/null +++ b/lib/OneWire/examples/DS18x20_Temperature/DS18x20_Temperature.ino @@ -0,0 +1,112 @@ +#include + +// OneWire DS18S20, DS18B20, DS1822 Temperature Example +// +// http://www.pjrc.com/teensy/td_libs_OneWire.html +// +// The DallasTemperature library can do all this work for you! +// https://github.com/milesburton/Arduino-Temperature-Control-Library + +OneWire ds(10); // on pin 10 (a 4.7K resistor is necessary) + +void setup(void) { + Serial.begin(9600); +} + +void loop(void) { + byte i; + byte present = 0; + byte type_s; + byte data[9]; + byte addr[8]; + float celsius, fahrenheit; + + if ( !ds.search(addr)) { + Serial.println("No more addresses."); + Serial.println(); + ds.reset_search(); + delay(250); + return; + } + + Serial.print("ROM ="); + for( i = 0; i < 8; i++) { + Serial.write(' '); + Serial.print(addr[i], HEX); + } + + if (OneWire::crc8(addr, 7) != addr[7]) { + Serial.println("CRC is not valid!"); + return; + } + Serial.println(); + + // the first ROM byte indicates which chip + switch (addr[0]) { + case 0x10: + Serial.println(" Chip = DS18S20"); // or old DS1820 + type_s = 1; + break; + case 0x28: + Serial.println(" Chip = DS18B20"); + type_s = 0; + break; + case 0x22: + Serial.println(" Chip = DS1822"); + type_s = 0; + break; + default: + Serial.println("Device is not a DS18x20 family device."); + return; + } + + ds.reset(); + ds.select(addr); + ds.write(0x44, 1); // start conversion, with parasite power on at the end + + delay(1000); // maybe 750ms is enough, maybe not + // we might do a ds.depower() here, but the reset will take care of it. + + present = ds.reset(); + ds.select(addr); + ds.write(0xBE); // Read Scratchpad + + Serial.print(" Data = "); + Serial.print(present, HEX); + Serial.print(" "); + for ( i = 0; i < 9; i++) { // we need 9 bytes + data[i] = ds.read(); + Serial.print(data[i], HEX); + Serial.print(" "); + } + Serial.print(" CRC="); + Serial.print(OneWire::crc8(data, 8), HEX); + Serial.println(); + + // Convert the data to actual temperature + // because the result is a 16 bit signed integer, it should + // be stored to an "int16_t" type, which is always 16 bits + // even when compiled on a 32 bit processor. + int16_t raw = (data[1] << 8) | data[0]; + if (type_s) { + raw = raw << 3; // 9 bit resolution default + if (data[7] == 0x10) { + // "count remain" gives full 12 bit resolution + raw = (raw & 0xFFF0) + 12 - data[6]; + } + } else { + byte cfg = (data[4] & 0x60); + // at lower res, the low bits are undefined, so let's zero them + if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms + else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms + else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms + //// default is 12 bit resolution, 750 ms conversion time + } + celsius = (float)raw / 16.0; + fahrenheit = celsius * 1.8 + 32.0; + Serial.print(" Temperature = "); + Serial.print(celsius); + Serial.print(" Celsius, "); + Serial.print(fahrenheit); + Serial.println(" Fahrenheit"); +} diff --git a/lib/OneWire/examples/DS2408_Switch/DS2408_Switch.ino b/lib/OneWire/examples/DS2408_Switch/DS2408_Switch.ino new file mode 100644 index 0000000..b70eda9 --- /dev/null +++ b/lib/OneWire/examples/DS2408_Switch/DS2408_Switch.ino @@ -0,0 +1,74 @@ +#include + +/* + * DS2408 8-Channel Addressable Switch + * + * Writte by Glenn Trewitt, glenn at trewitt dot org + * + * Some notes about the DS2408: + * - Unlike most input/output ports, the DS2408 doesn't have mode bits to + * set whether the pins are input or output. If you issue a read command, + * they're inputs. If you write to them, they're outputs. + * - For reading from a switch, you should use 10K pull-up resisters. + */ + +OneWire net(10); // on pin 10 + + +void PrintBytes(const uint8_t* addr, uint8_t count, bool newline=false) { + for (uint8_t i = 0; i < count; i++) { + Serial.print(addr[i]>>4, HEX); + Serial.print(addr[i]&0x0f, HEX); + } + if (newline) + Serial.println(); +} + + +void setup(void) { + Serial.begin(9600); +} + +void loop(void) { + byte addr[8]; + + if (!net.search(addr)) { + Serial.print("No more addresses.\n"); + net.reset_search(); + delay(1000); + return; + } + + if (OneWire::crc8(addr, 7) != addr[7]) { + Serial.print("CRC is not valid!\n"); + return; + } + + if (addr[0] != 0x29) { + PrintBytes(addr, 8); + Serial.print(" is not a DS2408.\n"); + return; + } + + Serial.print(" Reading DS2408 "); + PrintBytes(addr, 8); + Serial.println(); + + uint8_t buf[13]; // Put everything in the buffer so we can compute CRC easily. + buf[0] = 0xF0; // Read PIO Registers + buf[1] = 0x88; // LSB address + buf[2] = 0x00; // MSB address + net.write_bytes(buf, 3); + net.read_bytes(buf+3, 10); // 3 cmd bytes, 6 data bytes, 2 0xFF, 2 CRC16 + net.reset(); + + if (!OneWire::check_crc16(buf, 11, &buf[11])) { + Serial.print("CRC failure in DS2408 at "); + PrintBytes(addr, 8, true); + return; + } + Serial.print(" DS2408 data = "); + // First 3 bytes contain command, register address. + Serial.println(buf[3], BIN); +} + diff --git a/lib/OneWire/examples/DS250x_PROM/DS250x_PROM.ino b/lib/OneWire/examples/DS250x_PROM/DS250x_PROM.ino new file mode 100644 index 0000000..db95a5e --- /dev/null +++ b/lib/OneWire/examples/DS250x_PROM/DS250x_PROM.ino @@ -0,0 +1,75 @@ +/* +DS250x add-only programmable memory reader w/SKIP ROM. + + The DS250x is a 512/1024bit add-only PROM(you can add data but cannot change the old one) that's used mainly for device identification purposes + like serial number, mfgr data, unique identifiers, etc. It uses the Maxim 1-wire bus. + + This sketch will use the SKIP ROM function that skips the 1-Wire search phase since we only have one device connected in the bus on digital pin 6. + If more than one device is connected to the bus, it will fail. + Sketch will not verify if device connected is from the DS250x family since the skip rom function effectively skips the family-id byte readout. + thus it is possible to run this sketch with any Maxim OneWire device in which case the command CRC will most likely fail. + Sketch will only read the first page of memory(32bits) starting from the lower address(0000h), if more than 1 device is present, then use the sketch with search functions. + Remember to put a 4.7K pullup resistor between pin 6 and +Vcc + + To change the range or ammount of data to read, simply change the data array size, LSB/MSB addresses and for loop iterations + + This example code is in the public domain and is provided AS-IS. + + Built with Arduino 0022 and PJRC OneWire 2.0 library http://www.pjrc.com/teensy/td_libs_OneWire.html + + created by Guillermo Lovato + march/2011 + + */ + +#include +OneWire ds(6); // OneWire bus on digital pin 6 +void setup() { + Serial.begin (9600); +} + +void loop() { + byte i; // This is for the for loops + boolean present; // device present var + byte data[32]; // container for the data from device + byte leemem[3] = { // array with the commands to initiate a read, DS250x devices expect 3 bytes to start a read: command,LSB&MSB adresses + 0xF0 , 0x00 , 0x00 }; // 0xF0 is the Read Data command, followed by 00h 00h as starting address(the beginning, 0000h) + byte ccrc; // Variable to store the command CRC + byte ccrc_calc; + + present = ds.reset(); // OneWire bus reset, always needed to start operation on the bus, returns a 1/TRUE if there's a device present. + ds.skip(); // Skip ROM search + + if (present == true) { // We only try to read the data if there's a device present + Serial.println("DS250x device present"); + ds.write(leemem[0],1); // Read data command, leave ghost power on + ds.write(leemem[1],1); // LSB starting address, leave ghost power on + ds.write(leemem[2],1); // MSB starting address, leave ghost power on + + ccrc = ds.read(); // DS250x generates a CRC for the command we sent, we assign a read slot and store it's value + ccrc_calc = OneWire::crc8(leemem, 3); // We calculate the CRC of the commands we sent using the library function and store it + + if ( ccrc_calc != ccrc) { // Then we compare it to the value the ds250x calculated, if it fails, we print debug messages and abort + Serial.println("Invalid command CRC!"); + Serial.print("Calculated CRC:"); + Serial.println(ccrc_calc,HEX); // HEX makes it easier to observe and compare + Serial.print("DS250x readback CRC:"); + Serial.println(ccrc,HEX); + return; // Since CRC failed, we abort the rest of the loop and start over + } + Serial.println("Data is: "); // For the printout of the data + for ( i = 0; i < 32; i++) { // Now it's time to read the PROM data itself, each page is 32 bytes so we need 32 read commands + data[i] = ds.read(); // we store each read byte to a different position in the data array + Serial.print(data[i]); // printout in ASCII + Serial.print(" "); // blank space + } + Serial.println(); + delay(5000); // Delay so we don't saturate the serial output + } + else { // Nothing is connected in the bus + Serial.println("Nothing connected"); + delay(3000); + } +} + + diff --git a/lib/OneWire/keywords.txt b/lib/OneWire/keywords.txt new file mode 100644 index 0000000..bee5d90 --- /dev/null +++ b/lib/OneWire/keywords.txt @@ -0,0 +1,38 @@ +####################################### +# Syntax Coloring Map For OneWire +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +OneWire KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +reset KEYWORD2 +write_bit KEYWORD2 +read_bit KEYWORD2 +write KEYWORD2 +write_bytes KEYWORD2 +read KEYWORD2 +read_bytes KEYWORD2 +select KEYWORD2 +skip KEYWORD2 +depower KEYWORD2 +reset_search KEYWORD2 +search KEYWORD2 +crc8 KEYWORD2 +crc16 KEYWORD2 +check_crc16 KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/lib/OneWire/library.json b/lib/OneWire/library.json new file mode 100644 index 0000000..f370f06 --- /dev/null +++ b/lib/OneWire/library.json @@ -0,0 +1,61 @@ +{ + "name": "OneWire", + "description": "Control 1-Wire protocol (DS18S20, DS18B20, DS2408 and etc)", + "keywords": "onewire, 1-wire, bus, sensor, temperature, ibutton", + "authors": [ + { + "name": "Paul Stoffregen", + "email": "paul@pjrc.com", + "url": "http://www.pjrc.com", + "maintainer": true + }, + { + "name": "Jim Studt" + }, + { + "name": "Tom Pollard", + "email": "pollard@alum.mit.edu" + }, + { + "name": "Derek Yerger" + }, + { + "name": "Josh Larios" + }, + { + "name": "Robin James" + }, + { + "name": "Glenn Trewitt" + }, + { + "name": "Jason Dangel", + "email": "dangel.jason AT gmail.com" + }, + { + "name": "Guillermo Lovato" + }, + { + "name": "Ken Butcher" + }, + { + "name": "Mark Tillotson" + }, + { + "name": "Bertrik Sikken" + }, + { + "name": "Scott Roberts" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/PaulStoffregen/OneWire" + }, + "version": "2.3.7", + "homepage": "https://www.pjrc.com/teensy/td_libs_OneWire.html", + "frameworks": "Arduino", + "examples": [ + "examples/*/*.pde" + ] +} diff --git a/lib/OneWire/library.properties b/lib/OneWire/library.properties new file mode 100644 index 0000000..5256ce4 --- /dev/null +++ b/lib/OneWire/library.properties @@ -0,0 +1,10 @@ +name=OneWire +version=2.3.7 +author=Jim Studt, Tom Pollard, Robin James, Glenn Trewitt, Jason Dangel, Guillermo Lovato, Paul Stoffregen, Scott Roberts, Bertrik Sikken, Mark Tillotson, Ken Butcher, Roger Clark, Love Nystrom +maintainer=Paul Stoffregen +sentence=Access 1-wire temperature sensors, memory and other chips. +paragraph= +category=Communication +url=http://www.pjrc.com/teensy/td_libs_OneWire.html +architectures=* + diff --git a/lib/OneWire/util/OneWire_direct_gpio.h b/lib/OneWire/util/OneWire_direct_gpio.h new file mode 100644 index 0000000..435443a --- /dev/null +++ b/lib/OneWire/util/OneWire_direct_gpio.h @@ -0,0 +1,445 @@ +#ifndef OneWire_Direct_GPIO_h +#define OneWire_Direct_GPIO_h + +// This header should ONLY be included by OneWire.cpp. These defines are +// meant to be private, used within OneWire.cpp, but not exposed to Arduino +// sketches or other libraries which may include OneWire.h. + +#include + +// Platform specific I/O definitions + +#if defined(__AVR__) +#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint8_t +#define IO_REG_BASE_ATTR asm("r30") +#define IO_REG_MASK_ATTR +#if defined(__AVR_ATmega4809__) +#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) ((*((base)-8)) &= ~(mask)) +#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)-8)) |= (mask)) +#define DIRECT_WRITE_LOW(base, mask) ((*((base)-4)) &= ~(mask)) +#define DIRECT_WRITE_HIGH(base, mask) ((*((base)-4)) |= (mask)) +#else +#define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) &= ~(mask)) +#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+1)) |= (mask)) +#define DIRECT_WRITE_LOW(base, mask) ((*((base)+2)) &= ~(mask)) +#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask)) +#endif + +#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__) +#define PIN_TO_BASEREG(pin) (portOutputRegister(pin)) +#define PIN_TO_BITMASK(pin) (1) +#define IO_REG_TYPE uint8_t +#define IO_REG_BASE_ATTR +#define IO_REG_MASK_ATTR __attribute__ ((unused)) +#define DIRECT_READ(base, mask) (*((base)+512)) +#define DIRECT_MODE_INPUT(base, mask) (*((base)+640) = 0) +#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+640) = 1) +#define DIRECT_WRITE_LOW(base, mask) (*((base)+256) = 1) +#define DIRECT_WRITE_HIGH(base, mask) (*((base)+128) = 1) + +#elif defined(__MKL26Z64__) +#define PIN_TO_BASEREG(pin) (portOutputRegister(pin)) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint8_t +#define IO_REG_BASE_ATTR +#define IO_REG_MASK_ATTR +#define DIRECT_READ(base, mask) ((*((base)+16) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) (*((base)+20) &= ~(mask)) +#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+20) |= (mask)) +#define DIRECT_WRITE_LOW(base, mask) (*((base)+8) = (mask)) +#define DIRECT_WRITE_HIGH(base, mask) (*((base)+4) = (mask)) + +#elif defined(__IMXRT1052__) || defined(__IMXRT1062__) +#define PIN_TO_BASEREG(pin) (portOutputRegister(pin)) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint32_t +#define IO_REG_BASE_ATTR +#define IO_REG_MASK_ATTR +#define DIRECT_READ(base, mask) ((*((base)+2) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) (*((base)+1) &= ~(mask)) +#define DIRECT_MODE_OUTPUT(base, mask) (*((base)+1) |= (mask)) +#define DIRECT_WRITE_LOW(base, mask) (*((base)+34) = (mask)) +#define DIRECT_WRITE_HIGH(base, mask) (*((base)+33) = (mask)) + +#elif defined(__SAM3X8E__) || defined(__SAM3A8C__) || defined(__SAM3A4C__) +// Arduino 1.5.1 may have a bug in delayMicroseconds() on Arduino Due. +// http://arduino.cc/forum/index.php/topic,141030.msg1076268.html#msg1076268 +// If you have trouble with OneWire on Arduino Due, please check the +// status of delayMicroseconds() before reporting a bug in OneWire! +#define PIN_TO_BASEREG(pin) (&(digitalPinToPort(pin)->PIO_PER)) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint32_t +#define IO_REG_BASE_ATTR +#define IO_REG_MASK_ATTR +#define DIRECT_READ(base, mask) (((*((base)+15)) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) ((*((base)+5)) = (mask)) +#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+4)) = (mask)) +#define DIRECT_WRITE_LOW(base, mask) ((*((base)+13)) = (mask)) +#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+12)) = (mask)) +#ifndef PROGMEM +#define PROGMEM +#endif +#ifndef pgm_read_byte +#define pgm_read_byte(addr) (*(const uint8_t *)(addr)) +#endif + +#elif defined(__PIC32MX__) +#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin))) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint32_t +#define IO_REG_BASE_ATTR +#define IO_REG_MASK_ATTR +#define DIRECT_READ(base, mask) (((*(base+4)) & (mask)) ? 1 : 0) //PORTX + 0x10 +#define DIRECT_MODE_INPUT(base, mask) ((*(base+2)) = (mask)) //TRISXSET + 0x08 +#define DIRECT_MODE_OUTPUT(base, mask) ((*(base+1)) = (mask)) //TRISXCLR + 0x04 +#define DIRECT_WRITE_LOW(base, mask) ((*(base+8+1)) = (mask)) //LATXCLR + 0x24 +#define DIRECT_WRITE_HIGH(base, mask) ((*(base+8+2)) = (mask)) //LATXSET + 0x28 + +#elif defined(ARDUINO_ARCH_ESP8266) +// Special note: I depend on the ESP community to maintain these definitions and +// submit good pull requests. I can not answer any ESP questions or help you +// resolve any problems related to ESP chips. Please do not contact me and please +// DO NOT CREATE GITHUB ISSUES for ESP support. All ESP questions must be asked +// on ESP community forums. +#define PIN_TO_BASEREG(pin) ((volatile uint32_t*) GPO) +#define PIN_TO_BITMASK(pin) (1 << pin) +#define IO_REG_TYPE uint32_t +#define IO_REG_BASE_ATTR +#define IO_REG_MASK_ATTR +#define DIRECT_READ(base, mask) ((GPI & (mask)) ? 1 : 0) //GPIO_IN_ADDRESS +#define DIRECT_MODE_INPUT(base, mask) (GPE &= ~(mask)) //GPIO_ENABLE_W1TC_ADDRESS +#define DIRECT_MODE_OUTPUT(base, mask) (GPE |= (mask)) //GPIO_ENABLE_W1TS_ADDRESS +#define DIRECT_WRITE_LOW(base, mask) (GPOC = (mask)) //GPIO_OUT_W1TC_ADDRESS +#define DIRECT_WRITE_HIGH(base, mask) (GPOS = (mask)) //GPIO_OUT_W1TS_ADDRESS + +#elif defined(ARDUINO_ARCH_ESP32) +#include +#define PIN_TO_BASEREG(pin) (0) +#define PIN_TO_BITMASK(pin) (pin) +#define IO_REG_TYPE uint32_t +#define IO_REG_BASE_ATTR +#define IO_REG_MASK_ATTR + +static inline __attribute__((always_inline)) +IO_REG_TYPE directRead(IO_REG_TYPE pin) +{ +#if CONFIG_IDF_TARGET_ESP32C3 + return (GPIO.in.val >> pin) & 0x1; +#else // plain ESP32 + if ( pin < 32 ) + return (GPIO.in >> pin) & 0x1; + else if ( pin < 46 ) + return (GPIO.in1.val >> (pin - 32)) & 0x1; +#endif + + return 0; +} + +static inline __attribute__((always_inline)) +void directWriteLow(IO_REG_TYPE pin) +{ +#if CONFIG_IDF_TARGET_ESP32C3 + GPIO.out_w1tc.val = ((uint32_t)1 << pin); +#else // plain ESP32 + if ( pin < 32 ) + GPIO.out_w1tc = ((uint32_t)1 << pin); + else if ( pin < 46 ) + GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32)); +#endif +} + +static inline __attribute__((always_inline)) +void directWriteHigh(IO_REG_TYPE pin) +{ +#if CONFIG_IDF_TARGET_ESP32C3 + GPIO.out_w1ts.val = ((uint32_t)1 << pin); +#else // plain ESP32 + if ( pin < 32 ) + GPIO.out_w1ts = ((uint32_t)1 << pin); + else if ( pin < 46 ) + GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32)); +#endif +} + +static inline __attribute__((always_inline)) +void directModeInput(IO_REG_TYPE pin) +{ +#if CONFIG_IDF_TARGET_ESP32C3 + GPIO.enable_w1tc.val = ((uint32_t)1 << (pin)); +#else + if ( digitalPinIsValid(pin) ) + { +#if ESP_IDF_VERSION_MAJOR < 4 // IDF 3.x ESP32/PICO-D4 + uint32_t rtc_reg(rtc_gpio_desc[pin].reg); + + if ( rtc_reg ) // RTC pins PULL settings + { + ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux); + ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown); + } +#endif + // Input + if ( pin < 32 ) + GPIO.enable_w1tc = ((uint32_t)1 << pin); + else + GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32)); + } +#endif +} + +static inline __attribute__((always_inline)) +void directModeOutput(IO_REG_TYPE pin) +{ +#if CONFIG_IDF_TARGET_ESP32C3 + GPIO.enable_w1ts.val = ((uint32_t)1 << (pin)); +#else + if ( digitalPinIsValid(pin) && pin <= 33 ) // pins above 33 can be only inputs + { +#if ESP_IDF_VERSION_MAJOR < 4 // IDF 3.x ESP32/PICO-D4 + uint32_t rtc_reg(rtc_gpio_desc[pin].reg); + + if ( rtc_reg ) // RTC pins PULL settings + { + ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux); + ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown); + } +#endif + // Output + if ( pin < 32 ) + GPIO.enable_w1ts = ((uint32_t)1 << pin); + else // already validated to pins <= 33 + GPIO.enable1_w1ts.val = ((uint32_t)1 << (pin - 32)); + } +#endif +} + +#define DIRECT_READ(base, pin) directRead(pin) +#define DIRECT_WRITE_LOW(base, pin) directWriteLow(pin) +#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(pin) +#define DIRECT_MODE_INPUT(base, pin) directModeInput(pin) +#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(pin) +// https://github.com/PaulStoffregen/OneWire/pull/47 +// https://github.com/stickbreaker/OneWire/commit/6eb7fc1c11a15b6ac8c60e5671cf36eb6829f82c +#ifdef interrupts +#undef interrupts +#endif +#ifdef noInterrupts +#undef noInterrupts +#endif +#define noInterrupts() {portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;portENTER_CRITICAL(&mux) +#define interrupts() portEXIT_CRITICAL(&mux);} +//#warning "ESP32 OneWire testing" + +#elif defined(ARDUINO_ARCH_STM32) +#define PIN_TO_BASEREG(pin) (0) +#define PIN_TO_BITMASK(pin) ((uint32_t)digitalPinToPinName(pin)) +#define IO_REG_TYPE uint32_t +#define IO_REG_BASE_ATTR +#define IO_REG_MASK_ATTR +#define DIRECT_READ(base, pin) digitalReadFast((PinName)pin) +#define DIRECT_WRITE_LOW(base, pin) digitalWriteFast((PinName)pin, LOW) +#define DIRECT_WRITE_HIGH(base, pin) digitalWriteFast((PinName)pin, HIGH) +#define DIRECT_MODE_INPUT(base, pin) pin_function((PinName)pin, STM_PIN_DATA(STM_MODE_INPUT, GPIO_NOPULL, 0)) +#define DIRECT_MODE_OUTPUT(base, pin) pin_function((PinName)pin, STM_PIN_DATA(STM_MODE_OUTPUT_PP, GPIO_NOPULL, 0)) + +#elif defined(__SAMD21G18A__) +#define PIN_TO_BASEREG(pin) portModeRegister(digitalPinToPort(pin)) +#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) +#define IO_REG_TYPE uint32_t +#define IO_REG_BASE_ATTR +#define IO_REG_MASK_ATTR +#define DIRECT_READ(base, mask) (((*((base)+8)) & (mask)) ? 1 : 0) +#define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) = (mask)) +#define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+2)) = (mask)) +#define DIRECT_WRITE_LOW(base, mask) ((*((base)+5)) = (mask)) +#define DIRECT_WRITE_HIGH(base, mask) ((*((base)+6)) = (mask)) + +#elif defined(__ASR6501__) +#define PIN_IN_PORT(pin) (pin % PIN_NUMBER_IN_PORT) +#define PORT_FROM_PIN(pin) (pin / PIN_NUMBER_IN_PORT) +#define PORT_OFFSET(port) (PORT_REG_SHFIT * port) +#define PORT_ADDRESS(pin) (CYDEV_GPIO_BASE + PORT_OFFSET(PORT_FROM_PIN(pin))) + +#define PIN_TO_BASEREG(pin) (0) +#define PIN_TO_BITMASK(pin) (pin) +#define IO_REG_TYPE uint32_t +#define IO_REG_BASE_ATTR +#define IO_REG_MASK_ATTR +#define DIRECT_READ(base, pin) CY_SYS_PINS_READ_PIN(PORT_ADDRESS(pin)+4, PIN_IN_PORT(pin)) +#define DIRECT_WRITE_LOW(base, pin) CY_SYS_PINS_CLEAR_PIN(PORT_ADDRESS(pin), PIN_IN_PORT(pin)) +#define DIRECT_WRITE_HIGH(base, pin) CY_SYS_PINS_SET_PIN(PORT_ADDRESS(pin), PIN_IN_PORT(pin)) +#define DIRECT_MODE_INPUT(base, pin) CY_SYS_PINS_SET_DRIVE_MODE(PORT_ADDRESS(pin)+8, PIN_IN_PORT(pin), CY_SYS_PINS_DM_DIG_HIZ) +#define DIRECT_MODE_OUTPUT(base, pin) CY_SYS_PINS_SET_DRIVE_MODE(PORT_ADDRESS(pin)+8, PIN_IN_PORT(pin), CY_SYS_PINS_DM_STRONG) + +#elif defined(RBL_NRF51822) +#define PIN_TO_BASEREG(pin) (0) +#define PIN_TO_BITMASK(pin) (pin) +#define IO_REG_TYPE uint32_t +#define IO_REG_BASE_ATTR +#define IO_REG_MASK_ATTR +#define DIRECT_READ(base, pin) nrf_gpio_pin_read(pin) +#define DIRECT_WRITE_LOW(base, pin) nrf_gpio_pin_clear(pin) +#define DIRECT_WRITE_HIGH(base, pin) nrf_gpio_pin_set(pin) +#define DIRECT_MODE_INPUT(base, pin) nrf_gpio_cfg_input(pin, NRF_GPIO_PIN_NOPULL) +#define DIRECT_MODE_OUTPUT(base, pin) nrf_gpio_cfg_output(pin) + +#elif defined(__arc__) /* Arduino101/Genuino101 specifics */ + +#include "scss_registers.h" +#include "portable.h" +#include "avr/pgmspace.h" + +#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId) +#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType) +#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase) +#define DIR_OFFSET_SS 0x01 +#define DIR_OFFSET_SOC 0x04 +#define EXT_PORT_OFFSET_SS 0x0A +#define EXT_PORT_OFFSET_SOC 0x50 + +/* GPIO registers base address */ +#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase) +#define PIN_TO_BITMASK(pin) pin +#define IO_REG_TYPE uint32_t +#define IO_REG_BASE_ATTR +#define IO_REG_MASK_ATTR + +static inline __attribute__((always_inline)) +IO_REG_TYPE directRead(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + IO_REG_TYPE ret; + if (SS_GPIO == GPIO_TYPE(pin)) { + ret = READ_ARC_REG(((IO_REG_TYPE)base + EXT_PORT_OFFSET_SS)); + } else { + ret = MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, EXT_PORT_OFFSET_SOC); + } + return ((ret >> GPIO_ID(pin)) & 0x01); +} + +static inline __attribute__((always_inline)) +void directModeInput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + if (SS_GPIO == GPIO_TYPE(pin)) { + WRITE_ARC_REG(READ_ARC_REG((((IO_REG_TYPE)base) + DIR_OFFSET_SS)) & ~(0x01 << GPIO_ID(pin)), + ((IO_REG_TYPE)(base) + DIR_OFFSET_SS)); + } else { + MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) &= ~(0x01 << GPIO_ID(pin)); + } +} + +static inline __attribute__((always_inline)) +void directModeOutput(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + if (SS_GPIO == GPIO_TYPE(pin)) { + WRITE_ARC_REG(READ_ARC_REG(((IO_REG_TYPE)(base) + DIR_OFFSET_SS)) | (0x01 << GPIO_ID(pin)), + ((IO_REG_TYPE)(base) + DIR_OFFSET_SS)); + } else { + MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, DIR_OFFSET_SOC) |= (0x01 << GPIO_ID(pin)); + } +} + +static inline __attribute__((always_inline)) +void directWriteLow(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + if (SS_GPIO == GPIO_TYPE(pin)) { + WRITE_ARC_REG(READ_ARC_REG(base) & ~(0x01 << GPIO_ID(pin)), base); + } else { + MMIO_REG_VAL(base) &= ~(0x01 << GPIO_ID(pin)); + } +} + +static inline __attribute__((always_inline)) +void directWriteHigh(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) +{ + if (SS_GPIO == GPIO_TYPE(pin)) { + WRITE_ARC_REG(READ_ARC_REG(base) | (0x01 << GPIO_ID(pin)), base); + } else { + MMIO_REG_VAL(base) |= (0x01 << GPIO_ID(pin)); + } +} + +#define DIRECT_READ(base, pin) directRead(base, pin) +#define DIRECT_MODE_INPUT(base, pin) directModeInput(base, pin) +#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(base, pin) +#define DIRECT_WRITE_LOW(base, pin) directWriteLow(base, pin) +#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(base, pin) + +#elif defined(__riscv) + +/* + * Tested on highfive1 + * + * Stable results are achieved operating in the + * two high speed modes of the highfive1. It + * seems to be less reliable in slow mode. + */ +#define PIN_TO_BASEREG(pin) (0) +#define PIN_TO_BITMASK(pin) digitalPinToBitMask(pin) +#define IO_REG_TYPE uint32_t +#define IO_REG_BASE_ATTR +#define IO_REG_MASK_ATTR + +static inline __attribute__((always_inline)) +IO_REG_TYPE directRead(IO_REG_TYPE mask) +{ + return ((GPIO_REG(GPIO_INPUT_VAL) & mask) != 0) ? 1 : 0; +} + +static inline __attribute__((always_inline)) +void directModeInput(IO_REG_TYPE mask) +{ + GPIO_REG(GPIO_OUTPUT_XOR) &= ~mask; + GPIO_REG(GPIO_IOF_EN) &= ~mask; + + GPIO_REG(GPIO_INPUT_EN) |= mask; + GPIO_REG(GPIO_OUTPUT_EN) &= ~mask; +} + +static inline __attribute__((always_inline)) +void directModeOutput(IO_REG_TYPE mask) +{ + GPIO_REG(GPIO_OUTPUT_XOR) &= ~mask; + GPIO_REG(GPIO_IOF_EN) &= ~mask; + + GPIO_REG(GPIO_INPUT_EN) &= ~mask; + GPIO_REG(GPIO_OUTPUT_EN) |= mask; +} + +static inline __attribute__((always_inline)) +void directWriteLow(IO_REG_TYPE mask) +{ + GPIO_REG(GPIO_OUTPUT_VAL) &= ~mask; +} + +static inline __attribute__((always_inline)) +void directWriteHigh(IO_REG_TYPE mask) +{ + GPIO_REG(GPIO_OUTPUT_VAL) |= mask; +} + +#define DIRECT_READ(base, mask) directRead(mask) +#define DIRECT_WRITE_LOW(base, mask) directWriteLow(mask) +#define DIRECT_WRITE_HIGH(base, mask) directWriteHigh(mask) +#define DIRECT_MODE_INPUT(base, mask) directModeInput(mask) +#define DIRECT_MODE_OUTPUT(base, mask) directModeOutput(mask) + +#else +#define PIN_TO_BASEREG(pin) (0) +#define PIN_TO_BITMASK(pin) (pin) +#define IO_REG_TYPE unsigned int +#define IO_REG_BASE_ATTR +#define IO_REG_MASK_ATTR +#define DIRECT_READ(base, pin) digitalRead(pin) +#define DIRECT_WRITE_LOW(base, pin) digitalWrite(pin, LOW) +#define DIRECT_WRITE_HIGH(base, pin) digitalWrite(pin, HIGH) +#define DIRECT_MODE_INPUT(base, pin) pinMode(pin,INPUT) +#define DIRECT_MODE_OUTPUT(base, pin) pinMode(pin,OUTPUT) +#warning "OneWire. Fallback mode. Using API calls for pinMode,digitalRead and digitalWrite. Operation of this library is not guaranteed on this architecture." + +#endif + +#endif diff --git a/lib/OneWire/util/OneWire_direct_regtype.h b/lib/OneWire/util/OneWire_direct_regtype.h new file mode 100644 index 0000000..ca6aff7 --- /dev/null +++ b/lib/OneWire/util/OneWire_direct_regtype.h @@ -0,0 +1,55 @@ +#ifndef OneWire_Direct_RegType_h +#define OneWire_Direct_RegType_h + +#include + +// Platform specific I/O register type + +#if defined(__AVR__) +#define IO_REG_TYPE uint8_t + +#elif defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MK66FX1M0__) || defined(__MK64FX512__) +#define IO_REG_TYPE uint8_t + +#elif defined(__IMXRT1052__) || defined(__IMXRT1062__) +#define IO_REG_TYPE uint32_t + +#elif defined(__MKL26Z64__) +#define IO_REG_TYPE uint8_t + +#elif defined(__SAM3X8E__) || defined(__SAM3A8C__) || defined(__SAM3A4C__) +#define IO_REG_TYPE uint32_t + +#elif defined(__PIC32MX__) +#define IO_REG_TYPE uint32_t + +#elif defined(ARDUINO_ARCH_ESP8266) +#define IO_REG_TYPE uint32_t + +#elif defined(ARDUINO_ARCH_ESP32) +#define IO_REG_TYPE uint32_t +#define IO_REG_MASK_ATTR + +#elif defined(ARDUINO_ARCH_STM32) +#define IO_REG_TYPE uint32_t + +#elif defined(__SAMD21G18A__) +#define IO_REG_TYPE uint32_t + +#elif defined(__ASR6501__) +#define IO_REG_TYPE uint32_t + +#elif defined(RBL_NRF51822) +#define IO_REG_TYPE uint32_t + +#elif defined(__arc__) /* Arduino101/Genuino101 specifics */ +#define IO_REG_TYPE uint32_t + +#elif defined(__riscv) +#define IO_REG_TYPE uint32_t + +#else +#define IO_REG_TYPE unsigned int + +#endif +#endif diff --git a/lib/RCSwitch/RCSwitch.cpp b/lib/RCSwitch/RCSwitch.cpp new file mode 100644 index 0000000..762ebd0 --- /dev/null +++ b/lib/RCSwitch/RCSwitch.cpp @@ -0,0 +1,823 @@ +/* + RCSwitch - Arduino libary for remote control outlet switches + Copyright (c) 2011 Suat zgr. All right reserved. + + Contributors: + - Andre Koehler / info(at)tomate-online(dot)de + - Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com + - Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46 + - Dominik Fischer / dom_fischer(at)web(dot)de + - Frank Oltmanns / .(at)gmail(dot)com + - Andreas Steinel / A.(at)gmail(dot)com + + Project home: http://code.google.com/p/rc-switch/ + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "RCSwitch.h" + +#if not defined( RCSwitchDisableReceiving ) +unsigned long RCSwitch::nReceivedValue = NULL; +unsigned int RCSwitch::nReceivedBitlength = 0; +unsigned int RCSwitch::nReceivedDelay = 0; +unsigned int RCSwitch::nReceivedProtocol = 0; +int RCSwitch::nReceiveTolerance = 60; +#endif +unsigned int RCSwitch::timings[RCSWITCH_MAX_CHANGES]; + +RCSwitch::RCSwitch() { + this->nTransmitterPin = -1; + this->setPulseLength(350); + this->setRepeatTransmit(10); + this->setProtocol(1); + #if not defined( RCSwitchDisableReceiving ) + this->nReceiverInterrupt = -1; + this->setReceiveTolerance(60); + RCSwitch::nReceivedValue = NULL; + #endif +} + +/** + * Sets the protocol to send. + */ +void RCSwitch::setProtocol(int nProtocol) { + this->nProtocol = nProtocol; + if (nProtocol == 1){ + this->setPulseLength(350); + } + else if (nProtocol == 2) { + this->setPulseLength(650); + } + else if (nProtocol == 3) { + this->setPulseLength(100); + } +} + +/** + * Sets the protocol to send with pulse length in microseconds. + */ +void RCSwitch::setProtocol(int nProtocol, int nPulseLength) { + this->nProtocol = nProtocol; + this->setPulseLength(nPulseLength); +} + + +/** + * Sets pulse length in microseconds + */ +void RCSwitch::setPulseLength(int nPulseLength) { + this->nPulseLength = nPulseLength; +} + +/** + * Sets Repeat Transmits + */ +void RCSwitch::setRepeatTransmit(int nRepeatTransmit) { + this->nRepeatTransmit = nRepeatTransmit; +} + +/** + * Set Receiving Tolerance + */ +#if not defined( RCSwitchDisableReceiving ) +void RCSwitch::setReceiveTolerance(int nPercent) { + RCSwitch::nReceiveTolerance = nPercent; +} +#endif + + +/** + * Enable transmissions + * + * @param nTransmitterPin Arduino Pin to which the sender is connected to + */ +void RCSwitch::enableTransmit(int nTransmitterPin) { + this->nTransmitterPin = nTransmitterPin; + pinMode(this->nTransmitterPin, OUTPUT); +} + +/** + * Disable transmissions + */ +void RCSwitch::disableTransmit() { + this->nTransmitterPin = -1; +} + +/** + * Switch a remote switch on (Type D REV) + * + * @param sGroup Code of the switch group (A,B,C,D) + * @param nDevice Number of the switch itself (1..3) + */ +void RCSwitch::switchOn(char sGroup, int nDevice) { + this->sendTriState( this->getCodeWordD(sGroup, nDevice, true) ); +} + +/** + * Switch a remote switch off (Type D REV) + * + * @param sGroup Code of the switch group (A,B,C,D) + * @param nDevice Number of the switch itself (1..3) + */ +void RCSwitch::switchOff(char sGroup, int nDevice) { + this->sendTriState( this->getCodeWordD(sGroup, nDevice, false) ); +} + +/** + * Switch a remote switch on (Type C Intertechno) + * + * @param sFamily Familycode (a..f) + * @param nGroup Number of group (1..4) + * @param nDevice Number of device (1..4) + */ +void RCSwitch::switchOn(char sFamily, int nGroup, int nDevice) { + this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, true) ); +} + +/** + * Switch a remote switch off (Type C Intertechno) + * + * @param sFamily Familycode (a..f) + * @param nGroup Number of group (1..4) + * @param nDevice Number of device (1..4) + */ +void RCSwitch::switchOff(char sFamily, int nGroup, int nDevice) { + this->sendTriState( this->getCodeWordC(sFamily, nGroup, nDevice, false) ); +} + +/** + * Switch a remote switch on (Type B with two rotary/sliding switches) + * + * @param nAddressCode Number of the switch group (1..4) + * @param nChannelCode Number of the switch itself (1..4) + */ +void RCSwitch::switchOn(int nAddressCode, int nChannelCode) { + this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, true) ); +} + +/** + * Switch a remote switch off (Type B with two rotary/sliding switches) + * + * @param nAddressCode Number of the switch group (1..4) + * @param nChannelCode Number of the switch itself (1..4) + */ +void RCSwitch::switchOff(int nAddressCode, int nChannelCode) { + this->sendTriState( this->getCodeWordB(nAddressCode, nChannelCode, false) ); +} + +/** + * Deprecated, use switchOn(char* sGroup, char* sDevice) instead! + * Switch a remote switch on (Type A with 10 pole DIP switches) + * + * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111") + * @param nChannelCode Number of the switch itself (1..5) + */ +void RCSwitch::switchOn(char* sGroup, int nChannel) { + char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" }; + this->switchOn(sGroup, code[nChannel]); +} + +/** + * Deprecated, use switchOff(char* sGroup, char* sDevice) instead! + * Switch a remote switch off (Type A with 10 pole DIP switches) + * + * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111") + * @param nChannelCode Number of the switch itself (1..5) + */ +void RCSwitch::switchOff(char* sGroup, int nChannel) { + char* code[6] = { "00000", "10000", "01000", "00100", "00010", "00001" }; + this->switchOff(sGroup, code[nChannel]); +} + +/** + * Switch a remote switch on (Type A with 10 pole DIP switches) + * + * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111") + * @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111") + */ +void RCSwitch::switchOn(char* sGroup, char* sDevice) { + this->sendTriState( this->getCodeWordA(sGroup, sDevice, true) ); +} + +/** + * Switch a remote switch off (Type A with 10 pole DIP switches) + * + * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111") + * @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111") + */ +void RCSwitch::switchOff(char* sGroup, char* sDevice) { + this->sendTriState( this->getCodeWordA(sGroup, sDevice, false) ); +} + +/** + * Returns a char[13], representing the Code Word to be send. + * A Code Word consists of 9 address bits, 3 data bits and one sync bit but in our case only the first 8 address bits and the last 2 data bits were used. + * A Code Bit can have 4 different states: "F" (floating), "0" (low), "1" (high), "S" (synchronous bit) + * + * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+ + * | 4 bits address (switch group) | 4 bits address (switch number) | 1 bit address (not used, so never mind) | 1 bit address (not used, so never mind) | 2 data bits (on|off) | 1 sync bit | + * | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | F | F | on=FF off=F0 | S | + * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+ + * + * @param nAddressCode Number of the switch group (1..4) + * @param nChannelCode Number of the switch itself (1..4) + * @param bStatus Wether to switch on (true) or off (false) + * + * @return char[13] + */ +char* RCSwitch::getCodeWordB(int nAddressCode, int nChannelCode, boolean bStatus) { + int nReturnPos = 0; + static char sReturn[13]; + + char* code[5] = { "FFFF", "0FFF", "F0FF", "FF0F", "FFF0" }; + if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) { + return '\0'; + } + for (int i = 0; i<4; i++) { + sReturn[nReturnPos++] = code[nAddressCode][i]; + } + + for (int i = 0; i<4; i++) { + sReturn[nReturnPos++] = code[nChannelCode][i]; + } + + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + + if (bStatus) { + sReturn[nReturnPos++] = 'F'; + } else { + sReturn[nReturnPos++] = '0'; + } + + sReturn[nReturnPos] = '\0'; + + return sReturn; +} + +/** + * Returns a char[13], representing the Code Word to be send. + * + * getCodeWordA(char*, char*) + * + */ +char* RCSwitch::getCodeWordA(char* sGroup, char* sDevice, boolean bOn) { + static char sDipSwitches[13]; + int i = 0; + int j = 0; + + for (i=0; i < 5; i++) { + if (sGroup[i] == '0') { + sDipSwitches[j++] = 'F'; + } else { + sDipSwitches[j++] = '0'; + } + } + + for (i=0; i < 5; i++) { + if (sDevice[i] == '0') { + sDipSwitches[j++] = 'F'; + } else { + sDipSwitches[j++] = '0'; + } + } + + if ( bOn ) { + sDipSwitches[j++] = '0'; + sDipSwitches[j++] = 'F'; + } else { + sDipSwitches[j++] = 'F'; + sDipSwitches[j++] = '0'; + } + + sDipSwitches[j] = '\0'; + + return sDipSwitches; +} + +/** + * Like getCodeWord (Type C = Intertechno) + */ +char* RCSwitch::getCodeWordC(char sFamily, int nGroup, int nDevice, boolean bStatus) { + static char sReturn[13]; + int nReturnPos = 0; + + if ( (byte)sFamily < 97 || (byte)sFamily > 112 || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) { + return '\0'; + } + + char* sDeviceGroupCode = dec2binWzerofill( (nDevice-1) + (nGroup-1)*4, 4 ); + char familycode[16][5] = { "0000", "F000", "0F00", "FF00", "00F0", "F0F0", "0FF0", "FFF0", "000F", "F00F", "0F0F", "FF0F", "00FF", "F0FF", "0FFF", "FFFF" }; + for (int i = 0; i<4; i++) { + sReturn[nReturnPos++] = familycode[ (int)sFamily - 97 ][i]; + } + for (int i = 0; i<4; i++) { + sReturn[nReturnPos++] = (sDeviceGroupCode[3-i] == '1' ? 'F' : '0'); + } + sReturn[nReturnPos++] = '0'; + sReturn[nReturnPos++] = 'F'; + sReturn[nReturnPos++] = 'F'; + if (bStatus) { + sReturn[nReturnPos++] = 'F'; + } else { + sReturn[nReturnPos++] = '0'; + } + sReturn[nReturnPos] = '\0'; + return sReturn; +} + +/** + * Decoding for the REV Switch Type + * + * Returns a char[13], representing the Tristate to be send. + * A Code Word consists of 7 address bits and 5 command data bits. + * A Code Bit can have 3 different states: "F" (floating), "0" (low), "1" (high) + * + * +-------------------------------+--------------------------------+-----------------------+ + * | 4 bits address (switch group) | 3 bits address (device number) | 5 bits (command data) | + * | A=1FFF B=F1FF C=FF1F D=FFF1 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | on=00010 off=00001 | + * +-------------------------------+--------------------------------+-----------------------+ + * + * Source: http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/ + * + * @param sGroup Name of the switch group (A..D, resp. a..d) + * @param nDevice Number of the switch itself (1..3) + * @param bStatus Wether to switch on (true) or off (false) + * + * @return char[13] + */ + +char* RCSwitch::getCodeWordD(char sGroup, int nDevice, boolean bStatus){ + static char sReturn[13]; + int nReturnPos = 0; + + // Building 4 bits address + // (Potential problem if dec2binWcharfill not returning correct string) + char *sGroupCode; + switch(sGroup){ + case 'a': + case 'A': + sGroupCode = dec2binWcharfill(8, 4, 'F'); break; + case 'b': + case 'B': + sGroupCode = dec2binWcharfill(4, 4, 'F'); break; + case 'c': + case 'C': + sGroupCode = dec2binWcharfill(2, 4, 'F'); break; + case 'd': + case 'D': + sGroupCode = dec2binWcharfill(1, 4, 'F'); break; + default: + return '\0'; + } + + for (int i = 0; i<4; i++) + { + sReturn[nReturnPos++] = sGroupCode[i]; + } + + + // Building 3 bits address + // (Potential problem if dec2binWcharfill not returning correct string) + char *sDevice; + switch(nDevice) { + case 1: + sDevice = dec2binWcharfill(4, 3, 'F'); break; + case 2: + sDevice = dec2binWcharfill(2, 3, 'F'); break; + case 3: + sDevice = dec2binWcharfill(1, 3, 'F'); break; + default: + return '\0'; + } + + for (int i = 0; i<3; i++) + sReturn[nReturnPos++] = sDevice[i]; + + // fill up rest with zeros + for (int i = 0; i<5; i++) + sReturn[nReturnPos++] = '0'; + + // encode on or off + if (bStatus) + sReturn[10] = '1'; + else + sReturn[11] = '1'; + + // last position terminate string + sReturn[12] = '\0'; + return sReturn; + +} + +/** + * @param sCodeWord /^[10FS]*$/ -> see getCodeWord + */ +void RCSwitch::sendTriState(char* sCodeWord) { + for (int nRepeat=0; nRepeatsendT0(); + break; + case 'F': + this->sendTF(); + break; + case '1': + this->sendT1(); + break; + } + i++; + } + this->sendSync(); + } +} + +void RCSwitch::send(unsigned long Code, unsigned int length) { + this->send( this->dec2binWzerofill(Code, length) ); +} + +void RCSwitch::send(char* sCodeWord) { + for (int nRepeat=0; nRepeatsend0(); + break; + case '1': + this->send1(); + break; + } + i++; + } + this->sendSync(); + } +} + +void RCSwitch::transmit(int nHighPulses, int nLowPulses) { + #if not defined ( RCSwitchDisableReceiving ) + boolean disabled_Receive = false; + int nReceiverInterrupt_backup = nReceiverInterrupt; + #endif + if (this->nTransmitterPin != -1) { + #if not defined( RCSwitchDisableReceiving ) + if (this->nReceiverInterrupt != -1) { + this->disableReceive(); + disabled_Receive = true; + } + #endif + digitalWrite(this->nTransmitterPin, HIGH); + delayMicroseconds( this->nPulseLength * nHighPulses); + digitalWrite(this->nTransmitterPin, LOW); + delayMicroseconds( this->nPulseLength * nLowPulses); + + #if not defined( RCSwitchDisableReceiving ) + if(disabled_Receive){ + this->enableReceive(nReceiverInterrupt_backup); + } + #endif + } +} +/** + * Sends a "0" Bit + * _ + * Waveform Protocol 1: | |___ + * _ + * Waveform Protocol 2: | |__ + */ +void RCSwitch::send0() { + if (this->nProtocol == 1){ + this->transmit(1,3); + } + else if (this->nProtocol == 2) { + this->transmit(1,2); + } + else if (this->nProtocol == 3) { + this->transmit(4,11); + } +} + +/** + * Sends a "1" Bit + * ___ + * Waveform Protocol 1: | |_ + * __ + * Waveform Protocol 2: | |_ + */ +void RCSwitch::send1() { + if (this->nProtocol == 1){ + this->transmit(3,1); + } + else if (this->nProtocol == 2) { + this->transmit(2,1); + } + else if (this->nProtocol == 3) { + this->transmit(9,6); + } +} + + +/** + * Sends a Tri-State "0" Bit + * _ _ + * Waveform: | |___| |___ + */ +void RCSwitch::sendT0() { + this->transmit(1,3); + this->transmit(1,3); +} + +/** + * Sends a Tri-State "1" Bit + * ___ ___ + * Waveform: | |_| |_ + */ +void RCSwitch::sendT1() { + this->transmit(3,1); + this->transmit(3,1); +} + +/** + * Sends a Tri-State "F" Bit + * _ ___ + * Waveform: | |___| |_ + */ +void RCSwitch::sendTF() { + this->transmit(1,3); + this->transmit(3,1); +} + +/** + * Sends a "Sync" Bit + * _ + * Waveform Protocol 1: | |_______________________________ + * _ + * Waveform Protocol 2: | |__________ + */ +void RCSwitch::sendSync() { + + if (this->nProtocol == 1){ + this->transmit(1,31); + } + else if (this->nProtocol == 2) { + this->transmit(1,10); + } + else if (this->nProtocol == 3) { + this->transmit(1,71); + } +} + +#if not defined( RCSwitchDisableReceiving ) +/** + * Enable receiving data + */ +void RCSwitch::enableReceive(int interrupt) { + this->nReceiverInterrupt = interrupt; + this->enableReceive(); +} + +void RCSwitch::enableReceive() { + if (this->nReceiverInterrupt != -1) { + RCSwitch::nReceivedValue = NULL; + RCSwitch::nReceivedBitlength = NULL; + attachInterrupt(this->nReceiverInterrupt, handleInterrupt, CHANGE); + } +} + +/** + * Disable receiving data + */ +void RCSwitch::disableReceive() { + detachInterrupt(this->nReceiverInterrupt); + this->nReceiverInterrupt = -1; +} + +bool RCSwitch::available() { + return RCSwitch::nReceivedValue != NULL; +} + +void RCSwitch::resetAvailable() { + RCSwitch::nReceivedValue = NULL; +} + +unsigned long RCSwitch::getReceivedValue() { + return RCSwitch::nReceivedValue; +} + +unsigned int RCSwitch::getReceivedBitlength() { + return RCSwitch::nReceivedBitlength; +} + +unsigned int RCSwitch::getReceivedDelay() { + return RCSwitch::nReceivedDelay; +} + +unsigned int RCSwitch::getReceivedProtocol() { + return RCSwitch::nReceivedProtocol; +} + +unsigned int* RCSwitch::getReceivedRawdata() { + return RCSwitch::timings; +} + +/** + * + */ +bool RCSwitch::receiveProtocol1(unsigned int changeCount){ + + unsigned long code = 0; + unsigned long delay = RCSwitch::timings[0] / 31; + unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01; + + for (int i = 1; i delay-delayTolerance && RCSwitch::timings[i] < delay+delayTolerance && RCSwitch::timings[i+1] > delay*3-delayTolerance && RCSwitch::timings[i+1] < delay*3+delayTolerance) { + code = code << 1; + } else if (RCSwitch::timings[i] > delay*3-delayTolerance && RCSwitch::timings[i] < delay*3+delayTolerance && RCSwitch::timings[i+1] > delay-delayTolerance && RCSwitch::timings[i+1] < delay+delayTolerance) { + code+=1; + code = code << 1; + } else { + // Failed + i = changeCount; + code = 0; + } + } + code = code >> 1; + if (changeCount > 6) { // ignore < 4bit values as there are no devices sending 4bit values => noise + RCSwitch::nReceivedValue = code; + RCSwitch::nReceivedBitlength = changeCount / 2; + RCSwitch::nReceivedDelay = delay; + RCSwitch::nReceivedProtocol = 1; + } + + if (code == 0){ + return false; + }else if (code != 0){ + return true; + } + + +} + +bool RCSwitch::receiveProtocol2(unsigned int changeCount){ + + unsigned long code = 0; + unsigned long delay = RCSwitch::timings[0] / 10; + unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01; + + for (int i = 1; i delay-delayTolerance && RCSwitch::timings[i] < delay+delayTolerance && RCSwitch::timings[i+1] > delay*2-delayTolerance && RCSwitch::timings[i+1] < delay*2+delayTolerance) { + code = code << 1; + } else if (RCSwitch::timings[i] > delay*2-delayTolerance && RCSwitch::timings[i] < delay*2+delayTolerance && RCSwitch::timings[i+1] > delay-delayTolerance && RCSwitch::timings[i+1] < delay+delayTolerance) { + code+=1; + code = code << 1; + } else { + // Failed + i = changeCount; + code = 0; + } + } + code = code >> 1; + if (changeCount > 6) { // ignore < 4bit values as there are no devices sending 4bit values => noise + RCSwitch::nReceivedValue = code; + RCSwitch::nReceivedBitlength = changeCount / 2; + RCSwitch::nReceivedDelay = delay; + RCSwitch::nReceivedProtocol = 2; + } + + if (code == 0){ + return false; + }else if (code != 0){ + return true; + } + +} + +/** Protocol 3 is used by BL35P02. + * + */ +bool RCSwitch::receiveProtocol3(unsigned int changeCount){ + + unsigned long code = 0; + unsigned long delay = RCSwitch::timings[0] / PROTOCOL3_SYNC_FACTOR; + unsigned long delayTolerance = delay * RCSwitch::nReceiveTolerance * 0.01; + + for (int i = 1; i delay*PROTOCOL3_0_HIGH_CYCLES - delayTolerance + && RCSwitch::timings[i] < delay*PROTOCOL3_0_HIGH_CYCLES + delayTolerance + && RCSwitch::timings[i+1] > delay*PROTOCOL3_0_LOW_CYCLES - delayTolerance + && RCSwitch::timings[i+1] < delay*PROTOCOL3_0_LOW_CYCLES + delayTolerance) { + code = code << 1; + } else if (RCSwitch::timings[i] > delay*PROTOCOL3_1_HIGH_CYCLES - delayTolerance + && RCSwitch::timings[i] < delay*PROTOCOL3_1_HIGH_CYCLES + delayTolerance + && RCSwitch::timings[i+1] > delay*PROTOCOL3_1_LOW_CYCLES - delayTolerance + && RCSwitch::timings[i+1] < delay*PROTOCOL3_1_LOW_CYCLES + delayTolerance) { + code+=1; + code = code << 1; + } else { + // Failed + i = changeCount; + code = 0; + } + } + code = code >> 1; + if (changeCount > 6) { // ignore < 4bit values as there are no devices sending 4bit values => noise + RCSwitch::nReceivedValue = code; + RCSwitch::nReceivedBitlength = changeCount / 2; + RCSwitch::nReceivedDelay = delay; + RCSwitch::nReceivedProtocol = 3; + } + + if (code == 0){ + return false; + }else if (code != 0){ + return true; + } +} + +void RCSwitch::handleInterrupt() { + + static unsigned int duration; + static unsigned int changeCount; + static unsigned long lastTime; + static unsigned int repeatCount; + + + long time = micros(); + duration = time - lastTime; + + if (duration > 5000 && duration > RCSwitch::timings[0] - 200 && duration < RCSwitch::timings[0] + 200) { + repeatCount++; + changeCount--; + if (repeatCount == 2) { + if (receiveProtocol1(changeCount) == false){ + if (receiveProtocol2(changeCount) == false){ + if (receiveProtocol3(changeCount) == false){ + //failed + } + } + } + repeatCount = 0; + } + changeCount = 0; + } else if (duration > 5000) { + changeCount = 0; + } + + if (changeCount >= RCSWITCH_MAX_CHANGES) { + changeCount = 0; + repeatCount = 0; + } + RCSwitch::timings[changeCount++] = duration; + lastTime = time; +} +#endif + +/** + * Turns a decimal value to its binary representation + */ +char* RCSwitch::dec2binWzerofill(unsigned long Dec, unsigned int bitLength){ + return dec2binWcharfill(Dec, bitLength, '0'); +} + +char* RCSwitch::dec2binWcharfill(unsigned long Dec, unsigned int bitLength, char fill){ + static char bin[64]; + unsigned int i=0; + + while (Dec > 0) { + bin[32+i++] = ((Dec & 1) > 0) ? '1' : fill; + Dec = Dec >> 1; + } + + for (unsigned int j = 0; j< bitLength; j++) { + if (j >= bitLength - i) { + bin[j] = bin[ 31 + i - (j - (bitLength - i)) ]; + }else { + bin[j] = fill; + } + } + bin[bitLength] = '\0'; + + return bin; +} + + + diff --git a/lib/RCSwitch/RCSwitch.h b/lib/RCSwitch/RCSwitch.h new file mode 100644 index 0000000..247315a --- /dev/null +++ b/lib/RCSwitch/RCSwitch.h @@ -0,0 +1,144 @@ +/* + RCSwitch - Arduino libary for remote control outlet switches + Copyright (c) 2011 Suat zgr. All right reserved. + + Contributors: + - Andre Koehler / info(at)tomate-online(dot)de + - Gordeev Andrey Vladimirovich / gordeev(at)openpyro(dot)com + - Skineffect / http://forum.ardumote.com/viewtopic.php?f=2&t=46 + - Dominik Fischer / dom_fischer(at)web(dot)de + - Frank Oltmanns / .(at)gmail(dot)com + + Project home: http://code.google.com/p/rc-switch/ + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef _RCSwitch_h +#define _RCSwitch_h + +#if defined(ARDUINO) && ARDUINO >= 100 + #include "Arduino.h" +#elif defined(ENERGIA) // LaunchPad, FraunchPad and StellarPad specific + #include "Energia.h" +#else + #include "WProgram.h" +#endif + + +// At least for the ATTiny X4/X5, receiving has to be disabled due to +// missing libm depencies (udivmodhi4) +#if defined( __AVR_ATtinyX5__ ) or defined ( __AVR_ATtinyX4__ ) +#define RCSwitchDisableReceiving +#endif + +// Number of maximum High/Low changes per packet. +// We can handle up to (unsigned long) => 32 bit * 2 H/L changes per bit + 2 for sync +#define RCSWITCH_MAX_CHANGES 67 + +#define PROTOCOL3_SYNC_FACTOR 71 +#define PROTOCOL3_0_HIGH_CYCLES 4 +#define PROTOCOL3_0_LOW_CYCLES 11 +#define PROTOCOL3_1_HIGH_CYCLES 9 +#define PROTOCOL3_1_LOW_CYCLES 6 + +class RCSwitch { + + public: + RCSwitch(); + + void switchOn(int nGroupNumber, int nSwitchNumber); + void switchOff(int nGroupNumber, int nSwitchNumber); + void switchOn(char* sGroup, int nSwitchNumber); + void switchOff(char* sGroup, int nSwitchNumber); + void switchOn(char sFamily, int nGroup, int nDevice); + void switchOff(char sFamily, int nGroup, int nDevice); + void switchOn(char* sGroup, char* sDevice); + void switchOff(char* sGroup, char* sDevice); + void switchOn(char sGroup, int nDevice); + void switchOff(char sGroup, int nDevice); + + void sendTriState(char* Code); + void send(unsigned long Code, unsigned int length); + void send(char* Code); + + #if not defined( RCSwitchDisableReceiving ) + void enableReceive(int interrupt); + void enableReceive(); + void disableReceive(); + bool available(); + void resetAvailable(); + + unsigned long getReceivedValue(); + unsigned int getReceivedBitlength(); + unsigned int getReceivedDelay(); + unsigned int getReceivedProtocol(); + unsigned int* getReceivedRawdata(); + #endif + + void enableTransmit(int nTransmitterPin); + void disableTransmit(); + void setPulseLength(int nPulseLength); + void setRepeatTransmit(int nRepeatTransmit); + #if not defined( RCSwitchDisableReceiving ) + void setReceiveTolerance(int nPercent); + #endif + void setProtocol(int nProtocol); + void setProtocol(int nProtocol, int nPulseLength); + + private: + char* getCodeWordB(int nGroupNumber, int nSwitchNumber, boolean bStatus); + char* getCodeWordA(char* sGroup, int nSwitchNumber, boolean bStatus); + char* getCodeWordA(char* sGroup, char* sDevice, boolean bStatus); + char* getCodeWordC(char sFamily, int nGroup, int nDevice, boolean bStatus); + char* getCodeWordD(char group, int nDevice, boolean bStatus); + void sendT0(); + void sendT1(); + void sendTF(); + void send0(); + void send1(); + void sendSync(); + void transmit(int nHighPulses, int nLowPulses); + + static char* dec2binWzerofill(unsigned long dec, unsigned int length); + static char* dec2binWcharfill(unsigned long dec, unsigned int length, char fill); + + #if not defined( RCSwitchDisableReceiving ) + static void handleInterrupt(); + static bool receiveProtocol1(unsigned int changeCount); + static bool receiveProtocol2(unsigned int changeCount); + static bool receiveProtocol3(unsigned int changeCount); + int nReceiverInterrupt; + #endif + int nTransmitterPin; + int nPulseLength; + int nRepeatTransmit; + char nProtocol; + + #if not defined( RCSwitchDisableReceiving ) + static int nReceiveTolerance; + static unsigned long nReceivedValue; + static unsigned int nReceivedBitlength; + static unsigned int nReceivedDelay; + static unsigned int nReceivedProtocol; + #endif + /* + * timings[0] contains sync timing, followed by a number of bits + */ + static unsigned int timings[RCSWITCH_MAX_CHANGES]; + + +}; + +#endif diff --git a/lib/RCSwitch/examples/ReceiveDemo_Advanced/ReceiveDemo_Advanced.pde b/lib/RCSwitch/examples/ReceiveDemo_Advanced/ReceiveDemo_Advanced.pde new file mode 100644 index 0000000..89cbbc9 --- /dev/null +++ b/lib/RCSwitch/examples/ReceiveDemo_Advanced/ReceiveDemo_Advanced.pde @@ -0,0 +1,24 @@ +/* + Example for receiving + + http://code.google.com/p/rc-switch/ + + If you want to visualize a telegram copy the raw data and + paste it into http://test.sui.li/oszi/ +*/ + +#include + +RCSwitch mySwitch = RCSwitch(); + +void setup() { + Serial.begin(9600); + mySwitch.enableReceive(0); // Receiver on inerrupt 0 => that is pin #2 +} + +void loop() { + if (mySwitch.available()) { + output(mySwitch.getReceivedValue(), mySwitch.getReceivedBitlength(), mySwitch.getReceivedDelay(), mySwitch.getReceivedRawdata(),mySwitch.getReceivedProtocol()); + mySwitch.resetAvailable(); + } +} diff --git a/lib/RCSwitch/examples/ReceiveDemo_Advanced/helperfunctions.ino b/lib/RCSwitch/examples/ReceiveDemo_Advanced/helperfunctions.ino new file mode 100644 index 0000000..56f3c0c --- /dev/null +++ b/lib/RCSwitch/examples/ReceiveDemo_Advanced/helperfunctions.ino @@ -0,0 +1,20 @@ +static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength){ + static char bin[64]; + unsigned int i=0; + + while (Dec > 0) { + bin[32+i++] = (Dec & 1 > 0) ? '1' : '0'; + Dec = Dec >> 1; + } + + for (unsigned int j = 0; j< bitLength; j++) { + if (j >= bitLength - i) { + bin[j] = bin[ 31 + i - (j - (bitLength - i)) ]; + }else { + bin[j] = '0'; + } + } + bin[bitLength] = '\0'; + + return bin; +} diff --git a/lib/RCSwitch/examples/ReceiveDemo_Advanced/output.ino b/lib/RCSwitch/examples/ReceiveDemo_Advanced/output.ino new file mode 100644 index 0000000..b8b8cf8 --- /dev/null +++ b/lib/RCSwitch/examples/ReceiveDemo_Advanced/output.ino @@ -0,0 +1,52 @@ +void output(unsigned long decimal, unsigned int length, unsigned int delay, unsigned int* raw, unsigned int protocol) { + + if (decimal == 0) { + Serial.print("Unknown encoding."); + } else { + char* b = dec2binWzerofill(decimal, length); + Serial.print("Decimal: "); + Serial.print(decimal); + Serial.print(" ("); + Serial.print( length ); + Serial.print("Bit) Binary: "); + Serial.print( b ); + Serial.print(" Tri-State: "); + Serial.print( bin2tristate( b) ); + Serial.print(" PulseLength: "); + Serial.print(delay); + Serial.print(" microseconds"); + Serial.print(" Protocol: "); + Serial.println(protocol); + } + + Serial.print("Raw data: "); + for (int i=0; i<= length*2; i++) { + Serial.print(raw[i]); + Serial.print(","); + } + Serial.println(); + Serial.println(); +} + + +static char* bin2tristate(char* bin) { + char returnValue[50]; + int pos = 0; + int pos2 = 0; + while (bin[pos]!='\0' && bin[pos+1]!='\0') { + if (bin[pos]=='0' && bin[pos+1]=='0') { + returnValue[pos2] = '0'; + } else if (bin[pos]=='1' && bin[pos+1]=='1') { + returnValue[pos2] = '1'; + } else if (bin[pos]=='0' && bin[pos+1]=='1') { + returnValue[pos2] = 'F'; + } else { + return "not applicable"; + } + pos = pos+2; + pos2++; + } + returnValue[pos2] = '\0'; + return returnValue; +} + diff --git a/lib/RCSwitch/examples/ReceiveDemo_Simple/ReceiveDemo_Simple.pde b/lib/RCSwitch/examples/ReceiveDemo_Simple/ReceiveDemo_Simple.pde new file mode 100644 index 0000000..b55e5d7 --- /dev/null +++ b/lib/RCSwitch/examples/ReceiveDemo_Simple/ReceiveDemo_Simple.pde @@ -0,0 +1,35 @@ +/* + Simple example for receiving + + http://code.google.com/p/rc-switch/ +*/ + +#include + +RCSwitch mySwitch = RCSwitch(); + +void setup() { + Serial.begin(9600); + mySwitch.enableReceive(0); // Receiver on inerrupt 0 => that is pin #2 +} + +void loop() { + if (mySwitch.available()) { + + int value = mySwitch.getReceivedValue(); + + if (value == 0) { + Serial.print("Unknown encoding"); + } else { + Serial.print("Received "); + Serial.print( mySwitch.getReceivedValue() ); + Serial.print(" / "); + Serial.print( mySwitch.getReceivedBitlength() ); + Serial.print("bit "); + Serial.print("Protocol: "); + Serial.println( mySwitch.getReceivedProtocol() ); + } + + mySwitch.resetAvailable(); + } +} diff --git a/lib/RCSwitch/examples/SendDemo/SendDemo.pde b/lib/RCSwitch/examples/SendDemo/SendDemo.pde new file mode 100644 index 0000000..9ee54ce --- /dev/null +++ b/lib/RCSwitch/examples/SendDemo/SendDemo.pde @@ -0,0 +1,57 @@ +/* + Example for different sending methods + + http://code.google.com/p/rc-switch/ + +*/ + +#include + +RCSwitch mySwitch = RCSwitch(); + +void setup() { + + Serial.begin(9600); + + // Transmitter is connected to Arduino Pin #10 + mySwitch.enableTransmit(10); + + // Optional set pulse length. + // mySwitch.setPulseLength(320); + + // Optional set protocol (default is 1, will work for most outlets) + // mySwitch.setProtocol(2); + + // Optional set number of transmission repetitions. + // mySwitch.setRepeatTransmit(15); + +} + +void loop() { + + /* See Example: TypeA_WithDIPSwitches */ + mySwitch.switchOn("11111", "00010"); + delay(1000); + mySwitch.switchOn("11111", "00010"); + delay(1000); + + /* Same switch as above, but using decimal code */ + mySwitch.send(5393, 24); + delay(1000); + mySwitch.send(5396, 24); + delay(1000); + + /* Same switch as above, but using binary code */ + mySwitch.send("000000000001010100010001"); + delay(1000); + mySwitch.send("000000000001010100010100"); + delay(1000); + + /* Same switch as above, but tri-state code */ + mySwitch.sendTriState("00000FFF0F0F"); + delay(1000); + mySwitch.sendTriState("00000FFF0FF0"); + delay(1000); + + delay(20000); +} diff --git a/lib/RCSwitch/examples/TypeA_WithDIPSwitches/TypeA_WithDIPSwitches.pde b/lib/RCSwitch/examples/TypeA_WithDIPSwitches/TypeA_WithDIPSwitches.pde new file mode 100644 index 0000000..b362151 --- /dev/null +++ b/lib/RCSwitch/examples/TypeA_WithDIPSwitches/TypeA_WithDIPSwitches.pde @@ -0,0 +1,40 @@ +/* + Example for outlets which are configured with a 10 pole DIP switch. + + http://code.google.com/p/rc-switch/ +*/ + +#include + +RCSwitch mySwitch = RCSwitch(); + +void setup() { + + // Transmitter is connected to Arduino Pin #10 + mySwitch.enableTransmit(10); + + // Optional set pulse length. + // mySwitch.setPulseLength(320); + +} + +void loop() { + + // Switch on: + // The first parameter represents the setting of the first 5 DIP switches. + // In this example it's ON-ON-OFF-OFF-ON. + // + // The second parameter represents the setting of the last 5 DIP switches. + // In this example the last 5 DIP switches are OFF-ON-OFF-ON-OFF. + mySwitch.switchOn("11001", "01010"); + + // Wait a second + delay(1000); + + // Switch off + mySwitch.switchOff("11001", "01010"); + + // Wait another second + delay(1000); + +} diff --git a/lib/RCSwitch/examples/TypeA_WithDIPSwitches_Lightweight/TypeA_WithDIPSwitches_Lightweight.ino b/lib/RCSwitch/examples/TypeA_WithDIPSwitches_Lightweight/TypeA_WithDIPSwitches_Lightweight.ino new file mode 100644 index 0000000..5796624 --- /dev/null +++ b/lib/RCSwitch/examples/TypeA_WithDIPSwitches_Lightweight/TypeA_WithDIPSwitches_Lightweight.ino @@ -0,0 +1,43 @@ +/* + This is a minimal sketch without using the library at all but only works for + the 10 pole dip switch sockets. It saves a lot of memory and thus might be + very useful to use with ATTinys :) + + http://code.google.com/p/rc-switch/ +*/ + +int RCLpin = 7; + +void setup() { + pinMode(RCLpin, OUTPUT); +} + +void loop() { + RCLswitch(0b010001000001); // DIPs an Steckdose: 0100010000 An:01 + delay(2000); + + RCLswitch(0b010001000010); // DIPs an Steckdose: 0100010000 Aus:10 + delay(2000); +} + +void RCLswitch(uint16_t code) { + for (int nRepeat=0; nRepeat<6; nRepeat++) { + for (int i=4; i<16; i++) { + RCLtransmit(1,3); + if (((code << (i-4)) & 2048) > 0) { + RCLtransmit(1,3); + } else { + RCLtransmit(3,1); + } + } + RCLtransmit(1,31); + } +} + +void RCLtransmit(int nHighPulses, int nLowPulses) { + digitalWrite(RCLpin, HIGH); + delayMicroseconds( 350 * nHighPulses); + digitalWrite(RCLpin, LOW); + delayMicroseconds( 350 * nLowPulses); +} + diff --git a/lib/RCSwitch/examples/TypeB_WithRotaryOrSlidingSwitches/TypeB_WithRotaryOrSlidingSwitches.pde b/lib/RCSwitch/examples/TypeB_WithRotaryOrSlidingSwitches/TypeB_WithRotaryOrSlidingSwitches.pde new file mode 100644 index 0000000..61e0d76 --- /dev/null +++ b/lib/RCSwitch/examples/TypeB_WithRotaryOrSlidingSwitches/TypeB_WithRotaryOrSlidingSwitches.pde @@ -0,0 +1,40 @@ +/* + Example for outlets which are configured with two rotary/sliding switches. + + http://code.google.com/p/rc-switch/ +*/ + +#include + +RCSwitch mySwitch = RCSwitch(); + +void setup() { + + // Transmitter is connected to Arduino Pin #10 + mySwitch.enableTransmit(10); + + // Optional set pulse length. + // mySwitch.setPulseLength(320); + +} + +void loop() { + + // Switch on: + // The first parameter represents the setting of the first rotary switch. + // In this example it's switched to "1" or "A" or "I". + // + // The second parameter represents the setting of the second rotary switch. + // In this example it's switched to "4" or "D" or "IV". + mySwitch.switchOn(1, 4); + + // Wait a second + delay(1000); + + // Switch off + mySwitch.switchOff(1, 4); + + // Wait another second + delay(1000); + +} diff --git a/lib/RCSwitch/examples/TypeC_Intertechno/TypeC_Intertechno.pde b/lib/RCSwitch/examples/TypeC_Intertechno/TypeC_Intertechno.pde new file mode 100644 index 0000000..012a93a --- /dev/null +++ b/lib/RCSwitch/examples/TypeC_Intertechno/TypeC_Intertechno.pde @@ -0,0 +1,40 @@ +/* + Example for Intertechno outlets + + http://code.google.com/p/rc-switch/ +*/ + +#include + +RCSwitch mySwitch = RCSwitch(); + +void setup() { + + // Transmitter is connected to Arduino Pin #10 + mySwitch.enableTransmit(10); + + // Optional set pulse length. + // mySwitch.setPulseLength(320); + +} + +void loop() { + + // Switch on: + // The first parameter represents the familycode (a, b, c, ... f) + // The second parameter represents the group number + // The third parameter represents the device number + // + // In this example it's family 'b', group #3, device #2 + mySwitch.switchOn('b', 3, 2); + + // Wait a second + delay(1000); + + // Switch off + mySwitch.switchOff('b', 3, 2); + + // Wait another second + delay(1000); + +} \ No newline at end of file diff --git a/lib/RCSwitch/examples/TypeD_REV/TypeD_REV.ino b/lib/RCSwitch/examples/TypeD_REV/TypeD_REV.ino new file mode 100644 index 0000000..446bc8a --- /dev/null +++ b/lib/RCSwitch/examples/TypeD_REV/TypeD_REV.ino @@ -0,0 +1,41 @@ +/* + Example for REV outlets (e.g. 8342L) + + http://code.google.com/p/rc-switch/ + + Need help? http://forum.ardumote.com +*/ + +#include + +RCSwitch mySwitch = RCSwitch(); + +void setup() { + + // Transmitter is connected to Arduino Pin #10 + mySwitch.enableTransmit(10); + + // set pulse length. + mySwitch.setPulseLength(360); + +} + +void loop() { + + // Switch on: + // The first parameter represents the channel (a, b, c, d) + // The second parameter represents the device number + // + // In this example it's family 'd', device #2 + mySwitch.switchOn('d', 2); + + // Wait a second + delay(1000); + + // Switch off + mySwitch.switchOff('d', 2); + + // Wait another second + delay(1000); + +} diff --git a/lib/RCSwitch/examples/Webserver/Webserver.pde b/lib/RCSwitch/examples/Webserver/Webserver.pde new file mode 100644 index 0000000..ee2c74a --- /dev/null +++ b/lib/RCSwitch/examples/Webserver/Webserver.pde @@ -0,0 +1,154 @@ +/* + A simple RCSwitch/Ethernet/Webserver demo + + http://code.google.com/p/rc-switch/ +*/ + +#include +#include +#include + +// Ethernet configuration +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // MAC Address +byte ip[] = { 192,168,0, 2 }; // IP Address +EthernetServer server(80); // Server Port 80 + +// RCSwitch configuration +RCSwitch mySwitch = RCSwitch(); +int RCTransmissionPin = 7; + +// More to do... +// You should also modify the processCommand() and +// httpResponseHome() functions to fit your needs. + + + +/** + * Setup + */ +void setup() { + Ethernet.begin(mac, ip); + server.begin(); + mySwitch.enableTransmit( RCTransmissionPin ); +} + +/** + * Loop + */ +void loop() { + char* command = httpServer(); +} + +/** + * Command dispatcher + */ +void processCommand(char* command) { + if (strcmp(command, "1-on") == 0) { + mySwitch.switchOn(1,1); + } else if (strcmp(command, "1-off") == 0) { + mySwitch.switchOff(1,1); + } else if (strcmp(command, "2-on") == 0) { + mySwitch.switchOn(1,2); + } else if (strcmp(command, "2-off") == 0) { + mySwitch.switchOff(1,2); + } +} + +/** + * HTTP Response with homepage + */ +void httpResponseHome(EthernetClient c) { + c.println("HTTP/1.1 200 OK"); + c.println("Content-Type: text/html"); + c.println(); + c.println(""); + c.println(""); + c.println( "RCSwitch Webserver Demo"); + c.println( ""); + c.println(""); + c.println(""); + c.println( "

RCSwitch Webserver Demo

"); + c.println( ""); + c.println( ""); + c.println( "
"); + c.println( "http://code.google.com/p/rc-switch/"); + c.println(""); + c.println(""); +} + +/** + * HTTP Redirect to homepage + */ +void httpResponseRedirect(EthernetClient c) { + c.println("HTTP/1.1 301 Found"); + c.println("Location: /"); + c.println(); +} + +/** + * HTTP Response 414 error + * Command must not be longer than 30 characters + **/ +void httpResponse414(EthernetClient c) { + c.println("HTTP/1.1 414 Request URI too long"); + c.println("Content-Type: text/plain"); + c.println(); + c.println("414 Request URI too long"); +} + +/** + * Process HTTP requests, parse first request header line and + * call processCommand with GET query string (everything after + * the ? question mark in the URL). + */ +char* httpServer() { + EthernetClient client = server.available(); + if (client) { + char sReturnCommand[32]; + int nCommandPos=-1; + sReturnCommand[0] = '\0'; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + if ((c == '\n') || (c == ' ' && nCommandPos>-1)) { + sReturnCommand[nCommandPos] = '\0'; + if (strcmp(sReturnCommand, "\0") == 0) { + httpResponseHome(client); + } else { + processCommand(sReturnCommand); + httpResponseRedirect(client); + } + break; + } + if (nCommandPos>-1) { + sReturnCommand[nCommandPos++] = c; + } + if (c == '?' && nCommandPos == -1) { + nCommandPos = 0; + } + } + if (nCommandPos > 30) { + httpResponse414(client); + sReturnCommand[0] = '\0'; + break; + } + } + if (nCommandPos!=-1) { + sReturnCommand[nCommandPos] = '\0'; + } + // give the web browser time to receive the data + delay(1); + client.stop(); + + return sReturnCommand; + } + return '\0'; +} \ No newline at end of file diff --git a/lib/RCSwitch/keywords.txt b/lib/RCSwitch/keywords.txt new file mode 100644 index 0000000..2474367 --- /dev/null +++ b/lib/RCSwitch/keywords.txt @@ -0,0 +1,57 @@ +####################################### +# Syntax Coloring Map For RCSwitch +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +RCSwitch KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +########## +#SENDS Begin +########## +switchOn KEYWORD2 +switchOff KEYWORD2 +sendTriState KEYWORD2 +send KEYWORD2 +########## +#SENDS End +########## + +########## +#RECEIVE Begin +########## +enableReceive KEYWORD2 +disableReceive KEYWORD2 +available KEYWORD2 +resetAvailable KEYWORD2 +setReceiveTolerance KEYWORD2 +getReceivedValue KEYWORD2 +getReceivedBitlength KEYWORD2 +getReceivedDelay KEYWORD2 +getReceivedProtocol KEYWORD2 +getReceivedRawdata KEYWORD2 +########## +#RECEIVE End +########## + +########## +#OTHERS Begin +########## +enableTransmit KEYWORD2 +disableTransmit KEYWORD2 +setPulseLength KEYWORD2 +setProtocol KEYWORD2 +setRepeatTransmit KEYWORD2 +########## +#OTHERS End +########## + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/lib/ST_Anything/Constants.cpp b/lib/ST_Anything/Constants.cpp new file mode 100644 index 0000000..b564115 --- /dev/null +++ b/lib/ST_Anything/Constants.cpp @@ -0,0 +1,12 @@ +#include "Constants.h" + + +namespace st +{ +//private + + +//public + + +} \ No newline at end of file diff --git a/lib/ST_Anything/Constants.h b/lib/ST_Anything/Constants.h new file mode 100644 index 0000000..a0831ed --- /dev/null +++ b/lib/ST_Anything/Constants.h @@ -0,0 +1,154 @@ +//****************************************************************************************** +// File: Constants.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: This file contains a number of user-definable settings that affect the +// ST_Anything library. This is the main file where user specific settings +// should be made to adjust the behavior of SmartThings Shield communications. +// +// Notes: +// -The SmartThings Shield uses Pins 0,1 or Pins 2,3 for serial communications based +// on the user selectable switch on the shield. +// -The SmartThings Shield reserves Pin 6 as well. Best to avoid using it. +// -The Arduino UNO R3 defaults to using the SoftwareSerial library since the UNO has +// only one Hardware UART port ("Serial") which is used by the USB port for +// programming and debugging typically. +// -You can use Hardware Serial with an UNO or Leonardo if desired, but you must suppress +// all "Serial.Print()" calls in your sketch, and make sure your Serial.begin() call +// is suppressed or set to use 2400 baud. +// -Arduino MEGA defaults to using the MEGA's "Serial3" Hardware UART serial port. +// This port uses pins 14(Tx) and 15(Rx). Wire Pin14 to Pin2 and Pin15 to Pin3. +// Be certain to not use Pins 2 & 3 in your Arduino sketch since they are still +// electrically connected to the ThingShield. +// -The SoftwareSerial library has the following known limitations: +// -If using multiple software serial ports, only one can receive data at a time. +// - Not all pins on the Mega and Mega 2560 support change interrupts, so only +// the following can be used for RX: 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, +// A8(62), A9(63), A10(64), A11(65), A12(66), A13(67), A14(68), A15(69). +// - Not all pins on the Leonardo and Micro support change interrupts, so only +// the following can be used for RX : 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-03-28 Dan Ogorchock Change the default DEV_REFRESH_INTERVAL to 300 seconds. Was interfering with normal operations. +// Added SENDSTRINGS_INTERVAL to throttle the rate at which data is sent to the ThingShield. Events were being missed. +// Added DISABLE_REFRESH feature - commented out by default. Allows user to disable the automatic refresh feature as it can interfere with normal operations. +// Adjusted MAX Sensor and Executor counts for the Arduino MEGA to allow 16 relay system to function properly. +// 2016-06-04 Dan Ogorchock Added improved support for Arduino Leonardo +// 2017-02-07 Dan Ogorchock Added support for new SmartThings v2.0 library (ThingShield, W5100, ESP8266) +// 2017-08-14 Dan Ogorchock Added support for ESP32 +// +//****************************************************************************************** + +#ifndef ST_CONSTANTS_H +#define ST_CONSTANTS_H + +//#include "Arduino.h" +#include "SmartThings.h" + +//#define ENABLE_SERIAL //If uncommented, will allow you to type in commands via the Arduino Serial Console Window (useful for debugging) +//#define DISABLE_SMARTTHINGS //If uncommented, will disable all ST Shield Library calls (e.g. you want to use this library without SmartThings for a different application) +//#define DISABLE_REFRESH //If uncommented, will disable periodic refresh of the sensors and executors states to the ST Cloud - improves performance, but may reduce data integrity + +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(ARDUINO_AVR_UNO) +#define BOARD_UNO +#elif defined(__AVR_ATmega32U4__) || defined(ARDUINO_AVR_LEONARDO) +#define BOARD_LEONARDO +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(ARDUINO_AVR_MEGA2560) +#define BOARD_MEGA +#elif defined(ARDUINO_ARCH_SAMD) +#define BOARD_MKR1000 +#elif defined(ARDUINO_ARCH_ESP8266) +#define BOARD_ESP8266 +#elif defined(ARDUINO_ARCH_ESP32) +#define BOARD_ESP32 +#else +#define BOARD_UNO //assume user is using an UNO for the unknown case +#endif + +namespace st +{ + class Constants + { + public: + //Max name length (including null terminator!) + static const byte MAX_NAME_LENGTH=30; + + //Serial debug console baud rate + static const unsigned long SERIAL_BAUDRATE=115200; //Uncomment If NOT using pins 0,1 for ST Shield communications (default) + //static const unsigned int SERIAL_BAUDRATE=2400; //Uncomment if using Pins 0,1 for ST Shield Communications + #if defined(BOARD_MEGA) || defined(BOARD_MKR1000) || defined(BOARD_ESP8266) || defined(BOARD_ESP32) + //Maximum number of SENSOR objects + static const byte MAX_SENSOR_COUNT=30; //Used to limit the number of sensor devices allowed. Be careful on Arduino UNO due to 2K SRAM limitation + //Maximum number of EXECUTOR objects + static const byte MAX_EXECUTOR_COUNT=20; //Used to limit the number of executor devices allowed. Be careful on Arduino UNO due to 2K SRAM limitation + #else + //Maximum number of SENSOR objects + static const byte MAX_SENSOR_COUNT = 10; //Used to limit the number of sensor devices allowed. Be careful on Arduino UNO due to 2K SRAM limitation + //Maximum number of EXECUTOR objects + static const byte MAX_EXECUTOR_COUNT = 10; //Used to limit the number of executor devices allowed. Be careful on Arduino UNO due to 2K SRAM limitation + #endif + //Size of reserved return string + static const byte RETURN_STRING_RESERVE = (MAX_SENSOR_COUNT + MAX_EXECUTOR_COUNT) * 5; //Do not make too large due to UNO's 2K SRAM limitation + //Interval on which Device's refresh methods are called (in seconds) - most useful for Executors and InterruptSensors - only works if DISABLE_REFRESH is not defined above + static const int DEV_REFRESH_INTERVAL=300; //seconds - Used to make sure the ST Cloud is kept current with device status (in case of missed updates to the ST Cloud) - primarily for Executors and InterruptSensors - only works if DISABLE_REFRESH is not defined above + + //NOTE: The following constant was removed and replaced by a user defineable interval in the SmartThings library constaructors to permit different values for each communication method (i.e. ThingShield requires 1000ms, whereas Ethernet is ~100ms) + //Minumum interval between sending packets of data to ThingShield (in milliseconds) - noticed issue where ST Hub/Cloud could not keep up with rapid data transfer + //static const int SENDSTRINGS_INTERVAL = 100; + // ------------------------------------------------------------------------------- + // --- SmartThings specific items + // ------------------------------------------------------------------------------- + + //--- if true, the sketch will stall until the ST ThingShield has joined the ST Hub (set to false for debugging without a ST ThingShield, but with SmartThings code still enabled) + static const bool WAIT_FOR_JOIN_AT_START = true; + + //Select whether to use Hardware or Software Serial Communications - will result in the correct SmartThings constructor being called in Everything.cpp + //#if defined(BOARD_UNO) + // #define ST_SOFTWARE_SERIAL //Use Software Serial for UNO by default + // //#define ST_HARDWARE_SERIAL + //#elif defined(BOARD_MEGA) || defined(BOARD_LEONARDO) + // //#define ST_SOFTWARE_SERIAL + // #define ST_HARDWARE_SERIAL //Use Hardware Serial for MEGA or LEONARDO by default + //#else + // #define ST_SOFTWARE_SERIAL + // //#define ST_HARDWARE_SERIAL + //#endif + + //--- + //--- if using SoftwareSerial + //--- -set the following based on the pins you desire + //--- -NOTE: you must use the SoftwareSerial version of the SmartThings Constructor + //--- + //#if defined(BOARD_UNO) + // static const uint8_t pinRX = 3; //Rx Pin3 - works for UNO R3, but not for Leonardo or Mega + //#else + // static const uint8_t pinRX = 10; //Rx Pin10 - works for Leonardo or Mega - You MUST jumper Pin10 to Pin3 - do not use Pin3 or Pin10 in your sketch! + //#endif + // + // static const uint8_t pinTX = 2; //Tx Pin2 - works for UNO R3, Leonardo, and Mega + + //--- + //--- if using Hardware Serial + //--- -set the following based on the pins you desire (HW_SERIAL, Mega Only(HW_SERIAL1, HW_SERIAL2, HW_SERIAL3)) + //--- -NOTE: you must use the HardwareSerial version of the SmartThings Constructor + //--- + //#if defined(BOARD_UNO) + // static const SmartThingsSerialType_t SERIAL_TYPE = HW_SERIAL; //UNO - You MUST move ThingShield switch to D0/D1 position after loading program and then reset the Arduino + //#elif defined(BOARD_LEONARDO) + // static const SmartThingsSerialType_t SERIAL_TYPE = HW_SERIAL1; //Leonardo - You MUST move ThingShield switch to D0/D1 position + //#elif defined(BOARD_MEGA) + // //static const SmartThingsSerialType_t SERIAL_TYPE = HW_SERIAL; //MEGA - You MUST move ThingShield switch to D0/D1 position after loading program and then reset the Arduino + // //static const SmartThingsSerialType_t SERIAL_TYPE = HW_SERIAL1; //MEGA - You MUST jumper Pin18 to Pin2 AND Pin19 to Pin3 - do not use Pin2 or Pin3 in your sketch! + // //static const SmartThingsSerialType_t SERIAL_TYPE = HW_SERIAL2; //MEGA - You MUST jumper Pin16 to Pin2 AND Pin17 to Pin3 - do not use Pin2 or Pin3 in your sketch! + // static const SmartThingsSerialType_t SERIAL_TYPE = HW_SERIAL3; //MEGA - You MUST jumper Pin14 to Pin2 AND Pin15 to Pin3 - do not use Pin2 or Pin3 in your sketch! + //#endif + // ------------------------------------------------------------------------------- + }; +} + + +#endif \ No newline at end of file diff --git a/lib/ST_Anything/Device.cpp b/lib/ST_Anything/Device.cpp new file mode 100644 index 0000000..0126eeb --- /dev/null +++ b/lib/ST_Anything/Device.cpp @@ -0,0 +1,68 @@ +//****************************************************************************************** +// File: Device.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: st::Device is the highest level generic class for either a st::Sensor or +// st::Executor subclass. +// In general, this file should not need to be modified. +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2018-08-15 Dan Ogorchock Workaround for strcpy_P() ESP32 crash bug +// +//****************************************************************************************** + +#include "Device.h" +#include "Everything.h" +#include "Constants.h" + +namespace st +{ +//private + +//public + //constructor + Device::Device(const __FlashStringHelper *name): + m_pName(name) + { + if(debug) + { + Serial.print(F("Device: New Device ID: ")); + Serial.println(getName()); + } + } + + //destructor + Device::~Device() + { + if(debug) + { + Serial.print(F("Device: Destroyed Device ID: ")); + Serial.println(getName()); + } + } + + void Device::refresh() + { + + } + + const String Device::getName() const + { +#if defined(ARDUINO_ARCH_ESP32) + return String((const char*)m_pName); //strcpy_P() causes ESP32 to crash +#else + char tmp[Constants::MAX_NAME_LENGTH]; + strcpy_P(tmp, (const char*)m_pName); + return String(tmp); +#endif + + } + + + //debug flag to determine if debug print statements are executed (set value in your sketch) + bool Device::debug=false; +} \ No newline at end of file diff --git a/lib/ST_Anything/Device.h b/lib/ST_Anything/Device.h new file mode 100644 index 0000000..93766f8 --- /dev/null +++ b/lib/ST_Anything/Device.h @@ -0,0 +1,57 @@ +//****************************************************************************************** +// File: Device.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: st::Device is the highest level generic class for either a st::Sensor or +// st::Executor subclass. +// In general, this file should not need to be modified. +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2019-02-09 Dan Ogorchock Moved update() from Sensor to Device +// +// +//****************************************************************************************** + +#ifndef ST_DEVICE_H +#define ST_DEVICE_H + +#include +//#include + +namespace st +{ + class Device + { + private: + const __FlashStringHelper *m_pName; + + public: + //constructor + Device(const __FlashStringHelper *name); + + //destructor + virtual ~Device(); + + //initialization routine - This pure virtual function must be implemented by all derived classes + virtual void init()=0; + virtual void update() = 0; + + //function used by all devices to process data from SmartThings Shield - all derived classes must implement this pure virtual function + virtual void beSmart(const String &str)=0; + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of each Device subclass object + virtual void refresh(); + + //gets + const String getName() const; + + //debug flag to determine if debug print statements are executed (set value in your sketch) + static bool debug; + }; +} + +#endif \ No newline at end of file diff --git a/lib/ST_Anything/EX_Alarm.cpp b/lib/ST_Anything/EX_Alarm.cpp new file mode 100644 index 0000000..08d3527 --- /dev/null +++ b/lib/ST_Anything/EX_Alarm.cpp @@ -0,0 +1,191 @@ +//****************************************************************************************** +// File: EX_Alarm.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: EX_Alarm is a class which implements the SmartThings "Alarm" device capability. +// It inherits from the st::PollingSensor class. The current version implements the Siren as +// a digital output (uses a relay to switch the Siren on or off) +// +// TODO: Possibly add Strobe capability in the future +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_Alarm executor2(F("alarm1"), PIN_ALARM, LOW, true, PIN_STROBE); +// +// st::EX_Alarm() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic +// - byte pinStrobe - OPTOINAL - If supplied, will allow separate SIREN and STROBE outputs +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2017-04-20 Dan Ogorchock Add optional Strobe functionality +// 2017-04-26 Dan Ogorchock Improved Logic if Strobe pin not defined +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// +// +//****************************************************************************************** + +#include "EX_Alarm.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ + //private + void EX_Alarm::writeStateToPin() + { + if (m_nCurrentAlarmState == both) { + digitalWrite(m_nPin, m_bInvertLogic ? LOW : HIGH); + if (m_bUseStrobe) { digitalWrite(m_nPinStrobe, m_bInvertLogic ? LOW : HIGH); } + } + else if(m_nCurrentAlarmState == siren) { + digitalWrite(m_nPin, m_bInvertLogic ? LOW : HIGH); + if (m_bUseStrobe) { digitalWrite(m_nPinStrobe, m_bInvertLogic ? HIGH : LOW); } + } + else if(m_nCurrentAlarmState == strobe) { + digitalWrite(m_nPin, m_bInvertLogic ? HIGH : LOW); + if (m_bUseStrobe) { digitalWrite(m_nPinStrobe, m_bInvertLogic ? LOW : HIGH); } + } + else if(m_nCurrentAlarmState == off) { + digitalWrite(m_nPin, m_bInvertLogic ? HIGH : LOW); + if (m_bUseStrobe) { digitalWrite(m_nPinStrobe, m_bInvertLogic ? HIGH : LOW); } + } + + } + + //public + //constructor + EX_Alarm::EX_Alarm(const __FlashStringHelper *name, byte pin, bool startingState, bool invertLogic, byte pinStrobe) : + Executor(name), + m_nPin(pin), + m_bInvertLogic(invertLogic), + m_nPinStrobe(pinStrobe) + { + m_nCurrentAlarmState = off; + m_bUseStrobe = false; + + setPin(pin); + //If user has supplied a pin for Strobe Light + if (pinStrobe < 255) { + m_bUseStrobe = true; + setPin(pinStrobe); + } + //else + //{ + // m_bUseStrobe = false; + //} + + + } + + //destructor + EX_Alarm::~EX_Alarm() + { + + } + + //initialization routine + void EX_Alarm::init() + { + refresh(); //update ST Cloud with initial data + } + + //called periodically to ensure state of the Alarm Siren is up to date in the SmartThings Cloud (in case an event is missed) + void EX_Alarm::refresh() + { + //if (debug) { + // Serial.print(F("EX_Alarm:: UseStrobe = ")); + // Serial.println(m_bUseStrobe); + //} + + if (m_nCurrentAlarmState == both) { + Everything::sendSmartString(getName() + F(" both")); + } + else if(m_nCurrentAlarmState == siren) { + Everything::sendSmartString(getName() + F(" siren")); + } + else if(m_nCurrentAlarmState == strobe) { + Everything::sendSmartString(getName() + F(" strobe")); + } + else if(m_nCurrentAlarmState == off) { + //else { + Everything::sendSmartString(getName() + F(" off")); + } + } + + //SmartThings Shield data handler (receives command to turn "both" or "off" the Alarm (digital output) + void EX_Alarm::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (debug) { + Serial.print(F("EX_Alarm::beSmart s = ")); + Serial.println(s); + } + + //if (m_bUseStrobe) { + if (s == F("both")) { + if (m_bUseStrobe) { + m_nCurrentAlarmState = both; + } + else { + m_nCurrentAlarmState = siren; + if (debug) { + Serial.println(F("EX_Alarm::beSmart - Strobe Pin not defined. Defaulting to Siren!")); + } + + } + } + else if(s == F("siren")) { + m_nCurrentAlarmState = siren; + } + else if(s == F("strobe")) { + if (m_bUseStrobe) { + m_nCurrentAlarmState = strobe; + } + else { + m_nCurrentAlarmState = siren; + if (debug) { + Serial.println(F("EX_Alarm::beSmart - Strobe Pin not defined. Defaulting to Siren!")); + } + + } + } + else if(s == F("off")) { + m_nCurrentAlarmState = off; + } + //} + //else { + // if (s == F("both") { + // m_nCurrentAlarmState = both; + // } + // else if(s == F("siren")) { + // m_nCurrentAlarmState = siren; + // } + // else if(s == F("strobe")) { + // m_nCurrentAlarmState = siren; + // } + // else if(s == F("off")) { + // m_nCurrentAlarmState = off; + // } + //} + + writeStateToPin(); + + refresh(); + } + + void EX_Alarm::setPin(byte pin) + { + //m_nPin = pin; + digitalWrite(pin, m_bInvertLogic ? HIGH : LOW); + pinMode(pin, OUTPUT); + writeStateToPin(); + } +} diff --git a/lib/ST_Anything/EX_Alarm.h b/lib/ST_Anything/EX_Alarm.h new file mode 100644 index 0000000..4a36f5b --- /dev/null +++ b/lib/ST_Anything/EX_Alarm.h @@ -0,0 +1,82 @@ +//****************************************************************************************** +// File: EX_Alarm.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: EX_Alarm is a class which implements the SmartThings "Alarm" device capability. +// It inherits from the st::PollingSensor class. The current version implements the Siren as +// a digital output (uses a relay to switch the Siren on or off) +// +// TODO: Possibly add Strobe capability in the future +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_Alarm executor2(F("alarm1"), PIN_ALARM, LOW, true, PIN_STROBE); +// +// st::EX_Alarm() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic +// - byte pinStrobe - OPTOINAL - If supplied, will allow separate SIREN and STROBE outputs +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2017-04-20 Dan Ogorchock Add optional Strobe functionality +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// +// +//****************************************************************************************** + +#ifndef ST_EX_Alarm_H +#define ST_EX_Alarm_H + +#include "Executor.h" + +enum Alarm_States { off, both, siren, strobe}; + +namespace st +{ + class EX_Alarm : public Executor + { + + private: + + bool m_bInvertLogic; + byte m_nPin; + byte m_nPinStrobe; + bool m_bUseStrobe; + Alarm_States m_nCurrentAlarmState; + + void writeStateToPin(); + + public: + //constructor + EX_Alarm(const __FlashStringHelper *name, byte Pin, bool startingState = LOW, bool invertLogic = false, byte pinStrobe = 255); + + //destructor + virtual ~EX_Alarm(); + + //initialization function + virtual void init(); + + //called periodically to ensure state of the Alarm Siren is up to date in the SmartThings Cloud (in case an event is missed) + virtual void refresh(); + + //SmartThings Shield data handler (receives command to turn "both" or "off" the Alarm (digital output) + virtual void beSmart(const String &str); + + //gets + virtual byte getPin() const { return m_nPin; } + virtual byte getStrobePin() const { return m_nPinStrobe; } + + //sets + virtual void setPin(byte pin); + + }; +} + + + +#endif diff --git a/lib/ST_Anything/EX_PWM_Dim.cpp b/lib/ST_Anything/EX_PWM_Dim.cpp new file mode 100644 index 0000000..c0ef632 --- /dev/null +++ b/lib/ST_Anything/EX_PWM_Dim.cpp @@ -0,0 +1,201 @@ +//****************************************************************************************** +// File: EX_PWM_Dim.cpp +// Authors: Dan G Ogorchock +// +// Summary: EX_PWM_Dim is a class which implements the SmartThings "Switch" and "Switch Level" device capabilities. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_PWM_Dim executor1(F("dimmerSwitch1"), PIN_SWITCH, PIN_LEVEL, LOW, true); +// +// st::EX_PWM_Dim() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - byte pin_pwm - REQUIRED - the Arduino Pin to be used as a pwm output +// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2016-04-30 Dan Ogorchock Original Creation +// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()" +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2018-08-30 Dan Ogorchock Adding reporting of 'level' +// 2018-12-06 Dan Ogorchock Fixed Comments +// 2019-04-10 Dan Ogorchock Corrected analogWrite() call for ESP8266 platform +// 2019-12-19 Doug Johnson Created new file based on EX_Switch_Dim to remove separate switch, and add dedicated smoothing +// 2020-04-01 Dan Ogorchock Added compatability for traditional Arduino Boards +// +// +//****************************************************************************************** +#include "EX_PWM_Dim.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ + //private + + void EX_PWM_Dim::writeLevelToPin() + { + if((m_nCurrentLevel == 0) && (m_bSetState == HIGH)) + { + for(int i=1; i < m_nSetLevel; i++) + { + m_nCurrentLevel++; +#if defined(ARDUINO_ARCH_ESP32) + if (st::Executor::debug) { + Serial.println(F("EX_Switch_Dim:: analogWrite not currently supported on ESP32!")); + } +#elif defined(ARDUINO_ARCH_ESP8266) + analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 1023)); +#else + analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 255)); +#endif + delay(7); + } + } + if((m_nCurrentLevel > 0) && (m_bSetState == LOW)) + { + for(int i=m_nCurrentLevel; i > 0; i--) + { + m_nCurrentLevel--; +#if defined(ARDUINO_ARCH_ESP32) + if (st::Executor::debug) { + Serial.println(F("EX_Switch_Dim:: analogWrite not currently supported on ESP32!")); + } +#elif defined(ARDUINO_ARCH_ESP8266) + analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 1023)); +#else + analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 255)); +#endif + delay(7); + } + } + + + + if((m_nCurrentLevel < m_nSetLevel)&& (m_bSetState == HIGH)) + { + for(int i=m_nCurrentLevel; i < m_nSetLevel; i++) + { + m_nCurrentLevel++; +#if defined(ARDUINO_ARCH_ESP32) + if (st::Executor::debug) { + Serial.println(F("EX_Switch_Dim:: analogWrite not currently supported on ESP32!")); + } +#elif defined(ARDUINO_ARCH_ESP8266) + analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 1023)); +#else + analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 255)); +#endif + delay(7); + } + } + if(m_nCurrentLevel > m_nSetLevel) + { + for(int i=m_nCurrentLevel; i > m_nSetLevel; i--) + { + m_nCurrentLevel--; +#if defined(ARDUINO_ARCH_ESP32) + if (st::Executor::debug) { + Serial.println(F("EX_Switch_Dim:: analogWrite not currently supported on ESP32!")); + } +#elif defined(ARDUINO_ARCH_ESP8266) + analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 1023)); +#else + analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 255)); +#endif + delay(7); + } + } + if(m_nCurrentLevel == 0) + { + m_bCurrentState = LOW; + } + else + { + m_bCurrentState = HIGH; + } + } + + //public + //constructor + EX_PWM_Dim::EX_PWM_Dim(const __FlashStringHelper *name, byte pinPWM, bool startingState, bool invertLogic) : + Executor(name), + m_bCurrentState(startingState), + m_bInvertLogic(invertLogic) + { + m_nCurrentLevel = startingState == HIGH ? 100 : 0; + setPWMPin(pinPWM); + } + + //destructor + EX_PWM_Dim::~EX_PWM_Dim() + { + + } + + void EX_PWM_Dim::init() + { + //Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + refresh(); + } + + void EX_PWM_Dim::beSmart(const String &str) + { + //String s = str.substring(str.indexOf(' ') + 1, str.indexOf(':')); + //String dur = str.substring(str.indexOf(':') + 1); + //dur.trim(); + + String s = str.substring(str.indexOf(' ') + 1); + if (st::Executor::debug) { + Serial.print(F("EX_PWM_Dim::beSmart s = ")); + Serial.println(s); + } + if (s == F("on")) + { + m_bSetState = HIGH; + } + else if (s == F("off")) + { + m_bSetState = LOW; + } + else //must be a set level command + { + s.trim(); + m_nSetLevel = byte(s.toInt()); + if (m_nSetLevel == 0) + { + m_bSetState = LOW; + } + else + { + m_bSetState = HIGH; + } + } + + writeLevelToPin(); + + //Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + refresh(); + + } + + void EX_PWM_Dim::refresh() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + Everything::sendSmartString(getName() + " " + m_nSetLevel); + } + + + void EX_PWM_Dim::setPWMPin(byte pin) + { + m_nPinPWM = pin; + pinMode(m_nPinPWM, OUTPUT); + writeLevelToPin(); + } +} diff --git a/lib/ST_Anything/EX_PWM_Dim.h b/lib/ST_Anything/EX_PWM_Dim.h new file mode 100644 index 0000000..504fdf9 --- /dev/null +++ b/lib/ST_Anything/EX_PWM_Dim.h @@ -0,0 +1,82 @@ +//****************************************************************************************** +// File: EX_PWM_Dim.h +// Authors: Dan G Ogorchock +// +// Summary: EX_PWM_Dim is a class which implements the SmartThings "Switch" and "Switch Level" device capabilities. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_PWM_Dim executor1(F("dimmerSwitch1"), PIN_SWITCH, PIN_LEVEL, LOW, true); +// +// st::EX_PWM_Dim() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - byte pin_pwm - REQUIRED - the Arduino Pin to be used as a pwm output +// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2016-04-30 Dan Ogorchock Original Creation +// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()" +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2018-12-06 Dan Ogorchock Fixed Comments +// 2019-04-10 Dan Ogorchock Corrected analogWrite() call for ESP8266 platform +// 2019-12-19 Doug Johnson Created new file based on EX_Switch_Dim to remove separate switch, and add dedicated smoothing +// 2020-04-01 Dan Ogorchock Added compatability for traditional Arduino Boards +// +// +//****************************************************************************************** +#ifndef ST_EX_PWM_DIM +#define ST_EX_PWM_DIM + +#include "Executor.h" + +namespace st +{ + class EX_PWM_Dim: public Executor + { + private: + bool m_bCurrentState; //HIGH or LOW + bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic + bool m_bSetState; + //byte m_nPinSwitch; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED + byte m_nPinPWM; //Arduino Pin used as a PWM Output for the switch level capability + byte m_nCurrentLevel; //Switch Level value from SmartThings (0 to 100) + byte m_nSetLevel; + + //void writeStateToPin(); //function to update the Arduino Digital Output Pin + void writeLevelToPin(); //function to update the Arduino PWM Output Pin + + public: + //constructor - called in your sketch's global variable declaration section + EX_PWM_Dim(const __FlashStringHelper *name, byte pinPWM, bool startingState = LOW, bool invertLogic = false); + + //destructor + virtual ~EX_PWM_Dim(); + + //initialization routine + virtual void init(); + + //SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output) and the LEVEL (PWM Output) + virtual void beSmart(const String &str); + + //called periodically to ensure state of the switch is up to date in the SmartThings Cloud (in case an event is missed) + virtual void refresh(); + + //gets + virtual byte getPWMPin() const { return m_nPinPWM; } + + virtual bool getStatus() const { return m_bCurrentState; } //whether the switch is HIGH or LOW + virtual bool getLevel() const { return m_nCurrentLevel; } //Dim Level of the switch + + //sets + //virtual void setSwitchPin(byte pin); + virtual void setPWMPin(byte pin); + + }; +} + +#endif diff --git a/lib/ST_Anything/EX_RGBW_Dim.cpp b/lib/ST_Anything/EX_RGBW_Dim.cpp new file mode 100644 index 0000000..b204369 --- /dev/null +++ b/lib/ST_Anything/EX_RGBW_Dim.cpp @@ -0,0 +1,239 @@ +//****************************************************************************************** +// File: EX_RGBW_Dim.h +// Authors: Allan (vseven) based on EX_Switch_Dim by Dan G Ogorchock +// +// Summary: EX_RGBW_Dim is a class which implements the SmartThings "Color Control", "Switch", and "Switch Level" device capabilities. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_RGBW_Dim executor1("rgbwSwitch1", PIN_R, PIN_G, PIN_B, PIN_W, true, 0, 1, 2, 3); +// +// st::EX_RGBW_Dim() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin_r - REQUIRED - the Arduino Pin to be used as a digital output for Red. +// - byte pin_g - REQUIRED - the Arduino Pin to be used as a digital output for Green. +// - byte pin_b - REQUIRED - the Arduino Pin to be used as a digital output for Blue. +// - byte pin_w - REQUIRED - the Arduino Pin to be used as a digital output for White. +// - bool commonAnode - REQUIRED - determines whether the LED uses a common Anode or Cathode. True for Anode. +// - byte channel_r - OPTIONAL - PWM channel used for Red on a ESP32. +// - byte channel_g - OPTIONAL - PWM channel used for Green on a ESP32. +// - byte channel_b - OPTIONAL - PWM channel used for Blue on a ESP32. +// - byte channel_w - OPTIONAL - PWM channel used for Whitw on a ESP32. +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2016-04-30 Dan Ogorchock Original Creation +// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()" +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2017-10-08 Allan (vseven) Modified original code from EX_RGBW_Dim to be used for RGB lighting +// 2017-10-12 Allan (vseven) Modified EX_RGBW_Dim for support of a White LED channel +// 2018-04-02 Dan Ogorchock Fixed Typo +// 2020-06-09 Dan Ogorchock Scaled the 8bit values to 10bit for ESP8266 "analogWrite()" +// +//****************************************************************************************** +#include "EX_RGBW_Dim.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + void EX_RGBW_Dim::writeRGBWToPins() + { + int subStringR; + int subStringG; + int subStringB; + int subStringW; + + if (m_bCurrentState == HIGH) { + // Our status is on so get the RGBW value from the hex + String hexstring = m_sCurrentHEX; + unsigned long number = (unsigned long) strtoul( &hexstring[1], NULL, 16); + // Split them up into r, g, b, w values + subStringR = number >> 24; + subStringG = number >> 16 & 0xFF; + subStringB = number >> 8 & 0xFF; + subStringW = number & 0xFF; + } else { + // Status is off so turn off LED + subStringR = 00; + subStringG = 00; + subStringB = 00; + subStringW = 00; + } + + if(m_bCommonAnode) { + // A hex value of 00 will translate to 255 for a common anode. However the + // ledcWrite seems to need a 256 to turn off so we are adding one here. + + #if defined(ARDUINO_ARCH_ESP32) + subStringR = 255 - subStringR + 1; + subStringG = 255 - subStringG + 1; + subStringB = 255 - subStringB + 1; + subStringW = 255 - subStringW + 1; + #else + subStringR = 255 - subStringR; + subStringG = 255 - subStringG; + subStringB = 255 - subStringB; + subStringW = 255 - subStringW; + #endif + } + // Write to outputs. Use ledc for ESP32, analogWrite for everything else. + + if (st::Executor::debug) { + #if defined(ARDUINO_ARCH_ESP32) + Serial.print(F("subString R:G:B:W = ")); + Serial.println(String(subStringR) + ":" + String(subStringG) + ":" + String(subStringB) + ":" + String(subStringW)); + #elif defined(ARDUINO_ARCH_ESP8266) + Serial.print(F("subString R:G:B:W = ")); + Serial.println(String(map(subStringR, 0, 255, 0, 1023)) + ":" + String(map(subStringG, 0, 255, 0, 1023)) + ":" + String(map(subStringB, 0, 255, 0, 1023)) + ":" + String(map(subStringW, 0, 255, 0, 1023))); + #else + Serial.print(F("subString R:G:B:W = ")); + Serial.println(String(subStringR) + ":" + String(subStringG) + ":" + String(subStringB) + ":" + String(subStringW)); + #endif + } + + // Any adjustments to the colors can be done here before sending the commands. For example if red is always too bright reduce it: + // subStringR = subStringR * 0.95 + + #if defined(ARDUINO_ARCH_ESP32) + ledcWrite(m_nChannelR, subStringR); + #elif defined(ARDUINO_ARCH_ESP8266) + analogWrite(m_nPinR, map(subStringR, 0, 255, 0, 1023)); + #else + analogWrite(m_nPinR, subStringR); + #endif + + #if defined(ARDUINO_ARCH_ESP32) + ledcWrite(m_nChannelG, subStringG); + #elif defined(ARDUINO_ARCH_ESP8266) + analogWrite(m_nPinG, map(subStringG, 0, 255, 0, 1023)); + #else + analogWrite(m_nPinG, subStringG); + #endif + + #if defined(ARDUINO_ARCH_ESP32) + ledcWrite(m_nChannelB, subStringB); + #elif defined(ARDUINO_ARCH_ESP8266) + analogWrite(m_nPinB, map(subStringB, 0, 255, 0, 1023)); + #else + analogWrite(m_nPinB, subStringB); + #endif + + #if defined(ARDUINO_ARCH_ESP32) + ledcWrite(m_nChannelW, subStringW); + #elif defined(ARDUINO_ARCH_ESP8266) + analogWrite(m_nPinW, map(subStringW, 0, 255, 0, 1023)); + #else + analogWrite(m_nPinW, subStringW); + #endif + + } + +//public + //constructor + EX_RGBW_Dim::EX_RGBW_Dim(const __FlashStringHelper *name, byte pinR, byte pinG, byte pinB, byte pinW, bool commonAnode, byte channelR, byte channelG, byte channelB, byte channelW): + Executor(name), + m_bCommonAnode(commonAnode) + { + setRedPin(pinR, channelR); + setGreenPin(pinG, channelG); + setBluePin(pinB, channelB); + setWhitePin(pinW, channelW); + } + + //destructor + EX_RGBW_Dim::~EX_RGBW_Dim() + { + + } + + void EX_RGBW_Dim::init() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + } + + void EX_RGBW_Dim::beSmart(const String &str) + { + String s=str.substring(str.indexOf(' ')+1); + if (st::Executor::debug) { + Serial.print(F("EX_RGBW_Dim::beSmart s = ")); + Serial.println(s); + } + if(s==F("on")) + { + m_bCurrentState=HIGH; + } + else if(s==F("off")) + { + m_bCurrentState=LOW; + } + else //must be a set color command + { + s.trim(); + m_sCurrentHEX = s; + } + + writeRGBWToPins(); + + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off"))); + } + + void EX_RGBW_Dim::refresh() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off"))); + } + + void EX_RGBW_Dim::setRedPin(byte pin, byte channel) + { + m_nPinR = pin; + m_nChannelR = channel; + + #if defined(ARDUINO_ARCH_ESP32) + ledcAttachPin(m_nPinR, m_nChannelR); + ledcSetup(m_nChannelR, 5000, 8); + #else + pinMode(m_nPinR, OUTPUT); + #endif + } + void EX_RGBW_Dim::setGreenPin(byte pin, byte channel) + { + m_nPinG = pin; + m_nChannelG = channel; + + #if defined(ARDUINO_ARCH_ESP32) + ledcAttachPin(m_nPinG, m_nChannelG); + ledcSetup(m_nChannelG, 5000, 8); + #else + pinMode(m_nPinG, OUTPUT); + #endif + } + void EX_RGBW_Dim::setBluePin(byte pin, byte channel) + { + m_nPinB = pin; + m_nChannelB = channel; + + #if defined(ARDUINO_ARCH_ESP32) + ledcAttachPin(m_nPinB, m_nChannelB); + ledcSetup(m_nChannelB, 5000, 8); + #else + pinMode(m_nPinB, OUTPUT); + #endif + } + void EX_RGBW_Dim::setWhitePin(byte pin, byte channel) + { + m_nPinW = pin; + m_nChannelW = channel; + + #if defined(ARDUINO_ARCH_ESP32) + ledcAttachPin(m_nPinW, m_nChannelW); + ledcSetup(m_nChannelW, 5000, 8); + #else + pinMode(m_nPinW, OUTPUT); + #endif + } + +} diff --git a/lib/ST_Anything/EX_RGBW_Dim.h b/lib/ST_Anything/EX_RGBW_Dim.h new file mode 100644 index 0000000..f9de159 --- /dev/null +++ b/lib/ST_Anything/EX_RGBW_Dim.h @@ -0,0 +1,98 @@ +//****************************************************************************************** +// File: EX_RGBW_Dim.h +// Authors: Allan (vseven) based on EX_Switch_Dim by Dan G Ogorchock +// +// Summary: EX_RGBW_Dim is a class which implements the SmartThings "Color Control", "Switch", and "Switch Level" device capabilities. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_RGBW_Dim executor1("rgbwSwitch1", PIN_R, PIN_G, PIN_B, PIN_W, true, 0, 1, 2, 3); +// +// st::EX_RGBW_Dim() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name. +// - byte pin_r - REQUIRED - the Arduino Pin to be used as a digital output for Red. +// - byte pin_g - REQUIRED - the Arduino Pin to be used as a digital output for Green. +// - byte pin_b - REQUIRED - the Arduino Pin to be used as a digital output for Blue. +// - byte pin_w - REQUIRED - the Arduino Pin to be used as a digital output for White. +// - bool commonAnode - REQUIRED - determines whether the LED uses a common Anode or Cathode. True for Anode. +// - byte channel_r - OPTIONAL - PWM channel used for Red on a ESP32. +// - byte channel_g - OPTIONAL - PWM channel used for Green on a ESP32. +// - byte channel_b - OPTIONAL - PWM channel used for Blue on a ESP32. +// - byte channel_w - OPTIONAL - PWM channel used for Whitw on a ESP32. +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2016-04-30 Dan Ogorchock Original Creation +// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()" +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2017-10-06 Allan (vseven) Modified original code from EX_Switch_Dim to be used for RGB lighting +// 2017-10-12 Allan (vseven) Modified EX_RGB_Dim for support of a White LEd channel +// 2020-06-09 Dan Ogorchock Scaled the 8bit values to 10bit for ESP8266 "analogWrite()" +// +//****************************************************************************************** +#ifndef ST_EX_RGBW_Dim +#define ST_EX_RGBW_Dim + +#include "Executor.h" + +namespace st +{ + class EX_RGBW_Dim: public Executor + { + private: + bool m_bCurrentState; //HIGH or LOW + bool m_bCommonAnode; //TRUE or FALSE + byte m_nPinR; //Arduino Pin used as a PWM Output for Red + byte m_nPinG; //Arduino Pin used as a PWM Output for Green + byte m_nPinB; //Arduino Pin used as a PWM Output for Blue + byte m_nPinW; //Arduino Pin used as a PWM Output for White + byte m_nChannelR; //PWM Channel used for Red output + byte m_nChannelG; //PWM Channel used for Green output + byte m_nChannelB; //PWM Channel used for Blue output + byte m_nChannelW; //PWM Channel used for White output + String m_sCurrentHEX; //HEX value of color currently set + + void writeRGBWToPins(); //function to update the Arduino PWM Output Pins + + public: + //constructor - called in your sketch's global variable declaration section + EX_RGBW_Dim(const __FlashStringHelper *name, byte pinR, byte pinG, byte pinB, byte pinW, bool commonAnode, byte channelR = 0, byte channelG = 0, byte channelB = 0, byte channelW = 0); + + //destructor + virtual ~EX_RGBW_Dim(); + + //initialization routine + virtual void init(); + + //SmartThings Shield data handler (receives command to turn "on" or "off" the switch along with HEX value for LEDs) + virtual void beSmart(const String &str); + + //called periodically to ensure state of the switch is up to date in the SmartThings Cloud (in case an event is missed) + virtual void refresh(); + + //gets + virtual byte getRedPin() const { return m_nPinR; } + virtual byte getGreenPin() const { return m_nPinG; } + virtual byte getBluePin() const { return m_nPinB; } + virtual byte getWhitePin() const { return m_nPinW; } + + virtual byte getRedChannel() const { return m_nChannelR; } + virtual byte getGreenChannel() const { return m_nChannelG; } + virtual byte getBlueChannel() const { return m_nChannelB; } + virtual byte getWhiteChannel() const { return m_nChannelW; } + + virtual bool getStatus() const { return m_bCurrentState; } //whether the switch is HIGH or LOW + virtual String getHEX() const { return m_sCurrentHEX; } // color value in HEX + + //sets + virtual void setRedPin(byte pin,byte channel); + virtual void setGreenPin(byte pin,byte channel); + virtual void setBluePin(byte pin,byte channel); + virtual void setWhitePin(byte pin,byte channel); + + }; +} + +#endif diff --git a/lib/ST_Anything/EX_RGB_Dim.cpp b/lib/ST_Anything/EX_RGB_Dim.cpp new file mode 100644 index 0000000..a1d38ce --- /dev/null +++ b/lib/ST_Anything/EX_RGB_Dim.cpp @@ -0,0 +1,213 @@ +//****************************************************************************************** +// File: EX_RGB_Dim.h +// Authors: Allan (vseven) based on EX_Switch_Dim by Dan G Ogorchock +// +// Summary: EX_RGB_Dim is a class which implements the SmartThings "Color Control", "Switch", and "Switch Level" device capabilities. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_RGB_Dim executor1("rgbSwitch1", PIN_R, PIN_G, PIN_B, true, 0, 1, 2); +// +// st::EX_RGB_Dim() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin_r - REQUIRED - the Arduino Pin to be used as a digital output for Red +// - byte pin_g - REQUIRED - the Arduino Pin to be used as a digital output for Green +// - byte pin_b - REQUIRED - the Arduino Pin to be used as a digital output for Blue +// - bool commonAnode - REQUIRED - determines whether the Arduino Digital Output should use inverted logic +// - byte channel_r - OPTIONAL - PWM channel used for Red on a ESP32 +// - byte channel_g - OPTIONAL - PWM channel used for Green on a ESP32 +// - byte channel_b - OPTIONAL - PWM channel used for Blue on a ESP32 +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2016-04-30 Dan Ogorchock Original Creation +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2017-10-08 Allan (vseven) Modified original code from EX_Switch_Dim to be used for RGB lighting +// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()" +// 2020-03-29 DOUG (M2) Scaled the 8bit values to 10bit for ESP8266 "analogWrite()" +// 2020-04-01 Dan Ogorchock Added back in functionality for traditional Arduino Boards +// +//****************************************************************************************** +#include "EX_RGB_Dim.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + void EX_RGB_Dim::writeRGBToPins() + { + int subStringR; + int subStringG; + int subStringB; + + if (m_bCurrentState == HIGH) + { + // Our status is on so get the RGB value from the hex + String hexstring = m_sCurrentHEX; + long number = (long) strtol( &hexstring[1], NULL, 16); + // Split them up into r, g, b values + subStringR = number >> 16; + subStringG = number >> 8 & 0xFF; + subStringB = number & 0xFF; + } + else + { + // Status is off so turn off LED + subStringR = 00; + subStringG = 00; + subStringB = 00; + } + + if(m_bCommonAnode) + { + // A hex value of 00 will translate to 255 for a common anode. However the + // ledcWrite seems to need a 256 to turn off so we are adding one here. + #if defined(ARDUINO_ARCH_ESP32) + subStringR = 255 - subStringR + 1; + subStringG = 255 - subStringG + 1; + subStringB = 255 - subStringB + 1; + #else + subStringR = 255 - subStringR; + subStringG = 255 - subStringG; + subStringB = 255 - subStringB; + #endif + } + + // Write to outputs. Use ledc for ESP32, analogWrite for everything else. + if (st::Executor::debug) { + #if defined(ARDUINO_ARCH_ESP32) + Serial.print(F("subString R:G:B = ")); + Serial.println(String(subStringR) + ":" + String(subStringG) + ":" + String(subStringB)); + #elif defined(ARDUINO_ARCH_ESP8266) + Serial.print(F("subString 10bit R:G:B = ")); + Serial.println(String(map(subStringR, 0, 255, 0, 1023)) + ":" + String(map(subStringG, 0, 255, 0, 1023)) + ":" + String(map(subStringB, 0, 255, 0, 1023))); + #else + Serial.print(F("subString R:G:B = ")); + Serial.println(String(subStringR) + ":" + String(subStringG) + ":" + String(subStringB)); + #endif + } + + // Any adjustments to the colors can be done here before sending the commands. For example if red is always too bright reduce it: + // subStringR = subStringR * 0.95 + + #if defined(ARDUINO_ARCH_ESP32) + ledcWrite(m_nChannelR, subStringR); + #elif defined(ARDUINO_ARCH_ESP8266) + analogWrite(m_nPinR, map(subStringR, 0, 255, 0, 1023)); + #else + analogWrite(m_nPinR, subStringR); + #endif + + #if defined(ARDUINO_ARCH_ESP32) + ledcWrite(m_nChannelG, subStringG); + #elif defined(ARDUINO_ARCH_ESP8266) + analogWrite(m_nPinG, map(subStringG, 0, 255, 0, 1023)); + #else + analogWrite(m_nPinG, subStringG); + #endif + + #if defined(ARDUINO_ARCH_ESP32) + ledcWrite(m_nChannelB, subStringB); + #elif defined(ARDUINO_ARCH_ESP8266) + analogWrite(m_nPinB, map(subStringB, 0, 255, 0, 1023)); + #else + analogWrite(m_nPinB, subStringB); + #endif + + } + +//public + //constructor + EX_RGB_Dim::EX_RGB_Dim(const __FlashStringHelper *name, byte pinR, byte pinG, byte pinB, bool commonAnode, byte channelR, byte channelG, byte channelB): + Executor(name), + m_bCommonAnode(commonAnode) + { + setRedPin(pinR, channelR); + setGreenPin(pinG, channelG); + setBluePin(pinB, channelB); + } + + //destructor + EX_RGB_Dim::~EX_RGB_Dim() + { + + } + + void EX_RGB_Dim::init() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + } + + void EX_RGB_Dim::beSmart(const String &str) + { + String s=str.substring(str.indexOf(' ')+1); + if (st::Executor::debug) { + Serial.print(F("EX_RGB_Dim::beSmart s = ")); + Serial.println(s); + } + if(s==F("on")) + { + m_bCurrentState=HIGH; + } + else if(s==F("off")) + { + m_bCurrentState=LOW; + } + else //must be a set color command + { + s.trim(); + m_sCurrentHEX = s; + } + + writeRGBToPins(); + + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off"))); + } + + void EX_RGB_Dim::refresh() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off"))); + } + + void EX_RGB_Dim::setRedPin(byte pin, byte channel) + { + m_nPinR = pin; + m_nChannelR = channel; + + #if defined(ARDUINO_ARCH_ESP32) + ledcAttachPin(m_nPinR, m_nChannelR); + ledcSetup(m_nChannelR, 5000, 8); + #else + pinMode(m_nPinR, OUTPUT); + #endif + } + void EX_RGB_Dim::setGreenPin(byte pin, byte channel) + { + m_nPinG = pin; + m_nChannelG = channel; + + #if defined(ARDUINO_ARCH_ESP32) + ledcAttachPin(m_nPinG, m_nChannelG); + ledcSetup(m_nChannelG, 5000, 8); + #else + pinMode(m_nPinG, OUTPUT); + #endif + } + void EX_RGB_Dim::setBluePin(byte pin, byte channel) + { + m_nPinB = pin; + m_nChannelB = channel; + + #if defined(ARDUINO_ARCH_ESP32) + ledcAttachPin(m_nPinB, m_nChannelB); + ledcSetup(m_nChannelB, 5000, 8); + #else + pinMode(m_nPinB, OUTPUT); + #endif + } + +} diff --git a/lib/ST_Anything/EX_RGB_Dim.h b/lib/ST_Anything/EX_RGB_Dim.h new file mode 100644 index 0000000..fedfed7 --- /dev/null +++ b/lib/ST_Anything/EX_RGB_Dim.h @@ -0,0 +1,91 @@ + //****************************************************************************************** +// File: EX_RGB_Dim.h +// Authors: Allan (vseven) based on EX_Switch_Dim by Dan G Ogorchock +// +// Summary: EX_RGB_Dim is a class which implements the SmartThings "Color Control", "Switch", and "Switch Level" device capabilities. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_RGB_Dim executor1("rgbSwitch1", PIN_R, PIN_G, PIN_B, true, 0, 1, 2); +// +// st::EX_RGB_Dim() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name. +// - byte pin_r - REQUIRED - the Arduino Pin to be used as a digital output for Red. +// - byte pin_g - REQUIRED - the Arduino Pin to be used as a digital output for Green. +// - byte pin_b - REQUIRED - the Arduino Pin to be used as a digital output for Blue. +// - bool commonAnode - REQUIRED - determines whether the LED uses a common Anode or Cathode. True for Anode. +// - byte channel_r - OPTIONAL - PWM channel used for Red on a ESP32. +// - byte channel_g - OPTIONAL - PWM channel used for Green on a ESP32. +// - byte channel_b - OPTIONAL - PWM channel used for Blue on a ESP32. +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2016-04-30 Dan Ogorchock Original Creation +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2017-10-06 Allan (vseven) Modified original code from EX_Switch_Dim to be used for RGB lighting +// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()" +// 2020-03-29 DOUG (M2) Scaled the 8bit values to 10bit for ESP8266 "analogWrite()" +// 2020-04-01 Dan Ogorchock Added back in functionality for traditional Arduino Boards +// +//****************************************************************************************** +#ifndef ST_EX_RGB_DIM +#define ST_EX_RGB_DIM + +#include "Executor.h" + +namespace st +{ + class EX_RGB_Dim: public Executor + { + private: + bool m_bCurrentState; //HIGH or LOW + bool m_bCommonAnode; //TRUE or FALSE + byte m_nPinR; //Arduino Pin used as a PWM Output for Red + byte m_nPinG; //Arduino Pin used as a PWM Output for Green + byte m_nPinB; //Arduino Pin used as a PWM Output for Blue + byte m_nChannelR; //PWM Channel used for Red output + byte m_nChannelG; //PWM Channel used for Green output + byte m_nChannelB; //PWM Channel used for Blue output + String m_sCurrentHEX; //HEX value of color currently set + + void writeRGBToPins(); //function to update the Arduino PWM Output Pins + + public: + //constructor - called in your sketch's global variable declaration section + EX_RGB_Dim(const __FlashStringHelper *name, byte pinR, byte pinG, byte pinB, bool commonAnode, byte channelR = 0, byte channelG = 0, byte channelB = 0); + + //destructor + virtual ~EX_RGB_Dim(); + + //initialization routine + virtual void init(); + + //SmartThings Shield data handler (receives command to turn "on" or "off" the switch along with HEX value for LEDs) + virtual void beSmart(const String &str); + + //called periodically to ensure state of the switch is up to date in the SmartThings Cloud (in case an event is missed) + virtual void refresh(); + + //gets + virtual byte getRedPin() const { return m_nPinR; } + virtual byte getGreenPin() const { return m_nPinG; } + virtual byte getBluePin() const { return m_nPinB; } + + virtual byte getRedChannel() const { return m_nChannelR; } + virtual byte getGreenChannel() const { return m_nChannelG; } + virtual byte getBlueChannel() const { return m_nChannelB; } + + virtual bool getStatus() const { return m_bCurrentState; } //whether the switch is HIGH or LOW + virtual String getHEX() const { return m_sCurrentHEX; } // color value in HEX + + //sets + virtual void setRedPin(byte pin,byte channel); + virtual void setGreenPin(byte pin,byte channel); + virtual void setBluePin(byte pin,byte channel); + + }; +} + +#endif diff --git a/lib/ST_Anything/EX_Servo.cpp b/lib/ST_Anything/EX_Servo.cpp new file mode 100644 index 0000000..da5dcc0 --- /dev/null +++ b/lib/ST_Anything/EX_Servo.cpp @@ -0,0 +1,198 @@ +//****************************************************************************************** +// File: EX_Servo.cpp +// Authors: Dan G Ogorchock +// +// Summary: EX_Servo is a class which implements the SmartThings/Hubitat "Switch Level" device capability. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_Servo executor1(F("servo1"), PIN_SERVO, 90, true, 1000, 0, 180, 2000, 544, 2400); +// +// st::EX_Servo() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin_pwm - REQUIRED - the Arduino Pin to be used as a pwm output +// - int startingAngle - OPTIONAL - the value desired for the initial angle of the servo motor (0 to 180, defaults to 90) +// - bool detachAfterMove - OPTIONAL - determines if servo motor is powered down after move (defaults to false) +// - int servoDetachTime - OPTIONAL - determines how long after the servo is moved that the servo is powered down if detachAfterMove is true (defaults to 1000ms) +// - int minLevelAngle - OPTIONAL - servo angle in degrees to map to level 0 (defaults to 0 degrees) +// - int maxLevelAngle - OPTIONAL - servo angle in degrees to map to level 100 (defaults to 180 degrees) +// - int servoRate - OPTIONAL - initial servo rate in ms/degree (defaults to 2000, used to ensure a gentle move during startup, afterwards comes from SmartThings/Hubitat with each move request) +// - int minPulseWidth - OPTIONAL - minimum pulse width in milliseconds, defaults to 544 (see Arduino servo attach() function) +// - int maxPulseWidth - OPTIONAL - maximum pulse width in milliseconds, defaults to 2400 (see Arduino servo attach() function) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2018-06-23 Dan Ogorchock Original Creation +// 2018-06-24 Dan Ogorchock Since ESP32 does not support SERVO library, exclude all code to prevent compiler error +// 2018-08-19 Dan Ogorchock Added feature to optionally allow servo to be powered down after a move +// 2019-02-02 Jeff Albers Added Parameters to map servo endpoints, actively control rate of servo motion via duration input to device driver, intializes to level instead of angle +// 2019-02-09 Dan Ogorchock Adding Asynchronous Motion to eliminate blocking calls and to allow simultaneous motion across multiple servos +// 2019-03-04 Dan Ogorchock Added optional min and max pulse width parameters to allow servo specific adjustments +// +// +//****************************************************************************************** +#include "EX_Servo.h" + +#include "Constants.h" +#include "Everything.h" + +#if not defined(ARDUINO_ARCH_ESP32) + +namespace st +{ + //private + void EX_Servo::writeAngleToPin() + { + if(m_bMoveActive == true) { + m_bMoveActive = false; + } + + if (!m_Servo.attached()) { + m_Servo.attach(m_nPinPWM, m_nMinPulseWidth, m_nMaxPulseWidth); + } + + if ((m_nTargetAngle < m_nMinLevelAngle) and (m_nTargetAngle < m_nMaxLevelAngle)) { + if (m_nMinLevelAngle < m_nMaxLevelAngle) { + m_nTargetAngle = m_nMinLevelAngle; + } + else { + m_nTargetAngle = m_nMaxLevelAngle; + } + } + if ((m_nTargetAngle > m_nMaxLevelAngle) and (m_nTargetAngle > m_nMinLevelAngle)) { + if (m_nMaxLevelAngle > m_nMinLevelAngle) { + m_nTargetAngle = m_nMaxLevelAngle; + } + else { + m_nTargetAngle = m_nMinLevelAngle; + } + } + + m_nTimeStep = abs(m_nCurrentRate / (m_nMaxLevelAngle - m_nMinLevelAngle)); //Constant servo step rate assumes duration is the time desired for maximum level change of 100 + m_nCurrentAngle = m_nOldAngle; //preserver original angular position + m_bMoveActive = true; //start the move (the update() function will take care of the actual motion) + + if (st::Executor::debug) { + Serial.print(F("EX_Servo:: Servo motor angle set to ")); + Serial.println(m_nTargetAngle); + } + + } + + //public + //constructor + EX_Servo::EX_Servo(const __FlashStringHelper *name, byte pinPWM, int startingAngle, bool detachAfterMove, long servoDetachTime, int minLevelAngle, int maxLevelAngle, int servoRate, int minPulseWidth, int maxPulseWidth) : + Executor(name), + m_Servo(), + m_nTargetAngle(startingAngle), + m_bDetachAfterMove(detachAfterMove), + m_nDetachTime(servoDetachTime), + m_nMinLevelAngle(minLevelAngle), + m_nMaxLevelAngle(maxLevelAngle), + m_nCurrentRate(servoRate), + m_bMoveActive(false), + m_bDetachTmrActive(false), + m_nMinPulseWidth(minPulseWidth), + m_nMaxPulseWidth(maxPulseWidth) + { + setPWMPin(pinPWM); + m_nOldAngle = (minLevelAngle + maxLevelAngle) / 2; + } + + //destructor + EX_Servo::~EX_Servo() + { + + } + + void EX_Servo::init() + { + writeAngleToPin(); + refresh(); + } + + void EX_Servo::update() + { + if (m_bMoveActive) { + if ((millis() - m_nPrevMillis) > m_nTimeStep) { + m_nPrevMillis = millis(); + if (m_nCurrentAngle != m_nTargetAngle) { + if (m_nTargetAngle >= m_nOldAngle) { + m_nCurrentAngle = m_nCurrentAngle + 1; + } + else { + m_nCurrentAngle = m_nCurrentAngle - 1; + } + m_Servo.write(m_nCurrentAngle); + } + else { + m_bMoveActive = false; + if (st::Executor::debug) { + Serial.println(F("EX_Servo::update() move complete")); + } + if (m_bDetachAfterMove) { + m_bDetachTmrActive = true; + } + refresh(); + } + } + } + + if (m_bDetachTmrActive) { + if ((millis() - m_nPrevMillis) > m_nDetachTime) { + m_bDetachTmrActive = false; + m_Servo.detach(); + if (st::Executor::debug) { + Serial.println(F("EX_Servo::update() detach complete")); + } + } + } + } + + void EX_Servo::beSmart(const String &str) + { + String level = str.substring(str.indexOf(' ') + 1, str.indexOf(':')); + String rate = str.substring(str.indexOf(':') + 1); + + level.trim(); + rate.trim(); + + if (st::Executor::debug) { + Serial.print(F("EX_Servo::beSmart level = ")); + Serial.println(level); + Serial.print(F("EX_Servo::beSmart rate = ")); + Serial.println(rate); + } + + m_nCurrentLevel = int(level.toInt()); + m_nCurrentRate = long(rate.toInt()); + m_nOldAngle = m_nCurrentAngle; + m_nTargetAngle = map(m_nCurrentLevel, 0, 100, m_nMinLevelAngle, m_nMaxLevelAngle); + + if (st::Executor::debug) { + Serial.print(F("EX_Servo::beSmart OldAngle = ")); + Serial.println(m_nOldAngle); + Serial.print(F("EX_Servo::beSmart TargetAngle = ")); + Serial.println(m_nTargetAngle); + Serial.print(F("EX_Servo::beSmart CurrentRate = ")); + Serial.println(m_nCurrentRate); + } + writeAngleToPin(); + + + } + + void EX_Servo::refresh() + { + Everything::sendSmartString(getName() + " " + String(m_nCurrentLevel) + ":" + String(m_nTargetAngle) + ":" + String(m_nCurrentRate)); + } + + void EX_Servo::setPWMPin(byte pin) + { + m_nPinPWM = pin; + } +} + +#endif diff --git a/lib/ST_Anything/EX_Servo.h b/lib/ST_Anything/EX_Servo.h new file mode 100644 index 0000000..43f05b0 --- /dev/null +++ b/lib/ST_Anything/EX_Servo.h @@ -0,0 +1,102 @@ +//****************************************************************************************** +// File: EX_Servo.h +// Authors: Dan G Ogorchock +// +// Summary: EX_Servo is a class which implements the SmartThings/Hubitat "Switch Level" device capability. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_Servo executor1(F("servo1"), PIN_SERVO, 90, true, 1000, 0, 180, 2000, 544, 2400); +// +// st::EX_Servo() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin_pwm - REQUIRED - the Arduino Pin to be used as a pwm output +// - int startingAngle - OPTIONAL - the value desired for the initial angle of the servo motor (0 to 180, defaults to 90) +// - bool detachAfterMove - OPTIONAL - determines if servo motor is powered down after move (defaults to false) +// - int servoDetachTime - OPTIONAL - determines how long after the servo is moved that the servo is powered down if detachAfterMove is true (defaults to 1000ms) +// - int minLevelAngle - OPTIONAL - servo angle in degrees to map to level 0 (defaults to 0 degrees) +// - int maxLevelAngle - OPTIONAL - servo angle in degrees to map to level 100 (defaults to 180 degrees) +// - int servoRate - OPTIONAL - initial servo rate in ms/degree (defaults to 2000, used to ensure a gentle move during startup, afterwards comes from SmartThings/Hubitat with each move request) +// - int minPulseWidth - OPTIONAL - minimum pulse width in milliseconds, defaults to 544 (see Arduino servo attach() function) +// - int maxPulseWidth - OPTIONAL - maximum pulse width in milliseconds, defaults to 2400 (see Arduino servo attach() function) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2018-06-23 Dan Ogorchock Original Creation +// 2018-06-24 Dan Ogorchock Since ESP32 does not support SERVO library, exclude all code to prevent compiler error +// 2018-08-19 Dan Ogorchock Added feature to optionally allow servo to be powered down after a move +// 2019-02-02 Jeff Albers Added Parameters to map servo endpoints, actively control rate of servo motion via duration input to device driver, intializes to level instead of angle +// 2019-02-09 Dan Ogorchock Adding Asynchronous Motion to eliminate blocking calls and to allow simultaneous motion across multiple servos +// 2019-03-04 Dan Ogorchock Added optional min and max pulse width parameters to allow servo specific adjustments +// +// +//****************************************************************************************** +#ifndef ST_EX_SERVO +#define ST_EX_SERVO + +#if not defined(ARDUINO_ARCH_ESP32) + +#include "Executor.h" +#include + +namespace st +{ + class EX_Servo: public Executor + { + private: + Servo m_Servo; //Servo object + byte m_nPinPWM; //Arduino Pin used as a PWM Output for the switch level capability + int m_nCurrentLevel; //Servo Level value from SmartThings/Hubitat (0 to 100%) + int m_nOldAngle; //starting angle for servo move + int m_nTargetAngle; //ending angle for servo move, value mapped to Servo Level (0 to 180 degrees maximum range) + int m_nCurrentAngle; //servo angle output while stepping from OldAngle to TargetAngle + long m_nCurrentRate; //Servo move Duration value from SmartThings/Hubitat (0 to 10000 milliseconds) + long m_nDetachTime; //Servo Detach Time in milliseconds + bool m_bDetachAfterMove; //Issue a servo.detach() after servo move is complete + int m_nMinLevelAngle; //Angle (0-180 degrees)to map to level 0 + int m_nMaxLevelAngle; //Angle (0-180 degrees)to map to level 100 + bool m_bMoveActive; //True if servo move is active (asynchronous motion) + bool m_bDetachTmrActive; //True if servo is waiting to power off + long m_nTimeStep; //Number of milliseconds per servo motor degree (i.e. rate of change for the servo) + long m_nPrevMillis; //Previous millis() value + int m_nMinPulseWidth; //Minimum Servo Pulse Width + int m_nMaxPulseWidth; //Maximum Servo Pulse Width + + + void writeAngleToPin(); //function to update the Arduino PWM Output Pin + + public: + //constructor - called in your sketch's global variable declaration section + EX_Servo(const __FlashStringHelper *name, byte pinPWM, int startingAngle = 90, bool detachAfterMove = false, long servoDetachTime = 1000, int minLevelAngle = 0, int maxLevelAngle = 180, int servoRate = 2000, int minPulseWidth = 544, int maxPulseWidth = 2400); + + //destructor + virtual ~EX_Servo(); + + //initialization routine + virtual void init(); + + //update function + void update(); + + //SmartThings Shield data handler (receives Level and Duration from ST/Hubitat) + virtual void beSmart(const String &str); + + //called periodically to ensure state of the switch is up to date in the SmartThings Cloud / Hubitat Hub (in case an event is missed) + virtual void refresh(); + + //gets + virtual byte getPWMPin() const { return m_nPinPWM; } + + virtual bool getAngle() const { return m_nTargetAngle; } //Angle of the Servo mapped to Level + virtual bool getLevel() const { return m_nCurrentLevel; } //Servo Level from ST/Hubitat + virtual bool getRate() const { return m_nCurrentRate; } //Duration from ST/Hubitat + + //sets + virtual void setPWMPin(byte pin); + }; +} + +#endif +#endif \ No newline at end of file diff --git a/lib/ST_Anything/EX_Switch.cpp b/lib/ST_Anything/EX_Switch.cpp new file mode 100644 index 0000000..4716b31 --- /dev/null +++ b/lib/ST_Anything/EX_Switch.cpp @@ -0,0 +1,95 @@ +//****************************************************************************************** +// File: EX_Switch.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: EX_Switch is a class which implements the SmartThings "Switch" device capability. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_Switch executor1(F("switch1"), PIN_SWITCH, LOW, true); +// +// st::EX_Switch() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// +// +//****************************************************************************************** + +#include "EX_Switch.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + void EX_Switch::writeStateToPin() + { + digitalWrite(m_nPin, m_bInvertLogic ? !m_bCurrentState : m_bCurrentState); + } + + + +//public + //constructor + EX_Switch::EX_Switch(const __FlashStringHelper *name, byte pin, bool startingState, bool invertLogic) : + Executor(name), + m_bCurrentState(startingState), + m_bInvertLogic(invertLogic) + { + setPin(pin); + } + + //destructor + EX_Switch::~EX_Switch() + { + + } + + void EX_Switch::init() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + } + + void EX_Switch::beSmart(const String &str) + { + String s=str.substring(str.indexOf(' ')+1); + if (st::Executor::debug) { + Serial.print(F("EX_Switch::beSmart s = ")); + Serial.println(s); + } + if(s==F("on")) + { + m_bCurrentState=HIGH; + } + else if(s==F("off")) + { + m_bCurrentState=LOW; + } + + writeStateToPin(); + + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off"))); + } + + void EX_Switch::refresh() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off"))); + } + + void EX_Switch::setPin(byte pin) + { + m_nPin=pin; + pinMode(m_nPin, OUTPUT); + writeStateToPin(); + } +} diff --git a/lib/ST_Anything/EX_Switch.h b/lib/ST_Anything/EX_Switch.h new file mode 100644 index 0000000..aa7ca21 --- /dev/null +++ b/lib/ST_Anything/EX_Switch.h @@ -0,0 +1,69 @@ +//****************************************************************************************** +// File: EX_Switch.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: EX_Switch is a class which implements the SmartThings "Switch" device capability. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_Switch executor1(F("switch1"), PIN_SWITCH, LOW, true); +// +// st::EX_Switch() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// +// +//****************************************************************************************** +#ifndef ST_EX_SWITCH +#define ST_EX_SWITCH + +#include "Executor.h" + +namespace st +{ + class EX_Switch: public Executor + { + private: + bool m_bCurrentState; //HIGH or LOW + bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic + byte m_nPin; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED + + void writeStateToPin(); //function to update the Arduino Digital Output Pin + + public: + //constructor - called in your sketch's global variable declaration section + EX_Switch(const __FlashStringHelper *name, byte pin, bool startingState = LOW, bool invertLogic = false); + + //destructor + virtual ~EX_Switch(); + + //initialization routine + virtual void init(); + + //SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output) + virtual void beSmart(const String &str); + + //called periodically to ensure state of the switch is up to date in the SmartThings Cloud (in case an event is missed) + virtual void refresh(); + + //gets + virtual byte getPin() const {return m_nPin;} + + virtual bool getStatus() const { return m_bCurrentState; } //whether the switch is HIGH or LOW + + //sets + virtual void setPin(byte pin); + + }; +} + +#endif diff --git a/lib/ST_Anything/EX_Switch_Dim.cpp b/lib/ST_Anything/EX_Switch_Dim.cpp new file mode 100644 index 0000000..e1593ab --- /dev/null +++ b/lib/ST_Anything/EX_Switch_Dim.cpp @@ -0,0 +1,137 @@ +//****************************************************************************************** +// File: EX_Switch_Dim.cpp +// Authors: Dan G Ogorchock +// +// Summary: EX_Switch_Dim is a class which implements the SmartThings "Switch" and "Switch Level" device capabilities. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_Switch_Dim executor1(F("dimmerSwitch1"), PIN_SWITCH, PIN_LEVEL, LOW, true); +// +// st::EX_Switch_Dim() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - byte pin_pwm - REQUIRED - the Arduino Pin to be used as a pwm output +// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2016-04-30 Dan Ogorchock Original Creation +// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()" +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2018-08-30 Dan Ogorchock Adding reporting of 'level' +// 2018-12-06 Dan Ogorchock Fixed Comments +// 2019-04-10 Dan Ogorchock Corrected analogWrite() call for ESP8266 platform +// +// +//****************************************************************************************** +#include "EX_Switch_Dim.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ + //private + void EX_Switch_Dim::writeStateToPin() + { + digitalWrite(m_nPinSwitch, m_bInvertLogic ? !m_bCurrentState : m_bCurrentState); + } + + void EX_Switch_Dim::writeLevelToPin() + { +#if defined(ARDUINO_ARCH_ESP32) + if (st::Executor::debug) { + Serial.println(F("EX_Switch_Dim:: analogWrite not currently supported on ESP32!")); + } +#elif defined(ARDUINO_ARCH_ESP8266) + analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 1023)); +#else + analogWrite(m_nPinPWM, map(m_nCurrentLevel, 0, 100, 0, 255)); +#endif + } + + //public + //constructor + EX_Switch_Dim::EX_Switch_Dim(const __FlashStringHelper *name, byte pinSwitch, byte pinPWM, bool startingState, bool invertLogic) : + Executor(name), + m_bCurrentState(startingState), + m_bInvertLogic(invertLogic) + { + m_nCurrentLevel = startingState == HIGH ? 100 : 0; + setSwitchPin(pinSwitch); + setPWMPin(pinPWM); + } + + //destructor + EX_Switch_Dim::~EX_Switch_Dim() + { + + } + + void EX_Switch_Dim::init() + { + //Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + refresh(); + } + + void EX_Switch_Dim::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + if (st::Executor::debug) { + Serial.print(F("EX_Switch_Dim::beSmart s = ")); + Serial.println(s); + } + if (s == F("on")) + { + m_bCurrentState = HIGH; + } + else if (s == F("off")) + { + m_bCurrentState = LOW; + } + else //must be a set level command + { + s.trim(); + m_nCurrentLevel = byte(s.toInt()); + if (m_nCurrentLevel == 0) + { + m_bCurrentState = LOW; + } + else + { + m_bCurrentState = HIGH; + } + } + + writeStateToPin(); + writeLevelToPin(); + + //Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + refresh(); + + } + + void EX_Switch_Dim::refresh() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + Everything::sendSmartString(getName() + " " + m_nCurrentLevel); + } + + void EX_Switch_Dim::setSwitchPin(byte pin) + { + m_nPinSwitch = pin; + pinMode(m_nPinSwitch, OUTPUT); + writeStateToPin(); + } + + void EX_Switch_Dim::setPWMPin(byte pin) + { + m_nPinPWM = pin; + pinMode(m_nPinPWM, OUTPUT); + writeLevelToPin(); + } +} diff --git a/lib/ST_Anything/EX_Switch_Dim.h b/lib/ST_Anything/EX_Switch_Dim.h new file mode 100644 index 0000000..9bce739 --- /dev/null +++ b/lib/ST_Anything/EX_Switch_Dim.h @@ -0,0 +1,79 @@ +//****************************************************************************************** +// File: EX_Switch_Dim.h +// Authors: Dan G Ogorchock +// +// Summary: EX_Switch_Dim is a class which implements the SmartThings "Switch" and "Switch Level" device capabilities. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_Switch_Dim executor1(F("dimmerSwitch1"), PIN_SWITCH, PIN_LEVEL, LOW, true); +// +// st::EX_Switch_Dim() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - byte pin_pwm - REQUIRED - the Arduino Pin to be used as a pwm output +// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// - bool invertLogic - OPTIONAL - determines whether the Arduino Digital Output should use inverted logic +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2016-04-30 Dan Ogorchock Original Creation +// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()" +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2018-12-06 Dan Ogorchock Fixed Comments +// 2019-04-10 Dan Ogorchock Corrected analogWrite() call for ESP8266 platform +// +// +//****************************************************************************************** +#ifndef ST_EX_SWITCH_DIM +#define ST_EX_SWITCH_DIM + +#include "Executor.h" + +namespace st +{ + class EX_Switch_Dim: public Executor + { + private: + bool m_bCurrentState; //HIGH or LOW + bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic + byte m_nPinSwitch; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED + byte m_nPinPWM; //Arduino Pin used as a PWM Output for the switch level capability + byte m_nCurrentLevel; //Switch Level value from SmartThings (0 to 100) + + void writeStateToPin(); //function to update the Arduino Digital Output Pin + void writeLevelToPin(); //function to update the Arduino PWM Output Pin + + public: + //constructor - called in your sketch's global variable declaration section + EX_Switch_Dim(const __FlashStringHelper *name, byte pinSwitch, byte pinPWM, bool startingState = LOW, bool invertLogic = false); + + //destructor + virtual ~EX_Switch_Dim(); + + //initialization routine + virtual void init(); + + //SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output) and the LEVEL (PWM Output) + virtual void beSmart(const String &str); + + //called periodically to ensure state of the switch is up to date in the SmartThings Cloud (in case an event is missed) + virtual void refresh(); + + //gets + virtual byte getSwitchPin() const {return m_nPinSwitch;} + virtual byte getPWMPin() const { return m_nPinPWM; } + + virtual bool getStatus() const { return m_bCurrentState; } //whether the switch is HIGH or LOW + virtual bool getLevel() const { return m_nCurrentLevel; } //Dim Level of the switch + + //sets + virtual void setSwitchPin(byte pin); + virtual void setPWMPin(byte pin); + + }; +} + +#endif diff --git a/lib/ST_Anything/EX_TimedRelayPair.cpp b/lib/ST_Anything/EX_TimedRelayPair.cpp new file mode 100644 index 0000000..a08704a --- /dev/null +++ b/lib/ST_Anything/EX_TimedRelayPair.cpp @@ -0,0 +1,177 @@ +//****************************************************************************************** +// File: EX_TimedRelayPair.cpp +// Authors: Dan G Ogorchock +// +// Summary: EX_TimedRelayPair is a class which implements the "Valve" device capability, where output1 opens a valve, and +// output2 closes a valve. It features optional automatic-turn-off time delay times for for both outputs. +// +// It inherits from the st::Executor class +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_TimedRelayPair executor1(F("valve1"), PIN_RELAY1, PIN_RELAY2, LOW, true, 1000, 1000); +// +// st::EX_TimedRelayPair() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pinOutput1 - REQUIRED - the Arduino Pin to be used as a digital output +// - byte pinOutput2 - REQUIRED - the Arduino Pin to be used as a digital output +// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "closed", HIGH = "open" +// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Output should use inverted logic (e.g. active high versus active low relays) +// - long Output1Time - REQUIRED - the number of milliseconds to keep the output1 on, DEFAULTS to 1000 milliseconds, 0 = will stay on +// - long Output2Time - REQUIRED - the number of milliseconds to keep the output2 on, DEFAULTS to 1000 milliseconds, 0 = will stay on +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2019-10-30 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + +#include "EX_TimedRelayPair.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + void EX_TimedRelayPair::writeStateToPin(byte pin, bool state) + { + digitalWrite(pin, m_bInvertLogic ? !state : state); + } + +//public + //constructor + EX_TimedRelayPair::EX_TimedRelayPair(const __FlashStringHelper *name, byte pinOutput1, byte pinOutput2, bool startingState, bool invertLogic, unsigned long Output1Time, unsigned long Output2Time) : + Executor(name), + m_nOutputPin1(pinOutput1), + m_nOutputPin2(pinOutput2), + m_bCurrentState(startingState), + m_bInvertLogic(invertLogic), + m_lOutput1Time(Output1Time), + m_lOutput2Time(Output2Time), + m_lTimeChanged(0), + m_bTimerPending(false) + + { + //set pin mode + pinMode(m_nOutputPin1, OUTPUT); + pinMode(m_nOutputPin2, OUTPUT); + //update the digital outputs + if (((m_bCurrentState == HIGH) && (m_lOutput1Time > 0)) || ((m_bCurrentState == LOW) && (m_lOutput2Time > 0))) + { + m_bTimerPending = true; + } + m_lTimeChanged = millis(); + writeStateToPin(m_nOutputPin1, m_bCurrentState); + writeStateToPin(m_nOutputPin2, !m_bCurrentState); + } + + //destructor + EX_TimedRelayPair::~EX_TimedRelayPair() + { + } + + void EX_TimedRelayPair::init() + { + refresh(); + } + + //update function + void EX_TimedRelayPair::update() + { + + if (m_bTimerPending) + { + if ((m_bCurrentState == HIGH) && (millis() - m_lTimeChanged >= m_lOutput1Time)) + { + writeStateToPin(m_nOutputPin1, LOW); + } + else if ((m_bCurrentState == LOW) && (millis() - m_lTimeChanged >= m_lOutput2Time)) + { + writeStateToPin(m_nOutputPin2, LOW); + } + } + + } + + void EX_TimedRelayPair::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + if (st::Device::debug) { + Serial.print(F("EX_TimedRelayPair::beSmart s = ")); + Serial.println(s); + } + + //if ((s == F("open")) && (m_bCurrentState == LOW)) + if (s == F("open")) + { + if (m_bTimerPending) + { + if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--; + m_bTimerPending = false; + } + + m_bCurrentState = HIGH; + + //Save time turned on + m_lTimeChanged = millis(); + + //Increment number of active timers + if ((!m_bTimerPending) && (m_lOutput1Time > 0)) + { + st::Everything::bTimersPending++; + m_bTimerPending = true; + } + //Queue the relay status update the ST Cloud + refresh(); + + //update the digital outputs + writeStateToPin(m_nOutputPin2, !m_bCurrentState); + writeStateToPin(m_nOutputPin1, m_bCurrentState); + } + //else if ((s == F("close")) && (m_bCurrentState == HIGH)) + else if (s == F("close")) + { + if (m_bTimerPending) + { + if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--; + m_bTimerPending = false; + } + + m_bCurrentState = LOW; + + //Save time turned on + m_lTimeChanged = millis(); + + //Increment number of active timers + if ((!m_bTimerPending) && (m_lOutput2Time > 0)) + { + st::Everything::bTimersPending++; + m_bTimerPending = true; + } + + //Queue the relay status update the ST Cloud + refresh(); + + //update the digital outputs + writeStateToPin(m_nOutputPin1, m_bCurrentState); + writeStateToPin(m_nOutputPin2, !m_bCurrentState); + } + + } + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor + void EX_TimedRelayPair::refresh() + { + //Queue the relay status update the ST Cloud + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("open") : F("closed"))); + } + + //void EX_TimedRelayPair::setOutputPin(byte pin) + //{ + // pinMode(pin, OUTPUT); + //} + +} diff --git a/lib/ST_Anything/EX_TimedRelayPair.h b/lib/ST_Anything/EX_TimedRelayPair.h new file mode 100644 index 0000000..c884f20 --- /dev/null +++ b/lib/ST_Anything/EX_TimedRelayPair.h @@ -0,0 +1,84 @@ +//****************************************************************************************** +// File: EX_TimedRelayPair.h +// Authors: Dan G Ogorchock +// +// Summary: EX_TimedRelayPair is a class which implements the "Valve" device capability, where output1 opens a valve, and +// output2 closes a valve. It features optional automatic-turn-off time delay times for for both outputs. +// +// It inherits from the st::Executor class +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_TimedRelayPair executor1(F("valve1"), PIN_RELAY1, PIN_RELAY2, LOW, true, 1000, 1000); +// +// st::EX_TimedRelayPair() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pinOutput1 - REQUIRED - the Arduino Pin to be used as a digital output +// - byte pinOutput2 - REQUIRED - the Arduino Pin to be used as a digital output +// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "closed", HIGH = "open" +// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Output should use inverted logic (e.g. active high versus active low relays) +// - long Output1Time - REQUIRED - the number of milliseconds to keep the output1 on, DEFAULTS to 1000 milliseconds, 0 = will stay on +// - long Output2Time - REQUIRED - the number of milliseconds to keep the output2 on, DEFAULTS to 1000 milliseconds, 0 = will stay on +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2019-10-30 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + +#ifndef ST_EX_TimedRelayPair_H +#define ST_EX_TimedRelayPair_H + +#include "Executor.h" + +namespace st +{ + class EX_TimedRelayPair : public Executor //inherits from parent Executor Class + { + private: + + //following are for the digital output + bool m_bCurrentState; //HIGH or LOW + bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic + byte m_nOutputPin1; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED + byte m_nOutputPin2; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED + unsigned long m_lOutput1Time; //number of milliseconds to keep digital output HIGH before automatically turning off + unsigned long m_lOutput2Time; //number of milliseconds to keep digital output HIGH before automatically turning off + unsigned long m_lTimeChanged; //time when the digital output was last changed + bool m_bTimerPending; //true if waiting on relay timer to expire + + void writeStateToPin(byte, bool); //function to update the Arduino Digital Output Pin + + public: + //constructor - called in your sketch's global variable declaration section + EX_TimedRelayPair(const __FlashStringHelper *name, byte pinOutput1, byte pinOutput2, bool startingState = LOW, bool invertLogic = false, unsigned long Output1Time = 1000, unsigned long Output2Time = 1000); + + //destructor + virtual ~EX_TimedRelayPair(); + + //initialization function + virtual void init(); + + //update function + void update(); + + //SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output) + virtual void beSmart(const String &str); + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor + virtual void refresh(); + + //gets + //virtual byte getPin() const { return m_nOutputPin; } + virtual bool getTimerActive() const { return m_bTimerPending; } + virtual bool getStatus() const { return m_bCurrentState; } + + //sets + //virtual void setOutputPin(byte pin); + }; +} + + +#endif diff --git a/lib/ST_Anything/Everything.cpp b/lib/ST_Anything/Everything.cpp new file mode 100644 index 0000000..c438bac --- /dev/null +++ b/lib/ST_Anything/Everything.cpp @@ -0,0 +1,428 @@ +//****************************************************************************************** +// File: Everything.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: st::Everything is a generic class which essentially acts as the main() routine. +// All st::Device type objects are managed by st::Everything. It is responsible for +// for calling the correct functions within each object it is responsible for at the +// proper time. It handles all initialization of and use of the SmarThings Shield library. +// +// THere are user-definable settings which will impact the st::Everything class stored in +// Constants.h. Please edit Constants.h to adjust these settings. +// +// In general, this file should not need to be modified. +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-01-10 Dan Ogorchock Minor improvements to support Door Control Capability +// 2015-03-14 Dan Ogorchock Added public setLED() function to control ThingShield LED +// 2015-03-28 Dan Ogorchock Added throttling capability to sendStrings to improve success rate of ST Cloud getting the data ("SENDSTRINGS_INTERVAL" is in CONSTANTS.H) +// 2017-02-07 Dan Ogorchock Added support for new SmartThings v2.0 library (ThingShield, W5100, ESP8266) +// 2017-02-19 Dan Ogorchock Fixed bug in throttling capability +// 2017-04-26 Dan Ogorchock Allow each communication method to specify unique ST transmission throttling delay +// 2019-02-09 Dan Ogorchock Add update() call to Executors in support of devices like EX_Servo that need a non-blocking mechanism +// 2019-02-24 Dan Ogorchock Added new special callOnMsgRcvd2 callback capability. Allows recvd string to be manipulated in the sketch before being processed by Everything. +// 2021-01-31 Marcus van Ierssel Improved the automatic refresh to prevent it from blocking other updates. +// 2021-05-23 Dan Ogorchock Address EXP8266 v3.0.0 board support package compatibility issue with Strings +// +//****************************************************************************************** + +//#include +//#include +#include "Everything.h" + +long freeRam(); //freeRam() function prototype - useful in determining how much SRAM is available on Arduino +#if defined(ARDUINO_ARCH_SAMD) +extern "C" char* sbrk(int incr); +#endif +namespace st +{ + +//private + void Everything::updateDevices() + { + for(unsigned int index=0; indexupdate(); + sendStrings(); + } + + for (unsigned int i = 0; iupdate(); + sendStrings(); + } + } + +#if defined(ENABLE_SERIAL) + void Everything::readSerial() + { + String message; + while(Serial.available()>0) + { + char c=Serial.read(); + message+=c; + delay(10); + } + if(message.length()>0) + { + receiveSmartString(message); + } + } +#endif + + void Everything::sendStrings() + { + unsigned int index; + //Loop through the Return_String buffer and send each "|" delimited string to ST Shield + while(Return_String.length()>=1 && Return_String[0]!='|') + { + index=Return_String.indexOf("|"); + if(debug) + { + Serial.print(F("Everything: Sending: ")); + Serial.println(Return_String.substring(0, index)); + //Serial.print(F("Everything: getTransmitInterval() = ")); + //Serial.println(SmartThing->getTransmitInterval()); + } + #ifndef DISABLE_SMARTTHINGS +// if (millis() - sendstringsLastMillis < Constants::SENDSTRINGS_INTERVAL) + if (millis() - sendstringsLastMillis < SmartThing->getTransmitInterval()) + { +// delay(Constants::SENDSTRINGS_INTERVAL - (millis() - sendstringsLastMillis)); //Added due to slow ST Hub/Cloud Processing. Events were being missed. DGO 2015-03-28 + delay(SmartThing->getTransmitInterval() - (millis() - sendstringsLastMillis)); //modified to allow different values for each method of communicating to ST cloud. DGO 2017-04-26 + } + SmartThing->send(Return_String.substring(0, index)); + sendstringsLastMillis = millis(); + #endif + #if defined(ENABLE_SERIAL) && defined(DISABLE_SMARTTHINGS) + Serial.println(Return_String.substring(0, index)); + #endif + + if(callOnMsgSend!=0) + { + callOnMsgSend(Return_String.substring(0, index)); + } + + Return_String=Return_String.substring(index+1); + } + Return_String.remove(0); //clear the Return_String buffer + } + + void Everything::refreshDevices() + { + static int refresh_Executor = 0; + static int refresh_Sensor = 0; + /* + for(unsigned int i=0; irefresh(); + sendStrings(); + } + + for (unsigned int i = 0; irefresh(); + sendStrings(); + } + */ + if (refresh_Executor < m_nExecutorCount) { + m_Executors[refresh_Executor]->refresh(); + sendStrings(); + refresh_Executor++; + refLastMillis = millis() - long(Constants::DEV_REFRESH_INTERVAL) * 1000 + 4 * SmartThing->getTransmitInterval(); + } + else if (refresh_Sensor < m_nSensorCount) { + m_Sensors[refresh_Sensor]->refresh(); + sendStrings(); + refresh_Sensor++; + refLastMillis = millis() - long(Constants::DEV_REFRESH_INTERVAL) * 1000 + 4 * SmartThing->getTransmitInterval(); + } + else { + refLastMillis = millis(); + refresh_Executor = 0; + refresh_Sensor = 0; + } + } + +//public + void Everything::init() + { + Serial.begin(Constants::SERIAL_BAUDRATE); + Return_String.reserve(st::Constants::RETURN_STRING_RESERVE); //allocate Return_String buffer one time to prevent Heap Fragmentation. RETURN_STRING_RESERVE is set in Constants.h + + if(debug) + { + Serial.println(F("Everything: init started")); + Serial.print(F("Everything: Free RAM = ")); + Serial.println(freeRam()); + } + + #ifndef DISABLE_SMARTTHINGS + SmartThing->init(); + #endif + + + if(debug) + { + Serial.println(F("Everything: init ended")); + Serial.print(F("Everything: Free RAM = ")); + Serial.println(freeRam()); + } + } + + void Everything::initDevices() + { + if(debug) + { + Serial.println(F("Everything: initDevices started")); + Serial.print(F("Everything: Free RAM = ")); + Serial.println(freeRam()); + } + + for(unsigned int index=0; indexinit(); + sendStrings(); + } + + for(unsigned int index=0; indexinit(); + sendStrings(); + } + + if(debug) + { + Serial.println(F("Everything: initDevices ended")); + Serial.print(F("Everything: Free RAM = ")); + Serial.println(freeRam()); + } + + refLastMillis = millis(); //avoid immediately refreshing after initialization + } + + void Everything::run() + { + updateDevices(); //call each st::Sensor object to refresh data + + #ifndef DISABLE_SMARTTHINGS + SmartThing->run(); //call the ST Shield Library to receive any data from the ST Hub + #endif + + #if defined(ENABLE_SERIAL) + readSerial(); //read data from the Arduino IDE Serial Monitor window (useful for debugging sometimes) + #endif + + sendStrings(); //send any pending updates to ST Cloud + + #ifndef DISABLE_REFRESH //Added new check to allow user to disable REFRESH feature - setting is in Constants.h) + if ((bTimersPending == 0) && ((millis() - refLastMillis) >= long(Constants::DEV_REFRESH_INTERVAL) * 1000)) //DEV_REFRESH_INTERVAL is set in Constants.h + { + //refLastMillis = millis(); + refreshDevices(); //call each st::Device object to refresh data (this is just a safeguard to ensure the state of the Arduino and the ST Cloud stay in synch should an event be missed) + } + #endif + + if((debug) && (millis()%60000==0) && (millis()!=lastmillis)) + { + lastmillis = millis(); + Serial.print(F("Everything: Free Ram = ")); + Serial.println(freeRam()); + } + } + + bool Everything::sendSmartString(const String &str) + { + //while(str.length()>1 && str[0]=='|') //get rid of leading pipes (messes up sendStrings()'s parsing technique) + //{ + // str=str.substring(1); + //} + if((str.length()==1 && str[0]=='|') || str.length()==0) + { + return false; + } + + if(Return_String.length()+str.length()>=Constants::RETURN_STRING_RESERVE) + { + if (debug) + { + Serial.print(F("Everything: ERROR: \"")); + Serial.print(str); + Serial.println(F("\" would overflow the Return_String 'buffer'")); + } + return false; + } + else + { + Return_String+=str+"|"; //add the new message to the queue to be sent to ST Shield with a "|" delimiter + return true; + } + } + + bool Everything::sendSmartStringNow(const String &str) + { + bool queued = sendSmartString(str); + if (queued) sendStrings(); //send any pending updates to ST Cloud immediately + return queued; + } + + Device* Everything::getDeviceByName(const String &str) + { + for(unsigned int index=0; indexgetName()==str) + return (Device*)m_Sensors[index]; + } + + for(unsigned int index=0; indexgetName()==str) + return (Device*)m_Executors[index]; + } + + return 0; //null if no such device present + } + + bool Everything::addSensor(Sensor *sensor) + { + if(m_nSensorCount>=Constants::MAX_SENSOR_COUNT) + { + if(debug) + { + Serial.print(F("Did not add sensor named ")); + Serial.print(sensor->getName()); + Serial.println(F("(You've exceeded maximum number of sensors; edit Constants.h)")); + } + return false; + } + else + { + m_Sensors[m_nSensorCount]=sensor; + ++m_nSensorCount; + } + + if(debug) + { + Serial.print(F("Everything: adding sensor named ")); + Serial.println(sensor->getName()); + Serial.print(F("Everything: Free RAM = ")); + Serial.println(freeRam()); + } + return true; + } + + bool Everything::addExecutor(Executor *executor) + { + if(m_nExecutorCount>=Constants::MAX_EXECUTOR_COUNT) + { + if(debug) + { + Serial.print(F("Did not add executor named ")); + Serial.print(executor->getName()); + Serial.println(F("(You've exceeded maximum number of executors; edit Constants.h)")); + } + return false; + } + else + { + m_Executors[m_nExecutorCount]=executor; + ++m_nExecutorCount; + } + + if(debug) + { + Serial.print(F("Everything: adding executor named ")); + Serial.println(executor->getName()); + Serial.print(F("Everything: Free RAM = ")); + Serial.println(freeRam()); + } + return true; + } + + //friends! + void receiveSmartString(String message) + { + message.trim(); + if(Everything::debug && message.length()>1) + { + Serial.print(F("Everything: Received: ")); + Serial.println(message); + } + + if (Everything::callOnMsgRcvd2 != 0) + { + Everything::callOnMsgRcvd2(message); + } + + if (message == "refresh") + { + Everything::refreshDevices(); + } + else if (message.length() > 1) //ignore empty string messages from the ST Hub + { + Device *p = Everything::getDeviceByName(message.substring(0, message.indexOf(' '))); + if (p != 0) + { + p->beSmart(message); //pass the incoming SmartThings Shield message to the correct Device's beSmart() routine + } + } + + if(Everything::callOnMsgRcvd!=0) + { + Everything::callOnMsgRcvd(message); + } + + } + + //initialize static members + st::SmartThings* Everything::SmartThing=0; //initialize pointer to null + String Everything::Return_String; + Sensor* Everything::m_Sensors[Constants::MAX_SENSOR_COUNT]; + Executor* Everything::m_Executors[Constants::MAX_EXECUTOR_COUNT]; + byte Everything::m_nSensorCount=0; + byte Everything::m_nExecutorCount=0; + unsigned long Everything::lastmillis=0; + unsigned long Everything::refLastMillis=0; + unsigned long Everything::sendstringsLastMillis=0; + bool Everything::debug=false; + byte Everything::bTimersPending=0; //initialize variable + void (*Everything::callOnMsgSend)(const String &msg)=0; //initialize this callback function to null + void (*Everything::callOnMsgRcvd)(const String &msg)=0; //initialize this callback function to null + void(*Everything::callOnMsgRcvd2)(String &msg) = 0; //initialize this callback function to null + + //SmartThings static members + //#ifndef DISABLE_SMARTTHINGS + // // Please refer to Constants.h for settings that affect whether a board uses SoftwareSerial or Hardware Serial calls + // #if defined(ST_SOFTWARE_SERIAL) //use Software Serial + // SmartThingsThingShield Everything::SmartThing(Constants::pinRX, Constants::pinTX, receiveSmartString); + // #elif defined(ST_HARDWARE_SERIAL) //use Hardware Serial + // SmartThingsThingShield Everything::SmartThing(Constants::SERIAL_TYPE, receiveSmartString); + // #endif + + // SmartThingsNetworkState_t Everything::stNetworkState=(SmartThingsNetworkState_t)99; //bogus value for first pass through Everything::updateNetworkState() + //#endif +} + +//freeRam() function - useful in determining how much SRAM is available on Arduino +long freeRam() +{ +#if defined(ARDUINO_ARCH_AVR) + extern int __heap_start, *__brkval; + int v; + return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval); +#elif defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) + return ESP.getFreeHeap(); +#elif defined(ARDUINO_ARCH_SAMD) + char top; + return &top - reinterpret_cast(sbrk(0)); +#else + return -1; +#endif // ! + + +} + diff --git a/lib/ST_Anything/Everything.h b/lib/ST_Anything/Everything.h new file mode 100644 index 0000000..615c2ed --- /dev/null +++ b/lib/ST_Anything/Everything.h @@ -0,0 +1,109 @@ +//****************************************************************************************** +// File: Everything.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: st::Everything is a static class which essentially acts as the main() routine for +// a ST_Anything application. +// -All st::Device type objects (Sensors and Executors) are managed by st::Everything. +// -It calls the correct functions within each object it +// is responsible for at the proper time. +// -It handles all initialization of and use of the SmarThings Shield library. +// +// User-definable settings which will impact the st::Everything class are stored in +// Constants.h. Please edit Constants.h to adjust these settings. +// +// In general, this file should not need to be modified. +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-01-10 Dan Ogorchock Minor improvements to support Door Control Capability +// 2015-03-14 Dan Ogorchock Added public setLED() function to control ThingShield LED +// 2015-03-28 Dan Ogorchock Added throttling capability to sendStrings to improve success rate of ST Cloud getting the data ("SENDSTRINGS_INTERVAL" is in CONSTANTS.H) +// 2017-02-07 Dan Ogorchock Added support for new SmartThings v2.0 library (ThingShield, W5100, ESP8266) +// 2019-02-09 Dan Ogorchock Add update() call to Executors in support of devices like EX_Servo that need a non-blocking mechanism +// 2019-02-24 Dan Ogorchock Added new special callOnMsgRcvd2 callback capability. Allows recvd string to be manipulated in the sketch before being processed by Everything. +// 2021-05-23 Dan Ogorchock Address EXP8266 v3.0.0 board support package compatibility issue with Strings +// +//****************************************************************************************** + +#ifndef ST_EVERYTHING_H +#define ST_EVERYTHING_H + +//#include "Arduino.h" +#include "Constants.h" +#include "Sensor.h" +#include "Executor.h" + +#include "SmartThings.h" + +namespace st +{ + SmartThingsCallout_t receiveSmartString; //function prototype for ST Library callback function + + class Everything + { + private: + static Sensor* m_Sensors[Constants::MAX_SENSOR_COUNT]; //array of Sensor objects that st::Everything will keep track of + static byte m_nSensorCount; //number of st::Sensor objects added to st::Everything in your sketch Setup() routine + + static Executor* m_Executors[Constants::MAX_EXECUTOR_COUNT]; //array of Executor objects that st::Everything will keep track of + static byte m_nExecutorCount;//number of st::Executor objects added to st::Everything in your sketch Setup() routine + + + //static SmartThingsNetworkState_t stNetworkState; + + //static void updateNetworkState(); //keeps track of the current ST Shield to Hub network status + static void updateDevices(); //simply calls update on all the sensors + static void sendStrings(); //sends all updates from the devices in Return_String + static unsigned long sendstringsLastMillis; //keep track of how long since last time we sent data to ST Cloud, to enable throttling + + static unsigned long lastmillis; //used to keep track of last time run() has output freeRam() info + + //stuff for refreshing Devices + static unsigned long refLastMillis; //used to keep track of last time run() has called refreshDevices() + static void refreshDevices(); //simply calls refresh on all the Devices + + #ifdef ENABLE_SERIAL + static void readSerial(); //reads data from Arduino IDE Serial Monitor, if enabled in Constants.h + #endif + + static String Return_String; //static buffer for string data queued for transfer to SmartThings Shield - prevents dynamic memory allocation heap fragmentation + + public: + static void init(); //st::Everything initialization routine called in your sketch setup() routine + static void initDevices(); //calls the init() routine of every object added to st::Everything in your sketch setup() routine + static void run(); //st::Everything initialization routine called in your sketch loop() routine + + static bool sendSmartString(const String &str); //sendSmartString() may edit the string reference passed to it - queues messages - preferable + static bool sendSmartStringNow(const String &str); //sendSmartStringNow() may edit the string reference passed to it - sends messages immediate - only for special circumstances + + static Device* getDeviceByName(const String &str); //returns pointer to Device object by name + + static bool addSensor(Sensor *sensor); //adds a Sensor object to st::Everything's m_Sensors[] array - called in your sketch setup() routine + static bool addExecutor(Executor *executor);//adds a Executor object to st::Everything's m_Executors[] array - called in your sketch setup() routine + + static byte bTimersPending; //number of time critical events in progress - if > 0, do NOT perform refreshDevices() routine + + static bool debug; //debug flag to determine if debug print statements are executed - set value in your sketch's setup() routine + + static void (*callOnMsgSend)(const String &msg); //If this function pointer is assigned, the function it points to will be called upon every time a string is sent to the cloud. + static void (*callOnMsgRcvd)(const String &msg); //If this function pointer is assigned, the function it points to will be called upon every time a string is received from the cloud. + static void(*callOnMsgRcvd2)(String &msg); //If this function pointer is assigned, the function it points to will be called upon every time a string is received from the cloud. + + //SmartThings Object + #ifndef DISABLE_SMARTTHINGS + static st::SmartThings* SmartThing; //SmartThings Shield Library object + #endif + + friend SmartThingsCallout_t receiveSmartString; //callback function to act on data received from SmartThings Shield - called from SmartThings Shield Library + + //SmartThings Object + //#ifndef DISABLE_SMARTTHINGS + // static void setLED(uint8_t red, uint8_t green, uint8_t blue) {SmartThing.shieldSetLED(red, green, blue);} + //#endif + }; +} +#endif diff --git a/lib/ST_Anything/Executor.cpp b/lib/ST_Anything/Executor.cpp new file mode 100644 index 0000000..fb1e24d --- /dev/null +++ b/lib/ST_Anything/Executor.cpp @@ -0,0 +1,59 @@ +//****************************************************************************************** +// File: Executor.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: st::Executor is a generic class which inherits from st::Device. This is the +// parent class for the st::EX_Switch class. +// In general, this file should not need to be modified. +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2019-02-09 Dan Ogorchock Added update() function +// +// +//****************************************************************************************** + + +#include "Executor.h" + +#include "Constants.h" +#include "Everything.h" + +namespace +st +{ +//private + + + +//public + //constructor + Executor::Executor(const __FlashStringHelper *name): + Device(name) + { + + } + + //destructor + Executor::~Executor() + { + + } + + void Executor::init() + { + + } + + void Executor::update() + { + + } + + //debug flag to determine if debug print statements are executed (set value in your sketch) + bool Executor::debug=false; + +} \ No newline at end of file diff --git a/lib/ST_Anything/Executor.h b/lib/ST_Anything/Executor.h new file mode 100644 index 0000000..bc387bc --- /dev/null +++ b/lib/ST_Anything/Executor.h @@ -0,0 +1,54 @@ +//****************************************************************************************** +// File: Executor.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: st::Executor is a generic class which inherits from st::Device. This is the +// parent class for the st::EX_Switch class. +// In general, this file should not need to be modified. +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2019-02-09 Dan Ogorchock Added update() function +// +// +//****************************************************************************************** + +#ifndef ST_EXECUTOR_H +#define ST_EXECUTOR_H + +#include "Device.h" + +namespace st +{ + class Executor: public Device + { + private: + //Inherits private members from parent st::Device class + + public: + //constructor + Executor(const __FlashStringHelper *name); + + //destructor + virtual ~Executor(); + + //initialization routine + virtual void init(); + + //update function + virtual void update(); + + //debug flag to determine if debug print statements are executed (set value in your sketch) + static bool debug; + + }; + + +} + + + +#endif \ No newline at end of file diff --git a/lib/ST_Anything/IS_Button.cpp b/lib/ST_Anything/IS_Button.cpp new file mode 100644 index 0000000..39d3cd3 --- /dev/null +++ b/lib/ST_Anything/IS_Button.cpp @@ -0,0 +1,117 @@ +//****************************************************************************************** +// File: IS_Button.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_Button is a class which implements the SmartThings "Contact Sensor" device capability. +// It inherits from the st::InterruptSensor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_Button sensor(F("button1"), PIN_BUTTON1, 1000, LOW, true, 500); +// +// st::IS_Button() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - should be "button1", "button2", "button3", etc... +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input +// - long reqNumMillisHeld - Required - number of milliseconds required needed to detect a "Held" condition versus a "Pushed" (default = 1000) +// - bool iState - OPTIONAL - LOW or HIGH - determines which value indicates the interrupt is true (default = HIGH) +// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP (default - true) +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false triggers) (default = 500) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2017-03-25 Dan Original Creation +// 2019-09-7 Dan Ogorchock Send Button 'init' messages for automatic setting of numberOfButtons attribute +// 2020-09-19 Dan Ogorchock Modified to not wait until button is released to send 'held' event, also added released events +// +//****************************************************************************************** + +#include "IS_Button.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + +//public + //constructor + IS_Button::IS_Button(const __FlashStringHelper *name, byte pin, long reqNumMillisHeld, bool iState, bool internalPullup, long numReqCounts) : + InterruptSensor(name, pin, iState, internalPullup, numReqCounts), //use parent class' constructor + m_lreqNumMillisHeld(reqNumMillisHeld) + { + } + + //destructor + IS_Button::~IS_Button() + { + } + + void IS_Button::init() + { + //get current status of motion sensor by calling parent class's init() routine - no need to duplicate it here! + InterruptSensor::init(); + //m_lTimeBtnPressed = 0; + refresh(); + } + + //called periodically by Everything class to ensure ST Cloud is kept up yo date. HOWEVER, not useful for the IS_Button. + void IS_Button::refresh() + { + //Send 'init' message to allow Parent Driver to set numberOfButtons attribute automatically + Everything::sendSmartString(getName() + F(" init")); + } + + void IS_Button::update() + { + InterruptSensor::update(); + + if (getStatus()) + { + if (((millis() - m_lTimeBtnPressed) >= m_lreqNumMillisHeld) && (!m_bHeldSent)) + { + m_bHeldSent = true; + //add the "held" event to the buffer to be queued for transfer to SmartThings + Everything::sendSmartString(getName() + F(" held")); + } + + } + + } + + void IS_Button::runInterrupt() + { + //Capture time of button down event so we can figure it whether to send "pushed" or "held" on button release + m_lTimeBtnPressed = millis(); + + //Serial.println("IS_Button: in runInterrupt()"); + } + + void IS_Button::runInterruptEnded() + { + //Serial.println("IS_Button: in runInterruptEnded()"); + //Serial.println(millis()); + //Serial.println(m_lTimeBtnPressed); + //Serial.println(m_lreqNumMillisHeld); + + if (!m_bFirstRun) //Prevent sending data to SmartThings during initial startup + { + if ((millis() - m_lTimeBtnPressed) < m_lreqNumMillisHeld) + { + //immediately send the "pushed" event to the Hub (to make sure it arrives before the 'released' event) + Everything::sendSmartStringNow(getName() + F(" pushed")); + } + //add the "released" event to the buffer to be queued for transfer to Hub + Everything::sendSmartString(getName() + F(" released")); + + m_bHeldSent = false; + } + else + { + m_bFirstRun = false; + } + + } + +} diff --git a/lib/ST_Anything/IS_Button.h b/lib/ST_Anything/IS_Button.h new file mode 100644 index 0000000..5b60251 --- /dev/null +++ b/lib/ST_Anything/IS_Button.h @@ -0,0 +1,68 @@ +//****************************************************************************************** +// File: IS_Button.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_Button is a class which implements the SmartThings "Contact Sensor" device capability. +// It inherits from the st::InterruptSensor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_Button sensor(F("button1"), PIN_BUTTON1, 1000, LOW, true, 500); +// +// st::IS_Button() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - should be "button1", "button2", "button3", etc... +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input +// - long reqNumMillisHeld - Required - number of milliseconds required needed to detect a "Held" condition versus a "Pushed" (default = 1000) +// - bool iState - OPTIONAL - LOW or HIGH - determines which value indicates the interrupt is true (default = HIGH) +// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP (default - true) +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false triggers) (default = 500) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2017-03-25 Dan Ogorchock Original Creation +// 2020-09-19 Dan Ogorchock Modified to not wait until button is released to send 'held' event, also added released events +// +//****************************************************************************************** + +#ifndef ST_IS_BUTTON_H +#define ST_IS_BUTTON_H + +#include "InterruptSensor.h" + +namespace st +{ + class IS_Button: public InterruptSensor + { + private: + unsigned long m_lTimeBtnPressed; //time when the digital input went high + unsigned long m_lreqNumMillisHeld; //amount of time required to trigger "held" instead of "pushed" + bool m_bFirstRun = true; //used to prevent sending inadvertent button pushed/held message on startup + bool m_bHeldSent = false; //used to prevent sending multiple 'held' messages + + public: + //constructor - called in your sketch's global variable declaration section + IS_Button(const __FlashStringHelper *name, byte pin, long reqNumMillisHeld = 1000, bool iState = LOW, bool internalPullup = true, long numReqCounts = 500); //(defaults to using internal pullup resistors) + + //destructor + virtual ~IS_Button(); + + //initialization function + virtual void init(); + + //called periodically by Everything class to ensure ST Cloud is kept up to date. Not used for IS_Button. + virtual void refresh(); + + //handles what to do when interrupt is triggered + virtual void runInterrupt(); + + //handles what to do when interrupt is ended + virtual void runInterruptEnded(); + + //override update method + virtual void update(); + }; +} + + +#endif diff --git a/lib/ST_Anything/IS_CarbonMonoxide.cpp b/lib/ST_Anything/IS_CarbonMonoxide.cpp new file mode 100644 index 0000000..224d0e9 --- /dev/null +++ b/lib/ST_Anything/IS_CarbonMonoxide.cpp @@ -0,0 +1,73 @@ +//****************************************************************************************** +// File: IS_CarbonMonoxide.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_Smoke is a class which implements the SmartThings "Carbon Monoxide Detector" device capability. +// It inherits from the st::IS_Smoke class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_CarbonMonoxide sensor6("carbonMonoxide1", PIN_CO, HIGH, false, 500); +// +// st::IS_CarbonMonoxide() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input +// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-04-19 Dan & Daniel Original Creation +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// +// +//****************************************************************************************** + +#include "IS_CarbonMonoxide.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + +//public + //constructor + IS_CarbonMonoxide::IS_CarbonMonoxide(const __FlashStringHelper *name, byte pin, bool iState, bool pullup, long numReqCounts) : + InterruptSensor(name, pin, iState, pullup, numReqCounts) //use parent class' constructor + { + } + + //destructor + IS_CarbonMonoxide::~IS_CarbonMonoxide() + { + } + + void IS_CarbonMonoxide::init() + { + //get current status of motion sensor by calling parent class's init() routine - no need to duplicate it here! + InterruptSensor::init(); + } + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor + void IS_CarbonMonoxide::refresh() + { + Everything::sendSmartString(getName() + (getStatus() ? F(" clear") : F(" detected"))); + } + + void IS_CarbonMonoxide::runInterrupt() + { + //add the "closed" event to the buffer to be queued for transfer to the ST Shield + Everything::sendSmartString(getName() + F(" clear")); + } + + void IS_CarbonMonoxide::runInterruptEnded() + { + //add the "open" event to the buffer to be queued for transfer to the ST Shield + Everything::sendSmartString(getName() + F(" detected")); + } + +} \ No newline at end of file diff --git a/lib/ST_Anything/IS_CarbonMonoxide.h b/lib/ST_Anything/IS_CarbonMonoxide.h new file mode 100644 index 0000000..eb92cf0 --- /dev/null +++ b/lib/ST_Anything/IS_CarbonMonoxide.h @@ -0,0 +1,63 @@ +//****************************************************************************************** +// File: IS_CarbonMonoxide.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_Smoke is a class which implements the SmartThings "Carbon Monoxide Detector" device capability. +// It inherits from the st::IS_Smoke class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_CarbonMonoxide sensor6("carbonMonoxide1", PIN_CO, HIGH, false, 500); +// +// st::IS_CarbonMonoxide() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input +// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-04-19 Dan & Daniel Original Creation +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// +// +//****************************************************************************************** + +#ifndef ST_IS_CARBONMONOXIDE_H +#define ST_IS_CARBONMONOXIDE_H + +#include "InterruptSensor.h" + +namespace st +{ + class IS_CarbonMonoxide: public InterruptSensor + { + private: + //inherits everything necessary from parent IS_Smoke Class + + public: + //constructor - called in your sketch's global variable declaration section + IS_CarbonMonoxide(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup = false, long numReqCounts = 0); //(defaults to NOT using internal pullup resistors, and required counts = 0) + + //destructor + virtual ~IS_CarbonMonoxide(); + + //initialization function + virtual void init(); + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the sensor + virtual void refresh(); + + //handles what to do when interrupt is triggered + virtual void runInterrupt(); + + //handles what to do when interrupt is ended + virtual void runInterruptEnded(); + + }; +} + + +#endif \ No newline at end of file diff --git a/lib/ST_Anything/IS_Contact.cpp b/lib/ST_Anything/IS_Contact.cpp new file mode 100644 index 0000000..979ce1a --- /dev/null +++ b/lib/ST_Anything/IS_Contact.cpp @@ -0,0 +1,74 @@ +//****************************************************************************************** +// File: IS_Contact.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_Contact is a class which implements the SmartThings "Contact Sensor" device capability. +// It inherits from the st::InterruptSensor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_Contact sensor6(F("contact1"), PIN_CONTACT, HIGH, true, 500); +// +// st::IS_Contact() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input +// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-03-17 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// +// +//****************************************************************************************** + +#include "IS_Contact.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + +//public + //constructor + IS_Contact::IS_Contact(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup, long numReqCounts) : + InterruptSensor(name, pin, iState, internalPullup, numReqCounts) //use parent class' constructor + { + } + + //destructor + IS_Contact::~IS_Contact() + { + } + + void IS_Contact::init() + { + //get current status of motion sensor by calling parent class's init() routine - no need to duplicate it here! + InterruptSensor::init(); + } + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor + void IS_Contact::refresh() + { + Everything::sendSmartString(getName() + (getStatus() ? F(" closed") : F(" open"))); + } + + void IS_Contact::runInterrupt() + { + //add the "closed" event to the buffer to be queued for transfer to the ST Shield + Everything::sendSmartString(getName() + F(" closed")); + } + + void IS_Contact::runInterruptEnded() + { + //add the "open" event to the buffer to be queued for transfer to the ST Shield + Everything::sendSmartString(getName() + F(" open")); + } + +} diff --git a/lib/ST_Anything/IS_Contact.h b/lib/ST_Anything/IS_Contact.h new file mode 100644 index 0000000..ce136b5 --- /dev/null +++ b/lib/ST_Anything/IS_Contact.h @@ -0,0 +1,64 @@ +//****************************************************************************************** +// File: IS_Contact.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_Contact is a class which implements the SmartThings "Contact Sensor" device capability. +// It inherits from the st::InterruptSensor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_Contact sensor6(F("contact1"), PIN_CONTACT, HIGH, true, 500); +// +// st::IS_Contact() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input +// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-03-17 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// +// +//****************************************************************************************** + +#ifndef ST_IS_CONTACT_H +#define ST_IS_CONTACT_H + +#include "InterruptSensor.h" + +namespace st +{ + class IS_Contact: public InterruptSensor + { + private: + //inherits everything necessary from parent InterruptSensor Class + + public: + //constructor - called in your sketch's global variable declaration section + IS_Contact(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup = false, long numReqCounts = 0); //(defaults to NOT using internal pullup resistors, and required counts = 0) + + //destructor + virtual ~IS_Contact(); + + //initialization function + virtual void init(); + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor + virtual void refresh(); + + //handles what to do when interrupt is triggered + virtual void runInterrupt(); + + //handles what to do when interrupt is ended + virtual void runInterruptEnded(); + + }; +} + + +#endif diff --git a/lib/ST_Anything/IS_DoorControl.cpp b/lib/ST_Anything/IS_DoorControl.cpp new file mode 100644 index 0000000..8154d0d --- /dev/null +++ b/lib/ST_Anything/IS_DoorControl.cpp @@ -0,0 +1,162 @@ +//****************************************************************************************** +// File: IS_DoorControl.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_DoorControl is a class which implements the SmartThings "Door Control" device capability. It features +// an automatic-turn-off time delay for a relay to actuate a button press. This is useful for controlling +// a garage door. Use the input to monitor a magnetic door contact sensor. Use the output to control a relay to +// "press the garage door button" to open/close the garage door. +// +// It inherits from the st::InterruptSensor class and clones much from the st::Executor Class +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_DoorControl sensor3(F("doorControl1"), PIN_CONTACT_DOOR_1, LOW, true, PIN_RELAY_DOOR_1, LOW, true, 1000, 1000, true); +// +// st::IS_DoorControl() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pinInput - REQUIRED - the Arduino Pin to be used as a digital input +// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - REQUIRED - true == INTERNAL_PULLUP +// - byte pinOutput - REQUIRED - the Arduino Pin to be used as a digital output +// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Output should use inverted logic +// - long delayTime - REQUIRED - the number of milliseconds to keep the output on +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms) +// - bool useMomentary - OPTIONAL - use momentary output (true) or standard switch (false) (defaults to true) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-07 Dan Ogorchock Original Creation +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2018-11-07 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability +// 2019-07-24 Dan Ogorchock Added parameter to use output as a simple switch instead of momentary output +// +// +//****************************************************************************************** + +#include "IS_DoorControl.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + void IS_DoorControl::writeStateToPin() + { + digitalWrite(m_nOutputPin, m_bInvertLogic ? !m_bCurrentState : m_bCurrentState); + } + +//public + //constructor + IS_DoorControl::IS_DoorControl(const __FlashStringHelper *name, byte pinInput, bool iState, bool pullup, byte pinOutput, bool startingState, bool invertLogic, unsigned long delayTime, long numReqCounts, bool useMomentary) : + InterruptSensor(name, pinInput, iState, pullup, numReqCounts), //use parent class' constructor + m_bCurrentState(startingState), + m_bInvertLogic(invertLogic), + m_lDelayTime(delayTime), + m_bUseMomentary(useMomentary), + m_lTimeTurnedOn(0), + m_bTimerPending(false) + { + setOutputPin(pinOutput); + } + + //destructor + IS_DoorControl::~IS_DoorControl() + { + } + + void IS_DoorControl::init() + { + //get current status of contact sensor by calling parent class's init() routine - no need to duplicate it here! + InterruptSensor::init(); + } + + //update function + void IS_DoorControl::update() + { + if (m_bTimerPending) { + //Turn off digital output if timer has expired + if ((m_bCurrentState == HIGH) && (millis() - m_lTimeTurnedOn >= m_lDelayTime)) + { + m_bCurrentState = LOW; + writeStateToPin(); + //Decrement number of active timers + if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--; + m_bTimerPending = false; + } + } + //check to see if input pin has changed state + InterruptSensor::update(); + } + + void IS_DoorControl::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + if (st::InterruptSensor::debug) { + Serial.print(F("IS_ContactRelay::beSmart s = ")); + Serial.println(s); + } + + if ( (s == F("on")) || (m_bUseMomentary && (s == F("off")))) + { + m_bCurrentState = HIGH; + + if (m_bUseMomentary) { + //Save time turned on + m_lTimeTurnedOn = millis(); + + //Increment number of active timers + if (!m_bTimerPending) + { + st::Everything::bTimersPending++; + m_bTimerPending = true; + } + } + if (m_bUseMomentary) { + //Queue the door status update the ST Cloud + Everything::sendSmartStringNow(getName() + (getStatus() ? F(" opening") : F(" closing"))); + } + } + else if (s == F("off")) + { + m_bCurrentState = LOW; + + //Decrement number of active timers + if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--; + m_bTimerPending = false; + } + + //update the digital output + writeStateToPin(); + } + + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor + void IS_DoorControl::refresh() + { + Everything::sendSmartString(getName() + (getStatus() ? F(" closed") : F(" open"))); + } + + void IS_DoorControl::runInterrupt() + { + //add the "closed" event to the buffer to be queued for transfer to the ST Shield + Everything::sendSmartString(getName() + F(" closed")); + } + + void IS_DoorControl::runInterruptEnded() + { + //add the "open" event to the buffer to be queued for transfer to the ST Shield + Everything::sendSmartString(getName() + F(" open")); + } + + void IS_DoorControl::setOutputPin(byte pin) + { + m_nOutputPin = pin; + pinMode(m_nOutputPin, OUTPUT); + writeStateToPin(); + } + +} \ No newline at end of file diff --git a/lib/ST_Anything/IS_DoorControl.h b/lib/ST_Anything/IS_DoorControl.h new file mode 100644 index 0000000..a78e8de --- /dev/null +++ b/lib/ST_Anything/IS_DoorControl.h @@ -0,0 +1,97 @@ +//****************************************************************************************** +// File: IS_DoorControl.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_DoorControl is a class which implements the SmartThings "Door Control" device capability. It features +// an automatic-turn-off time delay for a relay to actuate a button press. This is useful for controlling +// a garage door. Use the input to monitor a magnetic door contact sensor. Use the output to control a relay to +// "press the garage door button" to open/close the garage door. +// +// It inherits from the st::InterruptSensor class and clones much from the st::Executor Class +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_DoorControl sensor3(F("doorControl1"), PIN_CONTACT_DOOR_1, LOW, true, PIN_RELAY_DOOR_1, LOW, true, 1000, 1000, true); +// +// st::IS_DoorControl() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pinInput - REQUIRED - the Arduino Pin to be used as a digital input +// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - REQUIRED - true == INTERNAL_PULLUP +// - byte pinOutput - REQUIRED - the Arduino Pin to be used as a digital output +// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Output should use inverted logic +// - long delayTime - REQUIRED - the number of milliseconds to keep the output on +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms) +// - bool useMomentary - OPTIONAL - use momentary output (true) or standard switch (false) (defaults to true) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-07 Dan Ogorchock Original Creation +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2018-11-07 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability +// 2019-07-24 Dan Ogorchock Added parameter to use output as a simple switch instead of momentary output +// +// +//****************************************************************************************** + +#ifndef ST_IS_DOORCONTROL_H +#define ST_IS_DOORCONTROL_H + +#include "InterruptSensor.h" + +namespace st +{ + class IS_DoorControl : public InterruptSensor + { + private: + //inherits everything necessary from parent InterruptSensor Class for the Contact Sensor + + //following are for the digital output + bool m_bCurrentState; //HIGH or LOW + bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic + bool m_bUseMomentary; //determines whether the output should be momentary or simple switch + byte m_nOutputPin; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED + unsigned long m_lDelayTime; //number of milliseconds to keep digital output active before automatically turning off + unsigned long m_lTimeTurnedOn; //time when the digital output was turned on + bool m_bTimerPending; //true if waiting on relay timer to expire + + void writeStateToPin(); //function to update the Arduino Digital Output Pin + + + public: + //constructor - momentary output - called in your sketch's global variable declaration section + IS_DoorControl(const __FlashStringHelper *name, byte pinInput, bool iState, bool pullup, byte pinOutput, bool startingState, bool invertLogic, unsigned long delayTime, long numReqCounts = 0, bool useMomentary = true); + + //destructor + virtual ~IS_DoorControl(); + + //initialization function + virtual void init(); + + //update function + void update(); + + //SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output) + virtual void beSmart(const String &str); + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor + virtual void refresh(); + + //handles what to do when interrupt is triggered + virtual void runInterrupt(); + + //handles what to do when interrupt is ended + virtual void runInterruptEnded(); + + //gets + virtual byte getPin() const { return m_nOutputPin; } + + //sets + virtual void setOutputPin(byte pin); + }; +} + + +#endif \ No newline at end of file diff --git a/lib/ST_Anything/IS_LatchingRelaySwitch.cpp b/lib/ST_Anything/IS_LatchingRelaySwitch.cpp new file mode 100644 index 0000000..34273e6 --- /dev/null +++ b/lib/ST_Anything/IS_LatchingRelaySwitch.cpp @@ -0,0 +1,206 @@ +//****************************************************************************************** +// File: IS_LatchingRelaySwitch.cpp +// Authors: Dan G Ogorchock +// +// Summary: IS_LatchingRelaySwitch is a class which implements the "Valve" device capability, where output1 opens a valve, and +// output2 closes a valve. It features optional automatic-turn-off time delay times for for both outputs. +// +// It inherits from the st::InterruptSensor class +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_LatchingRelaySwitch sensor1(F("switch1"), PIN_INPUT, HIGH, true, 500, PIN_RELAY1, PIN_RELAY2, LOW, true, 1000, 1000); +// +// st::IS_LatchingRelaySwitch() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pinInput - REQUIRED - the Arduino Pin to be used as a digital input to determine the switch state of latching relay +// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - REQUIRED - true == INTERNAL_PULLUP +// - long numReqCounts - REQUIRED - number of counts before changing state of input (prevent false alarms) +// - byte pinOutput1 - REQUIRED - the Arduino Pin to be used as a digital output +// - byte pinOutput2 - REQUIRED - the Arduino Pin to be used as a digital output +// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "closed", HIGH = "open" +// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Output should use inverted logic (e.g. active high versus active low relays) +// - long Output1Time - REQUIRED - the number of milliseconds to keep the output1 on, DEFAULTS to 1000 milliseconds, 0 = will stay on +// - long Output2Time - REQUIRED - the number of milliseconds to keep the output2 on, DEFAULTS to 1000 milliseconds, 0 = will stay on +// - bool initializeOutputs - OPTIONAL - determines if the digital outputs are activated during initialization/startup, defaults to 'false' +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2020-06-26 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + +#include "IS_LatchingRelaySwitch.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + void IS_LatchingRelaySwitch::writeStateToPin(byte pin, bool state) + { + digitalWrite(pin, m_bInvertLogic ? !state : state); + } + +//public + //constructor + IS_LatchingRelaySwitch::IS_LatchingRelaySwitch(const __FlashStringHelper *name, byte pinInput, bool iState, bool internalPullup, long numReqCounts, byte pinOutput1, byte pinOutput2, bool startingState, bool invertLogic, unsigned long Output1Time, unsigned long Output2Time, bool initializeOutputs) : + InterruptSensor(name, pinInput, iState, internalPullup, numReqCounts), //use parent class' constructor, + m_nOutputPin1(pinOutput1), + m_nOutputPin2(pinOutput2), + m_bCurrentState(startingState), + m_bInvertLogic(invertLogic), + m_lOutput1Time(Output1Time), + m_lOutput2Time(Output2Time), + m_lTimeChanged(0), + m_bTimerPending(false) + + { + //set pin mode + pinMode(m_nOutputPin1, OUTPUT); + pinMode(m_nOutputPin2, OUTPUT); + + if (initializeOutputs) + { + //update the digital outputs + if (((m_bCurrentState == HIGH) && (m_lOutput1Time > 0)) || ((m_bCurrentState == LOW) && (m_lOutput2Time > 0))) + { + m_bTimerPending = true; + } + m_lTimeChanged = millis(); + writeStateToPin(m_nOutputPin1, m_bCurrentState); + writeStateToPin(m_nOutputPin2, !m_bCurrentState); + } + else + { + //Make sure both digital outputs are 'off' if initializeOutputs == false + writeStateToPin(m_nOutputPin1, LOW); + writeStateToPin(m_nOutputPin2, LOW); + } + + + } + + //destructor + IS_LatchingRelaySwitch::~IS_LatchingRelaySwitch() + { + } + + void IS_LatchingRelaySwitch::init() + { + //get current status of switch by calling parent class's init() routine - no need to duplicate it here! + InterruptSensor::init(); + //refresh(); + } + + //update function + void IS_LatchingRelaySwitch::update() + { + + if (m_bTimerPending) + { + if ((m_bCurrentState == HIGH) && (millis() - m_lTimeChanged >= m_lOutput1Time)) + { + writeStateToPin(m_nOutputPin1, LOW); + } + else if ((m_bCurrentState == LOW) && (millis() - m_lTimeChanged >= m_lOutput2Time)) + { + writeStateToPin(m_nOutputPin2, LOW); + } + } + + //make sure to call the parent class' update() since we overrode it for the above timer logic + InterruptSensor::update(); + } + + void IS_LatchingRelaySwitch::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + if (st::Device::debug) { + Serial.print(F("IS_LatchingRelaySwitch::beSmart s = ")); + Serial.println(s); + } + + //if ((s == F("open")) && (m_bCurrentState == LOW)) + if (s == F("on")) + { + if (m_bTimerPending) + { + if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--; + m_bTimerPending = false; + } + + m_bCurrentState = HIGH; + + //Save time turned on + m_lTimeChanged = millis(); + + //Increment number of active timers + if ((!m_bTimerPending) && (m_lOutput1Time > 0)) + { + st::Everything::bTimersPending++; + m_bTimerPending = true; + } + //Queue the relay status update the ST Cloud + //refresh(); + + //update the digital outputs + writeStateToPin(m_nOutputPin2, !m_bCurrentState); + writeStateToPin(m_nOutputPin1, m_bCurrentState); + } + //else if ((s == F("close")) && (m_bCurrentState == HIGH)) + else if (s == F("off")) + { + if (m_bTimerPending) + { + if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--; + m_bTimerPending = false; + } + + m_bCurrentState = LOW; + + //Save time turned on + m_lTimeChanged = millis(); + + //Increment number of active timers + if ((!m_bTimerPending) && (m_lOutput2Time > 0)) + { + st::Everything::bTimersPending++; + m_bTimerPending = true; + } + + //Queue the relay status update the Hub + //refresh(); + + //update the digital outputs + writeStateToPin(m_nOutputPin1, m_bCurrentState); + writeStateToPin(m_nOutputPin2, !m_bCurrentState); + } + + } + + //called periodically by Everything class to ensure Hub is kept consistent with the state of the contact sensor + void IS_LatchingRelaySwitch::refresh() + { + //Queue the relay status update the Hub + //Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + Everything::sendSmartString(getName() + (getStatus() ? F(" off") : F(" on"))); + } + + void IS_LatchingRelaySwitch::runInterrupt() + { + //add the "closed" event to the buffer to be queued for transfer to the ST Shield + Everything::sendSmartString(getName() + F(" off")); + } + + void IS_LatchingRelaySwitch::runInterruptEnded() + { + //add the "open" event to the buffer to be queued for transfer to the ST Shield + Everything::sendSmartString(getName() + F(" on")); + } + +} diff --git a/lib/ST_Anything/IS_LatchingRelaySwitch.h b/lib/ST_Anything/IS_LatchingRelaySwitch.h new file mode 100644 index 0000000..e5026ab --- /dev/null +++ b/lib/ST_Anything/IS_LatchingRelaySwitch.h @@ -0,0 +1,93 @@ +//****************************************************************************************** +// File: IS_LatchingRelaySwitch.h +// Authors: Dan G Ogorchock +// +// Summary: IS_LatchingRelaySwitch is a class which implements the "Valve" device capability, where output1 opens a valve, and +// output2 closes a valve. It features optional automatic-turn-off time delay times for for both outputs. +// +// It inherits from the st::InterruptSensor class +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_LatchingRelaySwitch sensor1(F("switch1"), PIN_INPUT, HIGH, true, 500, PIN_RELAY1, PIN_RELAY2, LOW, true, 1000, 1000); +// +// st::IS_LatchingRelaySwitch() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pinInput - REQUIRED - the Arduino Pin to be used as a digital input to determine switch the state of latching relay +// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - REQUIRED - true == INTERNAL_PULLUP +// - long numReqCounts - REQUIRED - number of counts before changing state of input (prevent false alarms) +// - byte pinOutput1 - REQUIRED - the Arduino Pin to be used as a digital output +// - byte pinOutput2 - REQUIRED - the Arduino Pin to be used as a digital output +// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "closed", HIGH = "open" +// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Output should use inverted logic (e.g. active high versus active low relays) +// - long Output1Time - REQUIRED - the number of milliseconds to keep the output1 on, DEFAULTS to 1000 milliseconds, 0 = will stay on +// - long Output2Time - REQUIRED - the number of milliseconds to keep the output2 on, DEFAULTS to 1000 milliseconds, 0 = will stay on +// - bool initializeOutputs - OPTIONAL - determines if the digital outputs are activated during initialization/startup, defaults to 'false' +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2020-06-26 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + +#ifndef ST_IS_LatchingRelaySwitch_H +#define ST_IS_LatchingRelaySwitch_H + +#include "InterruptSensor.h" + +namespace st +{ + class IS_LatchingRelaySwitch : public InterruptSensor //inherits from parent InterruptSensor Class + { + private: + + //following are for the digital output + bool m_bCurrentState; //HIGH or LOW + bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic + byte m_nOutputPin1; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED + byte m_nOutputPin2; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED + unsigned long m_lOutput1Time; //number of milliseconds to keep digital output HIGH before automatically turning off + unsigned long m_lOutput2Time; //number of milliseconds to keep digital output HIGH before automatically turning off + unsigned long m_lTimeChanged; //time when the digital output was last changed + bool m_bTimerPending; //true if waiting on relay timer to expire + + void writeStateToPin(byte, bool); //function to update the Arduino Digital Output Pin + + public: + //constructor - called in your sketch's global variable declaration section + IS_LatchingRelaySwitch(const __FlashStringHelper *name, byte pinInput, bool iState, bool internalPullup, long numReqCounts, byte pinOutput1, byte pinOutput2, bool startingState = LOW, bool invertLogic = false, unsigned long Output1Time = 1000, unsigned long Output2Time = 1000, bool initializeOutputs = false); + + //destructor + virtual ~IS_LatchingRelaySwitch(); + + //initialization function + virtual void init(); + + //update function + void update(); + + //SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output) + virtual void beSmart(const String &str); + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor + virtual void refresh(); + + //handles what to do when interrupt is triggered + virtual void runInterrupt(); + + //handles what to do when interrupt is ended + virtual void runInterruptEnded(); + + //gets + //virtual byte getPin() const { return m_nOutputPin; } + virtual bool getTimerActive() const { return m_bTimerPending; } + virtual bool getStatus() const { return m_bCurrentState; } + + }; +} + + +#endif diff --git a/lib/ST_Anything/IS_Motion.cpp b/lib/ST_Anything/IS_Motion.cpp new file mode 100644 index 0000000..804ef62 --- /dev/null +++ b/lib/ST_Anything/IS_Motion.cpp @@ -0,0 +1,118 @@ +//****************************************************************************************** +// File: IS_Motion.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_Motion is a class which implements the SmartThings "Motion Sensor" device capability. +// It inherits from the st::InterruptSensor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_Motion sensor5(F("motion1"), PIN_MOTION, HIGH, false, 500); +// +// st::IS_Motion() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - bool iState - OPTIONAL - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms) +// - long inactiveTimeout - OPTIONAL - number of milliseconds motion must be inactive before sending update to hub (default = 0) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2016-09-03 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability +// 2017-01-25 Dan Ogorchock Corrected issue with INPUT_PULLUP per request of Jiri Culik +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2020-01-31 Dan Ogorchock Added optional inactivity timeout +// +// +//****************************************************************************************** + +#include "IS_Motion.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + +//public + //constructor + IS_Motion::IS_Motion(const __FlashStringHelper *name, byte pin, bool iState, bool pullup, long numReqCounts, long inactiveTimeout) : + InterruptSensor(name, pin, iState, pullup, numReqCounts), //use parent class' constructor + calibrated(false), + m_inactiveTimeout(inactiveTimeout), + m_inactiveTimerRunning(false) + { + } + + //destructor + IS_Motion::~IS_Motion() + { + } + + void IS_Motion::init() + { + if (debug){ + Serial.println(F("IS_Motion: 30 second Motion Sensor Calibration Started...")); + } + //calibrate the PIR Motion Sensor + digitalWrite(getInterruptPin(), LOW); + timer=millis(); + //delay(30000); + } + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the motion sensor + void IS_Motion::refresh() + { + Everything::sendSmartString(getName() + (getStatus() ? F(" active") : F(" inactive"))); + } + + void IS_Motion::runInterrupt() + { + if (m_inactiveTimerRunning == false) { + //add the "active" event to the buffer to be queued for transfer to the ST Shield + Everything::sendSmartString(getName() + F(" active")); + } + //cancel any inactivity timer that may be running + m_inactiveTimerRunning = false; + + } + + void IS_Motion::runInterruptEnded() + { + //start inactivity timer + m_inactiveTimer = millis(); + m_inactiveTimerRunning = true; + } + + void IS_Motion::update() + { + if (calibrated) { + InterruptSensor::update(); + + if ((m_inactiveTimerRunning == true) && (millis() > m_inactiveTimer + m_inactiveTimeout)) { + m_inactiveTimerRunning = false; + //add the "inactive" event to the buffer to be queued for transfer to the ST Shield + Everything::sendSmartString(getName() + F(" inactive")); + } + } + else + if(millis()>timer+30000) + { + calibrated=true; + + //get current status of motion sensor by calling parent class's init() routine - no need to duplicate it here! + setInterruptPin(getInterruptPin()); + InterruptSensor::init(); + + if (debug) + { + Serial.println(F("IS_Motion: Motion Sensor Calibration Finished")); + } + } + } + +} diff --git a/lib/ST_Anything/IS_Motion.h b/lib/ST_Anything/IS_Motion.h new file mode 100644 index 0000000..4ac62eb --- /dev/null +++ b/lib/ST_Anything/IS_Motion.h @@ -0,0 +1,76 @@ +//****************************************************************************************** +// File: IS_Motion.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_Motion is a class which implements the SmartThings "Motion Sensor" device capability. +// It inherits from the st::InterruptSensor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_Motion sensor5(F("motion1"), PIN_MOTION, HIGH, false, 500); +// +// st::IS_Motion() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - bool iState - OPTIONAL - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms) +// - long inactiveTimeout - OPTIONAL - number of milliseconds motion must be inactive before sending update to hub (default = 0) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2016-09-03 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability +// 2017-01-25 Dan Ogorchock Corrected issue with INPUT_PULLUP per request of Jiri Culik +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2020-01-31 Dan Ogorchock Added optional inactivity timeout +// +// +//****************************************************************************************** + +#ifndef ST_IS_MOTION_H +#define ST_IS_MOTION_H + +#include "InterruptSensor.h" + +namespace st +{ + class IS_Motion: public InterruptSensor + { + private: + //inherits everything necessary from parent InterruptSensor Class + + long timer; + bool calibrated; + long m_inactiveTimeout; + bool m_inactiveTimerRunning; + long m_inactiveTimer; + + public: + //constructor - called in your sketch's global variable declaration section + IS_Motion(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup = false, long numReqCounts = 0, long inactiveTimeout = 0); //(defaults to NOT using internal pullup resistors, and required counts = 0) + + //destructor + virtual ~IS_Motion(); + + //initialization function + virtual void init(); + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the motion sensor + virtual void refresh(); + + //handles what to do when interrupt is triggered + virtual void runInterrupt(); + + //handles what to do when interrupt is ended + virtual void runInterruptEnded(); + + //override update method + virtual void update(); + + }; +} + + +#endif diff --git a/lib/ST_Anything/IS_Presence.cpp b/lib/ST_Anything/IS_Presence.cpp new file mode 100644 index 0000000..587ec9b --- /dev/null +++ b/lib/ST_Anything/IS_Presence.cpp @@ -0,0 +1,72 @@ +//****************************************************************************************** +// File: IS_Presence.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_Presence is a class which implements the SmartThings "Presence Sensor" device capability. +// It inherits from the st::InterruptSensor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_Presence sensor1(F("presence1"), PIN_PRESENCE, LOW, true, 5000); +// +// st::IS_Presence() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input +// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2019-10-12 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + +#include "IS_Presence.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + +//public + //constructor + IS_Presence::IS_Presence(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup, long numReqCounts) : + InterruptSensor(name, pin, iState, internalPullup, numReqCounts) //use parent class' constructor + { + } + + //destructor + IS_Presence::~IS_Presence() + { + } + + void IS_Presence::init() + { + //get current status of motion sensor by calling parent class's init() routine - no need to duplicate it here! + InterruptSensor::init(); + } + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the presence sensor + void IS_Presence::refresh() + { + Everything::sendSmartString(getName() + (getStatus() ? F(" present") : F(" notpresent"))); + } + + void IS_Presence::runInterrupt() + { + //add the "present" event to the buffer to be queued for transfer to Hubitat/SmartThings + Everything::sendSmartString(getName() + F(" present")); + } + + void IS_Presence::runInterruptEnded() + { + //add the "notpresent" event to the buffer to be queued for transfer to Hubitat/SmartThings + Everything::sendSmartString(getName() + F(" notpresent")); + } + +} diff --git a/lib/ST_Anything/IS_Presence.h b/lib/ST_Anything/IS_Presence.h new file mode 100644 index 0000000..63ff50e --- /dev/null +++ b/lib/ST_Anything/IS_Presence.h @@ -0,0 +1,62 @@ +//****************************************************************************************** +// File: IS_Presence.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_Presence is a class which implements the SmartThings "Presence Sensor" device capability. +// It inherits from the st::InterruptSensor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_Presence sensor1(F("presence1"), PIN_PRESENCE, LOW, true, 5000); +// +// st::IS_Presence() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input +// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2019-10-12 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + +#ifndef ST_IS_PRESENCE_H +#define ST_IS_PRESENCE_H + +#include "InterruptSensor.h" + +namespace st +{ + class IS_Presence: public InterruptSensor + { + private: + //inherits everything necessary from parent InterruptSensor Class + + public: + //constructor - called in your sketch's global variable declaration section + IS_Presence(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup = false, long numReqCounts = 0); //(defaults to NOT using internal pullup resistors, and required counts = 0) + + //destructor + virtual ~IS_Presence(); + + //initialization function + virtual void init(); + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the presence sensor + virtual void refresh(); + + //handles what to do when interrupt is triggered + virtual void runInterrupt(); + + //handles what to do when interrupt is ended + virtual void runInterruptEnded(); + + }; +} + + +#endif diff --git a/lib/ST_Anything/IS_Smoke.cpp b/lib/ST_Anything/IS_Smoke.cpp new file mode 100644 index 0000000..7b36374 --- /dev/null +++ b/lib/ST_Anything/IS_Smoke.cpp @@ -0,0 +1,75 @@ +//****************************************************************************************** +// File: IS_Smoke.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_Smoke is a class which implements the SmartThings "Smoke Detector" device capability. +// It inherits from the st::InterruptSensor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: static st::IS_Smoke sensor6(F("smoke1"), PIN_SMOKE, HIGH, false, 500); +// +// st::IS_Smoke() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input +// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-03-17 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2019-11-04 Dan Ogorchock Updated Comments +// +// +//****************************************************************************************** + +#include "IS_Smoke.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + +//public + //constructor + IS_Smoke::IS_Smoke(const __FlashStringHelper *name, byte pin, bool iState, bool pullup, long numReqCounts) : + InterruptSensor(name, pin, iState, pullup, numReqCounts) //use parent class' constructor + { + } + + //destructor + IS_Smoke::~IS_Smoke() + { + } + + void IS_Smoke::init() + { + //get current status of motion sensor by calling parent class's init() routine - no need to duplicate it here! + InterruptSensor::init(); + } + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor + void IS_Smoke::refresh() + { + Everything::sendSmartString(getName() + (getStatus() ? F(" clear") : F(" detected"))); + } + + void IS_Smoke::runInterrupt() + { + //add the "closed" event to the buffer to be queued for transfer to the ST Shield + Everything::sendSmartString(getName() + F(" clear")); + } + + void IS_Smoke::runInterruptEnded() + { + //add the "open" event to the buffer to be queued for transfer to the ST Shield + Everything::sendSmartString(getName() + F(" detected")); + } + +} diff --git a/lib/ST_Anything/IS_Smoke.h b/lib/ST_Anything/IS_Smoke.h new file mode 100644 index 0000000..fb378f8 --- /dev/null +++ b/lib/ST_Anything/IS_Smoke.h @@ -0,0 +1,65 @@ +//****************************************************************************************** +// File: IS_Smoke.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_Smoke is a class which implements the SmartThings "Smoke Detector" device capability. +// It inherits from the st::InterruptSensor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: static st::IS_Smoke sensor6(F("smoke1"), PIN_SMOKE, HIGH, false, 500); +// +// st::IS_Smoke() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input +// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-03-17 Dan Ogorchock Added optional "numReqCounts" constructor argument/capability +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2019-11-04 Dan Ogorchock Updated Comments +// +// +//****************************************************************************************** + +#ifndef ST_IS_SMOKE_H +#define ST_IS_SMOKE_H + +#include "InterruptSensor.h" + +namespace st +{ + class IS_Smoke: public InterruptSensor + { + private: + //inherits everything necessary from parent InterruptSensor Class + + public: + //constructor - called in your sketch's global variable declaration section + IS_Smoke(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup = false, long numReqCounts = 0); //(defaults to NOT using internal pullup resistors, and required counts = 0) + + //destructor + virtual ~IS_Smoke(); + + //initialization function + virtual void init(); + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the sensor + virtual void refresh(); + + //handles what to do when interrupt is triggered + virtual void runInterrupt(); + + //handles what to do when interrupt is ended + virtual void runInterruptEnded(); + + }; +} + + +#endif diff --git a/lib/ST_Anything/IS_Water.cpp b/lib/ST_Anything/IS_Water.cpp new file mode 100644 index 0000000..d5609e8 --- /dev/null +++ b/lib/ST_Anything/IS_Water.cpp @@ -0,0 +1,73 @@ +//****************************************************************************************** +// File: IS_Water.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_Water is a class which implements the Hubitat "Water Sensor" device capability. +// It inherits from the st::InterruptSensor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_Water sensor6(F("water1"), PIN_WATER, HIGH, true, 500); +// +// st::IS_Water() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input +// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2020-06-30 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + + +#include "IS_Water.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + +//public + //constructor + IS_Water::IS_Water(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup, long numReqCounts) : + InterruptSensor(name, pin, iState, internalPullup, numReqCounts) //use parent class' constructor + { + } + + //destructor + IS_Water::~IS_Water() + { + } + + void IS_Water::init() + { + //get current status of motion sensor by calling parent class's init() routine - no need to duplicate it here! + InterruptSensor::init(); + } + + //called periodically by Everything class to ensure the Hub is kept consistent with the state of the water sensor + void IS_Water::refresh() + { + Everything::sendSmartString(getName() + (getStatus() ? F(" wet") : F(" dry"))); + } + + void IS_Water::runInterrupt() + { + //add the "closed" event to the buffer to be queued for transfer to the hub + Everything::sendSmartString(getName() + F(" wet")); + } + + void IS_Water::runInterruptEnded() + { + //add the "open" event to the buffer to be queued for transfer to the hub + Everything::sendSmartString(getName() + F(" dry")); + } + +} diff --git a/lib/ST_Anything/IS_Water.h b/lib/ST_Anything/IS_Water.h new file mode 100644 index 0000000..6c9c86a --- /dev/null +++ b/lib/ST_Anything/IS_Water.h @@ -0,0 +1,62 @@ +//****************************************************************************************** +// File: IS_Water.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: IS_Water is a class which implements the Hubitat "Water Sensor" device capability. +// It inherits from the st::InterruptSensor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::IS_Water sensor6(F("water1"), PIN_WATER, HIGH, true, 500); +// +// st::IS_Water() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital input +// - bool iState - REQUIRED - LOW or HIGH - determines which value indicates the interrupt is true +// - bool internalPullup - OPTIONAL - true == INTERNAL_PULLUP +// - long numReqCounts - OPTIONAL - number of counts before changing state of input (prevent false alarms) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2020-06-30 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + +#ifndef ST_IS_WATER_H +#define ST_IS_WATER_H + +#include "InterruptSensor.h" + +namespace st +{ + class IS_Water: public InterruptSensor + { + private: + //inherits everything necessary from parent InterruptSensor Class + + public: + //constructor - called in your sketch's global variable declaration section + IS_Water(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup = false, long numReqCounts = 0); //(defaults to NOT using internal pullup resistors, and required counts = 0) + + //destructor + virtual ~IS_Water(); + + //initialization function + virtual void init(); + + //called periodically by Everything class to ensure the Hub is kept consistent with the state of the water sensor + virtual void refresh(); + + //handles what to do when interrupt is triggered + virtual void runInterrupt(); + + //handles what to do when interrupt is ended + virtual void runInterruptEnded(); + + }; +} + + +#endif diff --git a/lib/ST_Anything/InterruptSensor.cpp b/lib/ST_Anything/InterruptSensor.cpp new file mode 100644 index 0000000..1007266 --- /dev/null +++ b/lib/ST_Anything/InterruptSensor.cpp @@ -0,0 +1,151 @@ +//****************************************************************************************** +// File: InterruptSensor.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: st::InterruptSensor is a generic class which inherits from st::Sensor. This is the +// parent class for the st::IS_Motion, IS_Contact, and IS_DoorControl classes. +// In general, this file should not need to be modified. +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-03-17 Dan Added optional "numReqCounts" constructor argument/capability +// 2019-09-22 Dan Ogorchock ESP8266 support for using A0 pin as a digital input +// +// +//****************************************************************************************** + +#include "InterruptSensor.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + + //Checks to see if the pin has changed state. If so calls appropriate function. + void InterruptSensor::checkIfTriggered() + { + bool inputState; +#if defined(ARDUINO_ARCH_ESP8266) + if (m_nInterruptPin == A0) + { + if (m_nLoopCounter == 1000) { //reading an analog input every pass through loop() is too slow + inputState = analogRead(A0) > 512 ? HIGH : LOW; + m_nLoopCounter = 0; + } + else { + m_nLoopCounter++; + return; + } + } + else { + inputState = digitalRead(m_nInterruptPin); + } +#else + inputState = digitalRead(m_nInterruptPin); +#endif + if (inputState == m_bInterruptState && !m_bStatus) //new interrupt + { + m_nCurrentDownCount = m_nRequiredCounts; + m_nCurrentUpCount++; + if (m_nCurrentUpCount >= m_nRequiredCounts) + { + m_bStatus = true; + m_bInitRequired = false; + runInterrupt(); + } + } + else if ((inputState != m_bInterruptState && m_bStatus) || m_bInitRequired) //interrupt has ended OR Init called us + { + m_nCurrentUpCount = 0; + m_nCurrentDownCount--; + if (m_nCurrentDownCount <= 0) + { + m_bStatus = false; + m_bInitRequired = false; + runInterruptEnded(); + } + } + } + +//public + //constructor + InterruptSensor::InterruptSensor(const __FlashStringHelper *name, byte pin, bool iState, bool pullup, long numReqCounts) : + Sensor(name), + m_bInterruptState(iState), + m_bStatus(false), + m_bPullup(pullup), + m_bInitRequired(true), + m_nRequiredCounts(numReqCounts), + m_nCurrentUpCount(0), + m_nCurrentDownCount(numReqCounts), + m_nLoopCounter(0) + { + setInterruptPin(pin); + } + + //destructor + InterruptSensor::~InterruptSensor() + { + + } + + //initialization function + void InterruptSensor::init() + { + checkIfTriggered(); + } + + //update function + void InterruptSensor::update() + { + checkIfTriggered(); + } + + //handles start of an interrupt - all derived classes should implement this virtual function + void InterruptSensor::runInterrupt() + { + if(debug) + { + Everything::sendSmartString(getName()+F(" triggered ") + (m_bInterruptState?F("HIGH"):F("LOW)"))); + } + } + + //handles the end of an interrupt - all derived classes should implement this virtual function + void InterruptSensor::runInterruptEnded() + { + if(debug) + { + Everything::sendSmartString(getName()+F(" ended ") + (m_bInterruptState?F("LOW)"):F("HIGH)"))); + } + } + + //sets the pin to be monitored, and set the Arduino pinMode based on constructor data + void InterruptSensor::setInterruptPin(byte pin) + { + m_nInterruptPin=pin; + +#if defined(ARDUINO_ARCH_ESP8266) + if (pin == A0) + { + pinMode(m_nInterruptPin, INPUT); + return; + } +#endif + if(!m_bPullup) + { + pinMode(m_nInterruptPin, INPUT); + } + else + { + pinMode(m_nInterruptPin, INPUT_PULLUP); + } + } + + //debug flag to determine if debug print statements are executed (set value in your sketch) + bool InterruptSensor::debug=false; +} \ No newline at end of file diff --git a/lib/ST_Anything/InterruptSensor.h b/lib/ST_Anything/InterruptSensor.h new file mode 100644 index 0000000..f766829 --- /dev/null +++ b/lib/ST_Anything/InterruptSensor.h @@ -0,0 +1,78 @@ +//****************************************************************************************** +// File: InterruptSensor.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: st::InterruptSensor is a generic class which inherits from st::Sensor. This is the +// parent class for the st::IS_Motion, IS_Contact, and IS_DoorControl classes. +// In general, this file should not need to be modified. +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-03-17 Dan Added optional "numReqCounts" constructor argument/capability +// 2019-09-22 Dan Ogorchock ESP8266 support for using A0 pin as a digital input +// +// +//****************************************************************************************** + +#ifndef ST_INTERRUPTSENSOR_H +#define ST_INTERRUPTSENSOR_H + +#include "Sensor.h" + +namespace st +{ + class InterruptSensor: public Sensor + { + private: + byte m_nInterruptPin; //pin that will be monitored for change of state + bool m_bInterruptState; //LOW or HIGH - determines which value indicates the interrupt is true (i.e. LOW=Falling Edge, HIGH=Rising Edge) + bool m_bStatus; //true == interrupted + bool m_bPullup; //true == Internal Pullup resistor required, set in constructor call in your sketch + bool m_bInitRequired; // + long m_nRequiredCounts; //Number of required counts (checks of the pin) before believing the pin is high/low + long m_nCurrentUpCount; + long m_nCurrentDownCount; + long m_nLoopCounter; + + void checkIfTriggered(); + + public: + //constructor + InterruptSensor(const __FlashStringHelper *name, byte pin, bool iState, bool internalPullup=false, long numReqCounts=0); //(defaults to NOT using internal pullup resistors, and required counts = 0) + + //destructor + virtual ~InterruptSensor(); + + //initialization function + virtual void init(); + + //update function + virtual void update(); + + //handles what to do when interrupt is triggered - all derived classes should implement this virtual function + virtual void runInterrupt(); + + //handles what to do when interrupt is ended - all derived classes should implement this virtual function + virtual void runInterruptEnded(); + + //gets + inline byte getInterruptPin() const {return m_nInterruptPin;} + inline bool getInterruptState() const {return m_bInterruptState;} + inline bool getStatus() const {return m_bStatus;} //whether or not the device is currently interrupted + + + //sets + void setInterruptPin(byte pin); + void setInterruptState(bool b) {m_bInterruptState=b;} + + //debug flag to determine if debug print statements are executed (set value in your sketch) + static bool debug; + + }; +} + + +#endif \ No newline at end of file diff --git a/lib/ST_Anything/PS_10kThermistor.cpp b/lib/ST_Anything/PS_10kThermistor.cpp new file mode 100644 index 0000000..ef32a48 --- /dev/null +++ b/lib/ST_Anything/PS_10kThermistor.cpp @@ -0,0 +1,136 @@ +//****************************************************************************************** +// File: PS_10kThermistor.cpp +// Authors: D. Johnson (_M2) based on the work of Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_10kThermistor is a class which implements the Hubitat "Temperature Measurement" device capability. +// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the +// value of a simple thermal resistor using another 10k resistor as a voltage divider. +// +// The last four arguments of the constructor are used as arguments to configure the resistance of the parts. +// The first number is the resistance of the thermistor. Second is R1. Third is the thermistor coefficient. Last is your preference of units. +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_10kThermistor sensor1(F("temperature1"), 120, 0, PIN_THERMISTOR, 10000, 10000, 3300, "F"); +// +// st::PS_10kThermistor() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - int tl - OPTIONAL - resistance of the thermocouple at the nominal temperature (usually 25C, 77F) +// - int r1 - OPTIONAL - actual measured resistance of the voltage divider resistor +// - int BCOEFF - OPTIONAL - The beta coefficient of the thermistor (usually 3000-4000). Tweak this number to calibrate. +// - int tempNOM - OPTIONAL - The nominal temperature of the thermistor @10k (usually 25C, 77F). +// - int unit - OPTIONAL - Use the letter F for Farhenheit, C for Celsius +// +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2019-12-23 D. Johnson Created 10k_Thermistor using PS_Illuminance as example +// +//****************************************************************************************** + +#include "PS_10kThermistor.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + PS_10kThermistor::PS_10kThermistor(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int t1, int r1, int BCOEFF, int tempNom, char unit): + PollingSensor(name, interval, offset), + m_nSensorValue(0), + thermResistance(t1), + r1Resistance(r1), + BetaCoeff(BCOEFF), + UNIT(unit), + TEMPNOMINAL(tempNom) + + { + setPin(analogInputPin); + } + + //destructor + PS_10kThermistor::~PS_10kThermistor() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_10kThermistor::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_10kThermistor::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_10kThermistor::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_10kThermistor::getData() + { + int NUMSAMPLES = 10; + float samples[NUMSAMPLES]; + for (int i=0; i< NUMSAMPLES; i++) + { + samples[i] = analogRead(m_nAnalogInputPin); + } + + // average all the samples out + float average = 0; + for (int i=0; i< NUMSAMPLES; i++) + { + average += samples[i]; + } + average /= NUMSAMPLES; + // convert the value to resistance + average = 1023 / average - 1; + average = r1Resistance / average; + + float reading; + float Temp1F; + float Temp1C; + reading = average / thermResistance; // (R/Ro) + reading = log(reading); // ln(R/Ro) + reading /= BetaCoeff; // 1/B * ln(R/Ro) + reading += 1.0 / (TEMPNOMINAL + 273.15); // + (1/To) + reading = 1.0 / reading; // Invert + Temp1C = reading -= 273.15; // convert to C + Temp1F = (Temp1C * 1.8) + 32; // convert to F + + if(UNIT == 'F'){ + m_nSensorValue = Temp1F; + } + else { + m_nSensorValue = Temp1C; + } + + Everything::sendSmartString(getName() + " " + String(m_nSensorValue)); + } + void PS_10kThermistor::setPin(byte pin) + { + m_nAnalogInputPin = pin; + } +} diff --git a/lib/ST_Anything/PS_10kThermistor.h b/lib/ST_Anything/PS_10kThermistor.h new file mode 100644 index 0000000..d187285 --- /dev/null +++ b/lib/ST_Anything/PS_10kThermistor.h @@ -0,0 +1,76 @@ +//****************************************************************************************** +// File: PS_10kThermistor.cpp +// Authors: D. Johnson (_M2) based on the work of Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_10kThermistor is a class which implements the Hubitat "Temperature Measurement" device capability. +// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the +// value of a simple thermal resistor using another 10k resistor as a voltage divider. +// +// The last four arguments of the constructor are used as arguments to configure the resistance of the parts. +// The first number is the resistance of the thermistor. Second is R1. Third is the thermistor coefficient. Last is your preference of units. +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_10kThermistor sensor1(F("temperature1"), 120, 0, PIN_THERMISTOR, 10000, 10000, 3300, "F"); +// +// st::PS_10kThermistor() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - int tl - OPTIONAL - resistance of the thermocouple at the nominal temperature (usually 25C, 77F) +// - int r1 - OPTIONAL - actual measured resistance of the voltage divider resistor +// - int BCOEFF - OPTIONAL - The beta coefficient of the thermistor (usually 3000-4000). Tweak this number to calibrate. +// - int tempNOM - OPTIONAL - The nominal temperature of the thermistor @10k (usually 25C, 77F). +// - int unit - OPTIONAL - Use the letter F for Farhenheit, C for Celsius +// +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2019-12-23 D. Johnson Created 10k_Thermistor using PS_Illuminance as example +// +//****************************************************************************************** + +#ifndef ST_PS_10KTHERMISTOR_H +#define ST_PS_10KTHERMISTOR_H + +#include "PollingSensor.h" + +namespace st +{ + class PS_10kThermistor: public PollingSensor + { + private: + byte m_nAnalogInputPin; + float m_nSensorValue; + int thermResistance; + int r1Resistance; + int BetaCoeff; + int TEMPNOMINAL; + char UNIT; + public: + //constructor - called in your sketch's global variable declaration section + PS_10kThermistor(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int t1=10000, int r1=10000, int BCOEFF=3300, int tempNom=25, char unit='F'); + + //destructor + virtual ~PS_10kThermistor(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline byte getPin() const {return m_nAnalogInputPin;} + inline byte getSensorValue() const {return m_nSensorValue;} + + //sets + void setPin(byte pin); + }; +} +#endif diff --git a/lib/ST_Anything/PS_Generic.cpp b/lib/ST_Anything/PS_Generic.cpp new file mode 100644 index 0000000..9d73f79 --- /dev/null +++ b/lib/ST_Anything/PS_Generic.cpp @@ -0,0 +1,118 @@ +//****************************************************************************************** +// File: PS_Generic.h +// Authors: Allan (vseven) (Based on original programming by Dan G Ogorchock & Daniel J Ogorchock (Father and Son) ) +// +// Summary: PS_Generic is a class which implements only the SmartThings "Sensor" device capability. +// It inherits from the st::PollingSensor class. The current version is made to be used as a framework +// for more complicated programming +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_Generic sensor1(F("generic1"), 120, 0); +// +// st::PS_Generic() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2017-10-20 Allan (vseven) Modified original PS_Illuminance library for use with a generic sensor +// 2017-12-28 Dan Ogorchock Fixed bug with improper init() definition +// +//****************************************************************************************** +#include "PS_Generic.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + //this can be modified to accepting more varialbes into it by modifying the + //next line. For example if you wanted to assign a pin or a variable you could add + //a ", myVariable" after the offset below and then use that within your program. + //you would need to also update the associated line in the header file. + PS_Generic::PS_Generic(const __FlashStringHelper *name, unsigned int interval, int offset): + PollingSensor(name, interval, offset),m_nSensorValue(0) + { + + } + + //destructor + PS_Generic::~PS_Generic() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_Generic::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_Generic::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_Generic::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + void PS_Generic::init() { + // This is where you would add any initialization for your custom code. For example if you + // are using a Adafruit sensor this is where you would setup the sensor. + Serial.println("Initiating the generic class."); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_Generic::getData() + { + Serial.println("getData routine called"); + + // Here is where you would do whatever you need to do to get your data. Some basic + // sample data is provided below just to see values come back in SmartThings. We firt + // define a integer called someValue then assign it a value of 15. + uint16_t someValue; + someValue = 15; + + + // Here is where you would assign the data to the sensor value. m_nSensorValue is a + // ST_Anything standard for the value of the sensor, in this case our generic sensor. + // In this example I'm converting everything to a String to make it easier to use if + // you are trying to send up multiple values. For example you can add the values together + // as a tring with a colon seperating them then in the DTH split the values back out. + String m_nSensorValue = String(someValue, DEC); + + + // To make it easier to debug print out our name and sensor value before sending it + Serial.println(getName()); + Serial.println(m_nSensorValue); + + + // Send the value to our parent which will then update the device handler + Everything::sendSmartString(getName() + " " + String(m_nSensorValue)); + } + +} diff --git a/lib/ST_Anything/PS_Generic.h b/lib/ST_Anything/PS_Generic.h new file mode 100644 index 0000000..9c7be82 --- /dev/null +++ b/lib/ST_Anything/PS_Generic.h @@ -0,0 +1,71 @@ +//****************************************************************************************** +// File: PS_Generic.h +// Authors: Allan (vseven) (Based on original programming by Dan G Ogorchock & Daniel J Ogorchock (Father and Son) ) +// +// Summary: PS_Generic is a class which implements only the SmartThings "Sensor" device capability. +// It inherits from the st::PollingSensor class. The current version is made to be used as a framework +// for more complicated programming +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_Generic sensor1(F("generic1"), 120, 0); +// +// st::PS_Generic() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2017-10-20 Allan (vseven) Modified original PS_Illuminance library for use with a generic sensor +// 2017-12-28 Dan Ogorchock Fixed bug with improper init() definition +// +// +//****************************************************************************************** + +#include "PollingSensor.h" + +namespace st +{ + class PS_Generic: public PollingSensor + { + private: + char m_nSensorValue; //converted to a string so all data can be passed in one call + + public: + //constructor - called in your sketch's global variable declaration section + //this can be modified to accepting more varialbes into it by modifying the + //line. For example if you wanted to assign a pin or a variable you could add + //a ", int myVariable" after the offset below and then use that within your program. + //you would need to also update the associated line in the .cpp file. + PS_Generic(const __FlashStringHelper *name, unsigned int interval, int offset); + + //destructor + virtual ~PS_Generic(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline byte getSensorValue() const {return m_nSensorValue;} + + //sets + + }; +} + diff --git a/lib/ST_Anything/PS_Illuminance.cpp b/lib/ST_Anything/PS_Illuminance.cpp new file mode 100644 index 0000000..fca8dc6 --- /dev/null +++ b/lib/ST_Anything/PS_Illuminance.cpp @@ -0,0 +1,105 @@ +//****************************************************************************************** +// File: PS_Illuminance.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_Illuminance is a class which implements the SmartThings "Illuminance Measurement" device capability. +// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the +// value of a simple photo resistor. +// +// The last four arguments of the constructor are used as arguments to an Arduino map() function which +// is used to scale the analog input readings (0 to 1024) to Lux before sending to SmartThings. The +// defaults for this sensor are based on the device used during testing. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_Illuminance sensor1(F("illuminance1"), 120, 0, PIN_ILLUMINANCE, 0, 1023, 0, 1000); +// +// st::PS_Illuminance() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - int s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output +// - int s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output +// - int m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output +// - int m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// +// +//****************************************************************************************** + +#include "PS_Illuminance.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + PS_Illuminance::PS_Illuminance(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int s_l, int s_h, int m_l, int m_h): + PollingSensor(name, interval, offset), + m_nSensorValue(0), + SENSOR_LOW(s_l), + SENSOR_HIGH(s_h), + MAPPED_LOW(m_l), + MAPPED_HIGH(m_h) + { + setPin(analogInputPin); + } + + //destructor + PS_Illuminance::~PS_Illuminance() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_Illuminance::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_Illuminance::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_Illuminance::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_Illuminance::getData() + { + int m_nSensorValue=map(analogRead(m_nAnalogInputPin), SENSOR_LOW, SENSOR_HIGH, MAPPED_LOW, MAPPED_HIGH); + + Everything::sendSmartString(getName() + " " + String(m_nSensorValue)); + } + + void PS_Illuminance::setPin(byte pin) + { + m_nAnalogInputPin=pin; + } +} diff --git a/lib/ST_Anything/PS_Illuminance.h b/lib/ST_Anything/PS_Illuminance.h new file mode 100644 index 0000000..4c66f72 --- /dev/null +++ b/lib/ST_Anything/PS_Illuminance.h @@ -0,0 +1,77 @@ +//****************************************************************************************** +// File: PS_Illuminance.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_Illuminance is a class which implements the SmartThings "Illuminance Measurement" device capability. +// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the +// value of a simple photo resistor. +// +// The last four arguments of the constructor are used as arguments to an Arduino map() function which +// is used to scale the analog input readings (0 to 1024) to Lux before sending to SmartThings. The +// defaults for this sensor are based on the device used during testing. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_Illuminance sensor1(F("illuminance1"), 120, 0, PIN_ILLUMINANCE, 0, 1023, 0, 1000); +// +// st::PS_Illuminance() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - int s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output +// - int s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output +// - int m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output +// - int m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// +// +//****************************************************************************************** + +#ifndef ST_PS_ILLUMINANCE_H +#define ST_PS_ILLUMINANCE_H + +#include "PollingSensor.h" + +namespace st +{ + class PS_Illuminance: public PollingSensor + { + private: + byte m_nAnalogInputPin; + int m_nSensorValue; + const int SENSOR_LOW, SENSOR_HIGH, MAPPED_LOW, MAPPED_HIGH; + + public: + //constructor - called in your sketch's global variable declaration section + PS_Illuminance(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int s_l=0, int s_h=1023, int m_l=1000, int m_h=0); + + //destructor + virtual ~PS_Illuminance(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline byte getPin() const {return m_nAnalogInputPin;} + inline byte getSensorValue() const {return m_nSensorValue;} + + //sets + void setPin(byte pin); + }; +} +#endif diff --git a/lib/ST_Anything/PS_MQ2_Smoke.cpp b/lib/ST_Anything/PS_MQ2_Smoke.cpp new file mode 100644 index 0000000..a5c4600 --- /dev/null +++ b/lib/ST_Anything/PS_MQ2_Smoke.cpp @@ -0,0 +1,103 @@ +//****************************************************************************************** +// File: PS_MQ2_Smoke.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_MQ2_Smoke is a class which implements the SmartThings "Smoke Detector" device capability. +// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the +// value from the MQ2 sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_MQ2_Smoke sensor1("smoke1", 10, 0, PIN_MQ2_SMOKE, 300); +// +// st::PS_MQ2_Smoke() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name e.g. "smoke1", "smoke2", etc... +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - int sensorLimit - REQUIRED - if sensor reads value above this limit, report Smoke Detected (typical range is 0 to 1023 on Arduino Analog Input) +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the Arduino. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2017-07-04 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + + +#include "PS_MQ2_Smoke.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + PS_MQ2_Smoke::PS_MQ2_Smoke(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int sensorLimit): + PollingSensor(name, interval, offset), + m_nSensorValue(0), + m_nSensorLimit(sensorLimit) + { + setPin(analogInputPin); + } + + //destructor + PS_MQ2_Smoke::~PS_MQ2_Smoke() + { + + } + + //SmartThings data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_MQ2_Smoke::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_MQ2_Smoke::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_MQ2_Smoke::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_MQ2_Smoke::getData() + { + int m_nSensorValue=analogRead(m_nAnalogInputPin); + + Everything::sendSmartString(getName() + (m_nSensorValue < m_nSensorLimit ? F(" clear") : F(" detected"))); + + if (st::PollingSensor::debug) + { + Serial.print(F("PS_MQ2_Smoke::Analog Pin value is ")); + Serial.print(m_nSensorValue); + Serial.print(F(" vs limit of ")); + Serial.println(m_nSensorLimit); + } + } + + void PS_MQ2_Smoke::setPin(byte pin) + { + m_nAnalogInputPin=pin; + } +} \ No newline at end of file diff --git a/lib/ST_Anything/PS_MQ2_Smoke.h b/lib/ST_Anything/PS_MQ2_Smoke.h new file mode 100644 index 0000000..870b826 --- /dev/null +++ b/lib/ST_Anything/PS_MQ2_Smoke.h @@ -0,0 +1,69 @@ +//****************************************************************************************** +// File: PS_MQ2_Smoke.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_MQ2_Smoke is a class which implements the SmartThings "Smoke Detector" device capability. +// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the +// value from the MQ2 sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_MQ2_Smoke sensor1("smoke1", 10, 0, PIN_MQ2_SMOKE, 300); +// +// st::PS_MQ2_Smoke() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name e.g. "smoke1", "smoke2", etc... +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - int sensorLimit - REQUIRED - if sensor reads value above this limit, report Smoke Detected (typical range is 0 to 1023 on Arduino Analog Input) +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the Arduino. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2017-07-04 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + +#ifndef ST_PS_MQ2_SMOKE_H +#define ST_PS_MQ2_SMOKE_H + +#include "PollingSensor.h" + +namespace st +{ + class PS_MQ2_Smoke: public PollingSensor + { + private: + byte m_nAnalogInputPin; + int m_nSensorValue; + int m_nSensorLimit; + + public: + //constructor - called in your sketch's global variable declaration section + PS_MQ2_Smoke(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int sensorLimit); + + //destructor + virtual ~PS_MQ2_Smoke(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline byte getPin() const {return m_nAnalogInputPin;} + inline byte getSensorValue() const {return m_nSensorValue;} + + //sets + void setPin(byte pin); + }; +} +#endif \ No newline at end of file diff --git a/lib/ST_Anything/PS_Power.cpp b/lib/ST_Anything/PS_Power.cpp new file mode 100644 index 0000000..dcd3489 --- /dev/null +++ b/lib/ST_Anything/PS_Power.cpp @@ -0,0 +1,138 @@ +//****************************************************************************************** +// File: PS_Power.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_Power is a class which implements the SmartThings "Power Meter" device capability. +// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the +// voltage on an analog input pin via the EmonLib. This produce the Irms current of the Current Transformer. +// The Irms current is then multiplied by the voltage constant passed in to produce Power in Watts. +// +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_Power sensor1(F("power1"), 120, 0, PIN_POWER, 30.0, 1480, 120.0); +// +// st::PS_Power() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input +// - double ICAL - REQUIRED - EmonLib Calibration Constant +// - unsigned int numSamples - OPTIONAL - defaults to 1480, number of analog readings to use for calculating the Irms Current +// - float voltage - OPTIONAL - defaults to 120, AC voltage of the mains line being monitored +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2019-02-17 Dan Ogorchock Original Creation +// 2019-09-19 Dan Ogorchock Added filtering optional argument to help reduce noisy signals +// +// +//****************************************************************************************** +#include "PS_Power.h" + +#include "Constants.h" +#include "Everything.h" +#include + +namespace st +{ +//private + +//public + //constructor - called in your sketch's global variable declaration section + PS_Power::PS_Power(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double ICAL, unsigned int NumSamples, float voltage, byte filterConstant) : + PollingSensor(name, interval, offset), + emon1(), + m_nAnalogInputPin(analogInputPin), + m_fICAL(ICAL), + m_fIrms(0.0), + m_fApparentPower(0.0), + m_nNumSamples(NumSamples), + m_fVoltage(voltage) + { + setPin(analogInputPin); + + //check for upper and lower limit and adjust accordingly + if ((filterConstant <= 0) || (filterConstant >= 100)) + { + m_fFilterConstant = 1.0; + } + else if (filterConstant <= 5) + { + m_fFilterConstant = 0.05; + } + else + { + m_fFilterConstant = float(filterConstant) / 100; + } + + emon1.current(m_nAnalogInputPin, m_fICAL); // Current: input pin, calibration. + } + + + //destructor + PS_Power::~PS_Power() + { + + } + + void PS_Power::init() + { + //Make sure the EmonLib has some data accumulated before anything is transmitted to ST/Hubitat + m_fIrms = emon1.calcIrms(m_nNumSamples); + m_fIrms = emon1.calcIrms(m_nNumSamples); + m_fIrms = emon1.calcIrms(m_nNumSamples); + m_fIrms = emon1.calcIrms(m_nNumSamples); + m_fIrms = emon1.calcIrms(m_nNumSamples); + + m_fApparentPower = m_fIrms * m_fVoltage; //Calcuate Apparent Power + + //Send initial data to ST/Hubitat + getData(); + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_Power::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_Power::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_Power::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //function to get data from sensor and queue results for transfer to ST/Hubitat + void PS_Power::getData() + { + double tempValue = 0; + + m_fIrms = emon1.calcIrms(m_nNumSamples); // Calculate Irms only + + tempValue = m_fIrms * m_fVoltage; //Calcuate Apparent Power + + m_fApparentPower = (m_fFilterConstant * tempValue) + (1 - m_fFilterConstant) * m_fApparentPower; + + Everything::sendSmartString(getName() + " " + String(m_fApparentPower)); + } + + void PS_Power::setPin(byte pin) + { + m_nAnalogInputPin=pin; + } +} diff --git a/lib/ST_Anything/PS_Power.h b/lib/ST_Anything/PS_Power.h new file mode 100644 index 0000000..6dd355c --- /dev/null +++ b/lib/ST_Anything/PS_Power.h @@ -0,0 +1,79 @@ +//****************************************************************************************** +// File: PS_Power.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_Power is a class which implements the SmartThings "Power Meter" device capability. +// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the +// voltage on an analog input pin via the EmonLib. This produce the Irms current of the Current Transformer. +// The Irms current is then multiplied by the voltage constant passed in to produce Power in Watts. +// +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_Power sensor1(F("power1"), 120, 0, PIN_POWER, 30.0, 1480, 120.0); +// +// st::PS_Power() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input +// - double ICAL - REQUIRED - EmonLib Calibration Constant +// - unsigned int numSamples - OPTIONAL - defaults to 1480, number of analog readings to use for calculating the Irms Current +// - float voltage - OPTIONAL - defaults to 120, AC voltage of the mains line being monitored +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2019-02-17 Dan Ogorchock Original Creation +// 2019-09-19 Dan Ogorchock Added filtering optional argument to help reduce noisy signals +// +// +//****************************************************************************************** +#ifndef ST_PS_Power_H +#define ST_PS_Power_H + +#include +#include "PollingSensor.h" + +namespace st +{ + class PS_Power: public PollingSensor + { + private: + EnergyMonitor emon1; + byte m_nAnalogInputPin; + double m_fICAL; + unsigned int m_nNumSamples; + float m_fVoltage; + double m_fIrms; + double m_fApparentPower; + float m_fFilterConstant; //Filter constant % as floating point from 0.00 to 1.00 + + public: + //constructor - called in your sketch's global variable declaration section + PS_Power(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double ICAL, unsigned int NumSamples=1480, float voltage=120.0, byte filterConstant = 100); + + //destructor + virtual ~PS_Power(); + + //initialization function + virtual void init(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline byte getPin() const {return m_nAnalogInputPin;} + inline float getSensorValue() const {return m_fApparentPower;} + + //sets + void setPin(byte pin); + }; +} +#endif diff --git a/lib/ST_Anything/PS_PulseCounter.cpp b/lib/ST_Anything/PS_PulseCounter.cpp new file mode 100644 index 0000000..bd338b2 --- /dev/null +++ b/lib/ST_Anything/PS_PulseCounter.cpp @@ -0,0 +1,151 @@ +//****************************************************************************************** +// File: PS_PulseCounter.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_PulseCounter is a class which implements the SmartThings "Power Meter"-style device capability. +// It inherits from the st::PollingSensor class. The current version uses a digital input to measure the +// the number of counts between polling intervals. At the polling interval, the pulse count is converted +// to engineering units via a linear conversion (engUnits = slope x counts + offset). +// +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_PulseCounter sensor3(F("power1"), 60, 5, PIN_PULSE, FALLING, INPUT_PULLUP, 1.0, 0); +// +// st::PS_PulseCounter() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must be in form of "power1", "power2", etc... +// - int interval - REQUIRED - the polling interval in seconds +// - int offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the GPIO Pin to be used as an digital input (Hardware Interrupt) +// - byte inttype - REQUIRED - which type of Arduino interrupt to trigger the ISR (RISING, FALLING, CHANGE) +// - byte inputmode - REQUIRED - Mode of the digital input Pin (INPUT, INPUT_PULLUP) +// - float cnvslope - REQUIRED - Conversion to Engineering Units Slope +// - float cnvoffset - REQUIRED - Conversion to Engineering Units Offset +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-03-31 Dan Ogorchock Original Creation +// 2018-03-03 Dan Ogorchock Improved code to make generic for all boards, not just Arduino MEGA +// 2020-01-17 Dan Ogorchock Improved support for ESP8266 using Arduino IDE Board Manager 2.5.1 and newer +// 2020-11-15 Dan Ogorchock Prevent Refresh from sending data for this particular device. +// 2021-04-12 Dan Ogorchock Corrected data type for interrupt type to correct compiler error for Nano 33 IoT +// 2021-06-14 Dan Ogorchock Fixed for SAMD Architectures...again +// 2023-01-25 Dan Ogorchock Fixed for MKR 1010 (use PinStatus instead of int for inttype) +// 2023-01-26 Dan Ogorchock Fixed for SAMD Architecture boards versus all other boards +// +// +//****************************************************************************************** + +#include "PS_PulseCounter.h" + +#include "Constants.h" +#include "Everything.h" +//#include "PinChangeInt.h" + +namespace st +{ + //private + + //This "Counts" variables must be declared here so they can be used in the Interrupt Service Routines (ISR) + volatile unsigned long m_nCounts; //current count of interrupts (pulses) + + //These are the four Interrupt Service Routines (ISR) which must be unique for each interrupt +#if defined(ARDUINO_ARCH_ESP8266) + void ICACHE_RAM_ATTR isrPulse() { +#else +void isrPulse() { +#endif + m_nCounts++; + } + +//public + + //constructor - called in your sketch's global variable declaration section +#if defined(ARDUINO_ARCH_SAMD) + PS_PulseCounter::PS_PulseCounter(const __FlashStringHelper *name, unsigned int interval, int offset, byte inputpin, PinStatus inttype, byte inputmode, float cnvslope, float cnvoffset) : +#else + PS_PulseCounter::PS_PulseCounter(const __FlashStringHelper* name, unsigned int interval, int offset, byte inputpin, int inttype, byte inputmode, float cnvslope, float cnvoffset) : +#endif + PollingSensor(name, interval, offset), + m_nInputMode(inputmode), + m_nSensorValue(0), + m_fCnvSlope(cnvslope), + m_fCnvOffset(cnvoffset) + { + setPin(inputpin); + m_nCounts = 0; + m_pCounter = &m_nCounts; + attachInterrupt(digitalPinToInterrupt(m_nInputPin), isrPulse, inttype); + } + + //destructor + PS_PulseCounter::~PS_PulseCounter() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_PulseCounter::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_PulseCounter::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_PulseCounter::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + void PS_PulseCounter::refresh() + { + //This specific device should not report data except during its scheduled polling interval to preserve data integrity of the pulse counted value + //getData(); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_PulseCounter::getData() + { + if (m_pCounter) + { + noInterrupts(); + unsigned long tmpCounts = *m_pCounter; + *m_pCounter = 0; + interrupts(); + + m_nSensorValue = long(m_fCnvSlope * tmpCounts + m_fCnvOffset); + + } + else //invalid Pin/Interrupt was requested, therefore we are in an error condition + { + m_nSensorValue = 0; + if (st::PollingSensor::debug) { + Serial.println(F("PS_PulseCounter::Something went wrong. Need to debug.")); + } + } + + Everything::sendSmartString(getName() + " " + m_nSensorValue); + } + + void PS_PulseCounter::setPin(byte pin) + { + m_nInputPin = pin; + pinMode(m_nInputPin, m_nInputMode); + } +} \ No newline at end of file diff --git a/lib/ST_Anything/PS_PulseCounter.h b/lib/ST_Anything/PS_PulseCounter.h new file mode 100644 index 0000000..4249261 --- /dev/null +++ b/lib/ST_Anything/PS_PulseCounter.h @@ -0,0 +1,99 @@ +//****************************************************************************************** +// File: PS_PulseCounter.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_PulseCounter is a class which implements the SmartThings "Power Meter"-style device capability. +// It inherits from the st::PollingSensor class. The current version uses a digital input to measure the +// the number of counts between polling intervals. At the polling interval, the pulse count is converted +// to engineering units via a linear conversion (engUnits = slope x counts + offset). +// +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_PulseCounter sensor3(F("power1"), 60, 5, PIN_PULSE, FALLING, INPUT_PULLUP, 1.0, 0); +// +// st::PS_PulseCounter() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must be in form of "power1", "power2", etc... +// - int interval - REQUIRED - the polling interval in seconds +// - int offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the GPIO Pin to be used as an digital input (Hardware Interrupt) +// - byte inttype - REQUIRED - which type of Arduino interrupt to trigger the ISR (RISING, FALLING, CHANGE) +// - byte inputmode - REQUIRED - Mode of the digital input Pin (INPUT, INPUT_PULLUP) +// - float cnvslope - REQUIRED - Conversion to Engineering Units Slope +// - float cnvoffset - REQUIRED - Conversion to Engineering Units Offset +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-03-31 Dan Ogorchock Original Creation +// 2018-03-03 Dan Ogorchock Improved code to make generic for all boards, not just Arduino MEGA +// 2020-01-17 Dan Ogorchock Improved support for ESP8266 using Arduino IDE Board Manager 2.5.1 and newer +// 2020-11-15 Dan Ogorchock Prevent Refresh from sending data for this particular device. +// 2021-04-12 Dan Ogorchock Corrected data type for interrupt type to correct compiler error for Nano 33 IoT +// 2021-06-14 Dan Ogorchock Fixed for SAMD Architectures...again +// 2023-01-25 Dan Ogorchock Fixed for MKR 1010 (use PinStatus instead of int for inttype) +// 2023-01-26 Dan Ogorchock Fixed for SAMD Architecture boards versus all other boards +// +// +//****************************************************************************************** + + +#ifndef ST_PS_PULSECOUNTER_H +#define ST_PS_PULSECOUNTER_H + +#include "PollingSensor.h" + +namespace st +{ + class PS_PulseCounter : public PollingSensor + { + private: + byte m_nInputPin; //input pin connected to the pulse generator + byte m_nInputMode; //input mode (INPUT or INPUT_PULLUP) + unsigned long m_nSensorValue; //current sensor value (m_nSensorValue = Long(m_fCnvSlope * m_nCounts + m_fCnvOffset)) + float m_fCnvSlope; //Linear Conversion Slope + float m_fCnvOffset; //Linear Conversion Offset + volatile unsigned long* m_pCounter; //Point to the correct Counter variable; + + public: + +#if defined(ARDUINO_ARCH_SAMD) + //constructor - called in your sketch's global variable declaration section + PS_PulseCounter(const __FlashStringHelper *name, unsigned int interval, int offset, byte inputpin, PinStatus inttype, byte inputmode, float cnvslope, float cnvoffset); +#else + //constructor - called in your sketch's global variable declaration section + PS_PulseCounter(const __FlashStringHelper* name, unsigned int interval, int offset, byte inputpin, int inttype, byte inputmode, float cnvslope, float cnvoffset); +#endif + //destructor + virtual ~PS_PulseCounter(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of each Device subclass object + virtual void refresh(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline byte getPin() const {return m_nInputPin;} + inline long getSensorValue() const {return m_nSensorValue;} + + //sets + void setPin(byte pin); + + friend void isrPulse(); + + }; +} + + + +#endif \ No newline at end of file diff --git a/lib/ST_Anything/PS_SoundPressureLevel.cpp b/lib/ST_Anything/PS_SoundPressureLevel.cpp new file mode 100644 index 0000000..a5fdecd --- /dev/null +++ b/lib/ST_Anything/PS_SoundPressureLevel.cpp @@ -0,0 +1,137 @@ +//****************************************************************************************** +// File: PS_SoundPressureLevel.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_SoundPressureLevel is a class which implements the "Sound Pressure Level" device capability. +// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the +// voltage on an anlog input pin and then scale it to engineering units. +// +// The last four arguments of the constructor are used as arguments to an Arduino map() function which +// is used to scale the analog input readings (e.g. 0 to 1024) to Engineering Units before sending to SmartThings. +// +// Create an instance of this class in your sketch's global variable section +// For Example: static st::PS_SoundPressureLevel sensor1(F("soundPressureLevel1"), 60, 0, PIN_SPL, 0, 1024, 0.0, 165.0, 50); +// +// st::PS_SoundPressureLevel() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input +// - double s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - minimum raw AI value +// - double s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - maximum raw AI value +// - double m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Min (or Max if inverting) +// - double m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Max (or Min if inverting) +// - long m_nHighSpeedPollingInterval - OPTIONAL - number of milliseconds between high speed analog reads - defaults to 50ms +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2019-07-08 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** +#include "PS_SoundPressureLevel.h" + +#include "Constants.h" +#include "Everything.h" +#include + +namespace st +{ +//private + float PS_SoundPressureLevel::map_double(double x, double in_min, double in_max, double out_min, double out_max) + { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; + } + +//public + //constructor - called in your sketch's global variable declaration section + PS_SoundPressureLevel::PS_SoundPressureLevel(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double s_l, double s_h, double m_l, double m_h, long HighSpeedPollingInterval): + PollingSensor(name, interval, offset), + m_fSensorValue(-1.0), + SENSOR_LOW(s_l), + SENSOR_HIGH(s_h), + MAPPED_LOW(m_l), + MAPPED_HIGH(m_h), + m_nHighSpeedPollingInterval(HighSpeedPollingInterval) + { + setPin(analogInputPin); + } + + //destructor + PS_SoundPressureLevel::~PS_SoundPressureLevel() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_SoundPressureLevel::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_SoundPressureLevel::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_SoundPressureLevel::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + void PS_SoundPressureLevel::update() + { + + //read the SPL value if enough time has elapsed + if ((millis() - m_nPrevMillis) > m_nHighSpeedPollingInterval) { + m_nPrevMillis = millis(); + + //read analog input + long tempAnalogInput = analogRead(m_nAnalogInputPin); + + //scale raw AI value into Engineering Units + float tempValue = map_double(tempAnalogInput, SENSOR_LOW, SENSOR_HIGH, MAPPED_LOW, MAPPED_HIGH); + + //if new value is greater than previous value, store the new value (i.e. keep the MAX SPL) + if (tempValue > m_fSensorValue) { + m_fSensorValue = tempValue; + } + } + + //make sure to call the parent class' update function, since we've overriden update() + PollingSensor::update(); + + } + + //function to get data from sensor and queue results for transfer to Hub + void PS_SoundPressureLevel::getData() + { + //make sure we have at least one reading before transferring data + update(); + + //transfer the data to the hub + Everything::sendSmartString(getName() + " " + String(m_fSensorValue)); + + //reset the max value + m_fSensorValue = -1.0; + } + + void PS_SoundPressureLevel::setPin(byte pin) + { + m_nAnalogInputPin=pin; + } +} diff --git a/lib/ST_Anything/PS_SoundPressureLevel.h b/lib/ST_Anything/PS_SoundPressureLevel.h new file mode 100644 index 0000000..04e4651 --- /dev/null +++ b/lib/ST_Anything/PS_SoundPressureLevel.h @@ -0,0 +1,82 @@ +//****************************************************************************************** +// File: PS_SoundPressureLevel.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_SoundPressureLevel is a class which implements the "Sound Pressure Level" device capability. +// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the +// voltage on an anlog input pin and then scale it to engineering units. +// +// The last four arguments of the constructor are used as arguments to an Arduino map() function which +// is used to scale the analog input readings (e.g. 0 to 1024) to Engineering Units before sending to SmartThings. +// +// Create an instance of this class in your sketch's global variable section +// For Example: static st::PS_SoundPressureLevel sensor1(F("soundPressureLevel1"), 60, 0, PIN_SPL, 0, 1024, 0.0, 165.0, 50); +// +// st::PS_SoundPressureLevel() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input +// - double s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - minimum raw AI value +// - double s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - maximum raw AI value +// - double m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Min (or Max if inverting) +// - double m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Max (or Min if inverting) +// - long m_nHighSpeedPollingInterval - OPTIONAL - number of milliseconds between high speed analog reads - defaults to 50ms +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2019-07-08 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** +#ifndef ST_PS_SOUNDPRESSURELEVEL_H +#define ST_PS_SOUNDPRESSURELEVEL_H + +#include "PollingSensor.h" + +namespace st +{ + class PS_SoundPressureLevel: public PollingSensor + { + private: + byte m_nAnalogInputPin; + float m_fSensorValue; + double SENSOR_LOW, SENSOR_HIGH, MAPPED_LOW, MAPPED_HIGH; + long m_nPrevMillis; + long m_nHighSpeedPollingInterval; + + float map_double(double x, double in_min, double in_max, double out_min, double out_max); + + public: + //constructor - called in your sketch's global variable declaration section + PS_SoundPressureLevel(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double s_l=0, double s_h=1024, double m_l=0.0, double m_h=165.0, long HighSpeedPollingInterval = 50); + + //destructor + virtual ~PS_SoundPressureLevel(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //update function + virtual void update(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline byte getPin() const {return m_nAnalogInputPin;} + inline float getSensorValue() const {return m_fSensorValue;} + + //sets + void setPin(byte pin); + }; +} +#endif diff --git a/lib/ST_Anything/PS_Ultrasonic.cpp b/lib/ST_Anything/PS_Ultrasonic.cpp new file mode 100644 index 0000000..b83ea6f --- /dev/null +++ b/lib/ST_Anything/PS_Ultrasonic.cpp @@ -0,0 +1,107 @@ +//****************************************************************************************** +// File: PS_Ultrasonic.cpp +// Authors: +// +// Summary: PS_Ultrasonic is a class which implements a custom Level device capability. +// It inherits from the st::PollingSensor class. +// +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_Ultrasonic sensor1(F("ultrasonic1"), 60, 0, PIN_ULTRASONIC_T, PIN_ULTRASONIC_E); +// +// st::PS_Ultrasonic() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte digitalTriggerPin - REQUIRED - the Arduino Pin to be used as a digital output to trigger ultrasonic +// - byte digitalEchoPin - REQUIRED - the Arduino Pin to be used as a digital input to read the echo +// +// +// Change History: +// +// Date Who What +// ---- --- ---- +// +// +// +//****************************************************************************************** + +#include "PS_Ultrasonic.h" + +#include "Constants.h" +#include "Everything.h" + + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + PS_Ultrasonic::PS_Ultrasonic(const __FlashStringHelper *name, unsigned int interval, int offset, byte digitalTriggerPin, byte digitalEchoPin): + PollingSensor(name, interval, offset), + m_nSensorValue(0) + { + setPin(digitalTriggerPin,digitalEchoPin); + } + + //destructor + PS_Ultrasonic::~PS_Ultrasonic() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_Ultrasonic::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + Serial.print("st string ##### "); + Serial.println(str); + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_Ultrasonic::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_Ultrasonic::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_Ultrasonic::getData() + { + + //int m_nSensorValue=map(analogRead(m_nAnalogInputPin), SENSOR_LOW, SENSOR_HIGH, MAPPED_LOW, MAPPED_HIGH); + long duration; + // Clears the trigPin + digitalWrite(m_nDigitalTriggerPin, LOW); + delayMicroseconds(2); + // Sets the trigPin on HIGH state for 10 micro seconds + digitalWrite(m_nDigitalTriggerPin, HIGH); + delayMicroseconds(10); + digitalWrite(m_nDigitalTriggerPin, LOW); + // Reads the echoPin, returns the sound wave travel time in microseconds + duration = pulseIn(m_nDigitalEchoPin, HIGH); + // Calculating the distance + m_nSensorValue = duration*0.034/2; + + // queue the distance to send to smartthings + Everything::sendSmartString(getName() + " " + String(m_nSensorValue)); + } + + void PS_Ultrasonic::setPin(byte &trigPin,byte &echoPin) + { + m_nDigitalTriggerPin=trigPin; + m_nDigitalEchoPin=echoPin; + pinMode(m_nDigitalTriggerPin, OUTPUT); // Sets the trigPin as an Output + pinMode(m_nDigitalEchoPin, INPUT); // Sets the echoPin as an Input + } +} diff --git a/lib/ST_Anything/PS_Ultrasonic.h b/lib/ST_Anything/PS_Ultrasonic.h new file mode 100644 index 0000000..29d5bd8 --- /dev/null +++ b/lib/ST_Anything/PS_Ultrasonic.h @@ -0,0 +1,64 @@ +//****************************************************************************************** +// File: PS_Ultrasonic.h +// Authors: +// +// Summary: PS_Ultrasonic is a class which implements a custom Level device capability. +// It inherits from the st::PollingSensor class. +// +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_Ultrasonic sensor1(F("ultrasonic1"), 60, 0, PIN_ULTRASONIC_T, PIN_ULTRASONIC_E); +// +// st::PS_Ultrasonic() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte digitalTriggerPin - REQUIRED - the Arduino Pin to be used as a digital output to trigger ultrasonic +// - byte digitalEchoPin - REQUIRED - the Arduino Pin to be used as a digital input to read the echo +// +// +// Change History: +// +// Date Who What +// ---- --- ---- +// +// +// +//****************************************************************************************** + +#ifndef ST_PS_Ultrasonic_H +#define ST_PS_Ultrasonic_H + +#include "PollingSensor.h" + +namespace st +{ + class PS_Ultrasonic : public PollingSensor + { + private: + byte m_nDigitalTriggerPin; + byte m_nDigitalEchoPin; + float m_nSensorValue; + + public: + //constructor - called in your sketch's global variable declaration section + PS_Ultrasonic(const __FlashStringHelper *name, unsigned int interval, int offset, byte digitalTriggerPin, byte digitalEchoPin); + + //destructor + virtual ~PS_Ultrasonic(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + //inline byte getPin() const {return m_nAnalogInputPin;} + inline byte getSensorValue() const {return m_nSensorValue;} + + //sets + void setPin(byte &trigPin,byte &echoPin); + }; +} +#endif diff --git a/lib/ST_Anything/PS_Voltage.cpp b/lib/ST_Anything/PS_Voltage.cpp new file mode 100644 index 0000000..35baa9b --- /dev/null +++ b/lib/ST_Anything/PS_Voltage.cpp @@ -0,0 +1,239 @@ +//****************************************************************************************** +// File: PS_Voltage.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_Voltage is a class which implements the SmartThings "Voltage Measurement" device capability. +// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the +// voltage on an anlog input pin and then scale it to engineering units. +// +// The last four arguments of the constructor are used as arguments to an Arduino map() function which +// is used to scale the analog input readings (e.g. 0 to 1024) to Engineering Units before sending to SmartThings. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_Voltage sensor1(F("voltage1"), 120, 0, PIN_VOLTAGE, 0, 1023, 0.0, 5.0); +// +// st::PS_Voltage() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input +// - double s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - minimum raw AI value +// - double s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - maximum raw AI value +// - double m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Min (or Max if inverting) +// - double m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Max (or Min if inverting) +// - byte numSamples - OPTIONAL - defaults to 1, number of analog readings to average per scheduled reading of the analog input +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// +// Filtering/Averaging +// +// Filtering the value sent to ST is performed per the following equation +// +// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue) +// +//---------------------------------------------------------------------------------------------------------------------------------------------- +// st::PS_Voltage() has a second constructor which includes a 3rd order polynomial compensation algorithm. +// +// Create an instance of this class in your sketch's global variable section +// For Example: static st::PS_Voltage sensor5(F("voltage1"), 5, 1, PIN_VOLTAGE_1, -40, 140, 0, 4095, 20, 75, -0.000000025934, 0.0001049656215, 0.9032840665333, 204.642825355678); +// +// The following arguments all all REQUIRED in order to use the Compensation Algorithm. +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input +// - double s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - minimum raw AI value +// - double s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - maximum raw AI value +// - double m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Min (or Max if inverting) +// - double m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Max (or Min if inverting) +// - byte numSamples - REQUIRED - number of analog readings to average per scheduled reading of the analog input +// - byte filterConstant - REQUIRED - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none, 5 = maximum +// - double Coeff1 - REQUIRED - 3rd order polynomial coefficient #1 +// - double Coeff2 - REQUIRED - 3rd order polynomial coefficient #2 +// - double Coeff3 - REQUIRED - 3rd order polynomial coefficient #3 +// - double Coeff4 - REQUIRED - 3rd order polynomial coefficient #4 +// +// 3rd order Plynomial Compensation Algorithm (useful for correcting non-linear analog to digital converters) +// +// CompensatedValue = Coeff1 * rawAnalogInput^3 + Coeff2 * rawAnalogInput^2 + Coeff3 * rawAnalogInput + Coeff4 +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-04-19 Dan & Daniel Original Creation +// 2017-08-18 Dan Ogorchock Modified to return floating point values instead of integer +// 2017-08-31 Dan Ogorchock Added oversampling optional argument to help reduce noisy signals +// 2017-08-31 Dan Ogorchock Added filtering optional argument to help reduce noisy signals +// 2017-09-01 Dan Ogorchock Added 3rd order polynomial nonlinear correction compensation +// 2018-06-24 Dan Ogorchock Improved documentation / comments (above) +// +// +//****************************************************************************************** +#include "PS_Voltage.h" + +#include "Constants.h" +#include "Everything.h" +#include + +namespace st +{ +//private + float map_double(double x, double in_min, double in_max, double out_min, double out_max) + { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; + } + +//public + //constructor - called in your sketch's global variable declaration section + PS_Voltage::PS_Voltage(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double s_l, double s_h, double m_l, double m_h, int NumSamples, byte filterConstant): + PollingSensor(name, interval, offset), + m_fSensorValue(-1.0), + SENSOR_LOW(s_l), + SENSOR_HIGH(s_h), + MAPPED_LOW(m_l), + MAPPED_HIGH(m_h), + m_nNumSamples(NumSamples), + m_bUseCompensation(false) + { + setPin(analogInputPin); + + //check for upper and lower limit and adjust accordingly + if ((filterConstant <= 0) || (filterConstant >= 100)) + { + m_fFilterConstant = 1.0; + } + else if (filterConstant <= 5) + { + m_fFilterConstant = 0.05; + } + else + { + m_fFilterConstant = float(filterConstant) / 100; + } + + } + + //constructor - called in your sketch's global variable declaration section + PS_Voltage::PS_Voltage(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double s_l, double s_h, double m_l, double m_h, int NumSamples, byte filterConstant, double Coeff1, double Coeff2, double Coeff3, double Coeff4) : + PollingSensor(name, interval, offset), + m_fSensorValue(-1.0), + SENSOR_LOW(s_l), + SENSOR_HIGH(s_h), + MAPPED_LOW(m_l), + MAPPED_HIGH(m_h), + m_nNumSamples(NumSamples), + m_dCoeff1(Coeff1), + m_dCoeff2(Coeff2), + m_dCoeff3(Coeff3), + m_dCoeff4(Coeff4), + m_bUseCompensation(true) + { + setPin(analogInputPin); + + //check for upper and lower limit and adjust accordingly + if ((filterConstant <= 0) || (filterConstant >= 100)) + { + m_fFilterConstant = 1.0; + } + else if (filterConstant <= 5) + { + m_fFilterConstant = 0.05; + } + else + { + m_fFilterConstant = float(filterConstant) / 100; + } + + } + + + //destructor + PS_Voltage::~PS_Voltage() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_Voltage::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_Voltage::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_Voltage::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_Voltage::getData() + { + int i; + double tempValue = 0; + long tempAnalogInput = 0; + + //implement oversampling / averaging + for (i = 0; i < m_nNumSamples; i++) { + + tempAnalogInput = analogRead(m_nAnalogInputPin); + + if (m_bUseCompensation) { + + //Serial.print(F("PS_Voltage::tempAnalogInput = ")); + //Serial.print(tempAnalogInput); + + tempAnalogInput = (m_dCoeff1 * pow(tempAnalogInput, 3)) + (m_dCoeff2 * pow(tempAnalogInput, 2)) + (m_dCoeff3 * tempAnalogInput) + m_dCoeff4; + + //Serial.print(F(", PS_Voltage::tempAnalogInput (Compensated) = ")); + //Serial.print(tempAnalogInput); + //Serial.println(); + + } + + tempValue += map_double(tempAnalogInput, SENSOR_LOW, SENSOR_HIGH, MAPPED_LOW, MAPPED_HIGH); + + //if (st::PollingSensor::debug) + //{ + // Serial.print(F("PS_Voltage::tempValue = ")); + // Serial.print(tempValue); + // Serial.println(); + //} + } + + tempValue = tempValue / m_nNumSamples; //calculate the average value over the number of samples + + //implement filtering + if (m_fSensorValue == -1.0) + { + //first time through, no filtering + m_fSensorValue = tempValue; + } + else + { + m_fSensorValue = (m_fFilterConstant * tempValue) + (1 - m_fFilterConstant) * m_fSensorValue; + } + + Everything::sendSmartString(getName() + " " + String(m_fSensorValue)); + } + + void PS_Voltage::setPin(byte pin) + { + m_nAnalogInputPin=pin; + } +} diff --git a/lib/ST_Anything/PS_Voltage.h b/lib/ST_Anything/PS_Voltage.h new file mode 100644 index 0000000..d13057e --- /dev/null +++ b/lib/ST_Anything/PS_Voltage.h @@ -0,0 +1,120 @@ +//****************************************************************************************** +// File: PS_Voltage.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_Voltage is a class which implements the SmartThings "Voltage Measurement" device capability. +// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the +// voltage on an anlog input pin and then scale it to engineering units. +// +// The last four arguments of the constructor are used as arguments to an Arduino map() function which +// is used to scale the analog input readings (e.g. 0 to 1024) to Engineering Units before sending to SmartThings. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_Voltage sensor1(F("voltage1"), 120, 0, PIN_VOLTAGE, 0, 1023, 0.0, 5.0); +// +// st::PS_Voltage() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input +// - double s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - minimum raw AI value +// - double s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - maximum raw AI value +// - double m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Min (or Max if inverting) +// - double m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Max (or Min if inverting) +// - byte numSamples - OPTIONAL - defaults to 1, number of analog readings to average per scheduled reading of the analog input +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// +// Filtering/Averaging +// +// Filtering the value sent to ST is performed per the following equation +// +// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue) +// +//---------------------------------------------------------------------------------------------------------------------------------------------- +// st::PS_Voltage() has a second constructor which includes a 3rd order polynomial compensation algorithm. +// +// Create an instance of this class in your sketch's global variable section +// For Example: static st::PS_Voltage sensor5(F("voltage1"), 5, 1, PIN_VOLTAGE_1, -40, 140, 0, 4095, 20, 75, -0.000000025934, 0.0001049656215, 0.9032840665333, 204.642825355678); +// +// The following arguments all all REQUIRED in order to use the Compensation Algorithm. +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input +// - double s_l - OPTIONAL - first argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - minimum raw AI value +// - double s_h - OPTIONAL - second argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - maximum raw AI value +// - double m_l - OPTIONAL - third argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Min (or Max if inverting) +// - double m_h - OPTIONAL - fourth argument of Arduino map(s_l,s_h,m_l,m_h) function to scale the output - Engineering Unit Max (or Min if inverting) +// - byte numSamples - REQUIRED - number of analog readings to average per scheduled reading of the analog input +// - byte filterConstant - REQUIRED - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none, 5 = maximum +// - double Coeff1 - REQUIRED - 3rd order polynomial coefficient #1 +// - double Coeff2 - REQUIRED - 3rd order polynomial coefficient #2 +// - double Coeff3 - REQUIRED - 3rd order polynomial coefficient #3 +// - double Coeff4 - REQUIRED - 3rd order polynomial coefficient #4 +// +// 3rd order Plynomial Compensation Algorithm (useful for correcting non-linear analog to digital converters) +// +// CompensatedValue = Coeff1 * rawAnalogInput^3 + Coeff2 * rawAnalogInput^2 + Coeff3 * rawAnalogInput + Coeff4 +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-04-19 Dan & Daniel Original Creation +// 2017-08-18 Dan Ogorchock Modified to return floating point values instead of integer +// 2017-08-31 Dan Ogorchock Added oversampling optional argument to help reduce noisy signals +// 2017-08-31 Dan Ogorchock Added filtering optional argument to help reduce noisy signals +// 2017-09-01 Dan Ogorchock Added 3rd order polynomial nonlinear correction compensation +// 2018-06-24 Dan Ogorchock Improved documentation / comments (above) +// +// +//****************************************************************************************** +#ifndef ST_PS_VOLTAGE_H +#define ST_PS_VOLTAGE_H + +#include "PollingSensor.h" + +namespace st +{ + class PS_Voltage: public PollingSensor + { + private: + byte m_nAnalogInputPin; + float m_fSensorValue; + double SENSOR_LOW, SENSOR_HIGH, MAPPED_LOW, MAPPED_HIGH; + int m_nNumSamples; + float m_fFilterConstant; //Filter constant % as floating point from 0.00 to 1.00 + double m_dCoeff1, m_dCoeff2, m_dCoeff3, m_dCoeff4; //3rd order polynomial nonlinear correction compensation coefficients + bool m_bUseCompensation; + + public: + //constructor - called in your sketch's global variable declaration section + PS_Voltage(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double s_l=0, double s_h=1023, double m_l=0, double m_h=5000, int NumSamples=1, byte filterConstant = 100); + + //constructor with 3rd order polynomial nonlinear correction compensation coefficients - called in your sketch's global variable declaration section + PS_Voltage(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, double s_l, double s_h, double m_l, double m_h, int NumSamples, byte filterConstant, double Coeff1, double Coeff2, double Coeff3, double Coeff4); + + //destructor + virtual ~PS_Voltage(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline byte getPin() const {return m_nAnalogInputPin;} + inline float getSensorValue() const {return m_fSensorValue;} + + //sets + void setPin(byte pin); + }; +} +#endif diff --git a/lib/ST_Anything/PS_Water.cpp b/lib/ST_Anything/PS_Water.cpp new file mode 100644 index 0000000..583c9aa --- /dev/null +++ b/lib/ST_Anything/PS_Water.cpp @@ -0,0 +1,115 @@ +//****************************************************************************************** +// File: PS_Water.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_Water is a class which implements both the SmartThings "Water Sensor" device capability. +// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the +// presence of water using an inexpensive water sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_Water sensor3(F("water1"), 60, 6, PIN_WATER, 200, false); +// +// st::PS_Water() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input +// - int limit - OPTIONAL - the alarm limit to compare analog pin's reading to, above which the sensor reports "wet" instead of "dry", default = 100 +// - bool invertLogic - OPTIONAL - if set to true, will invert the comparison against target from < to >, default = false +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-08-23 Dan Added optional alarm limit to constructor +// 2018-10-17 Dan Added invertLogic parameter to constructor +// +// +//****************************************************************************************** + + +#include "PS_Water.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + PS_Water::PS_Water(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int limit, bool invertLogic): + PollingSensor(name, interval, offset), + m_nSensorValue(0), + m_nSensorLimit(limit), + m_binvertLogic(invertLogic) + { + setPin(analogInputPin); + } + + //destructor + PS_Water::~PS_Water() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_Water::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_Water::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_Water::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_Water::getData() + { + int m_nSensorValue = analogRead(m_nAnalogInputPin); + + if (st::PollingSensor::debug) + { + Serial.print(F("PS_Water::Analog Pin value is ")); + Serial.print(m_nSensorValue); + Serial.print(F(" vs limit of ")); + Serial.println(m_nSensorLimit); + } + + //compare the sensor's value is against the limit to determine whether to send "dry" versus "wet". + if (m_binvertLogic) + { + Everything::sendSmartString(getName() + (m_nSensorValue > m_nSensorLimit ? F(" dry") : F(" wet"))); + } + else + { + Everything::sendSmartString(getName() + (m_nSensorValue < m_nSensorLimit ? F(" dry") : F(" wet"))); + } + } + + void PS_Water::setPin(byte pin) + { + m_nAnalogInputPin=pin; + } +} \ No newline at end of file diff --git a/lib/ST_Anything/PS_Water.h b/lib/ST_Anything/PS_Water.h new file mode 100644 index 0000000..92cdc50 --- /dev/null +++ b/lib/ST_Anything/PS_Water.h @@ -0,0 +1,77 @@ +//****************************************************************************************** +// File: PS_Water.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_Water is a class which implements both the SmartThings "Water Sensor" device capability. +// It inherits from the st::PollingSensor class. The current version uses an analog input to measure the +// presence of water using an inexpensive water sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_Water sensor3(F("water1"), 60, 6, PIN_WATER, 200, false); +// +// st::PS_Water() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as an analog input +// - int limit - OPTIONAL - the alarm limit to compare analog pin's reading to, above which the sensor reports "wet" instead of "dry", default = 100 +// - bool invertLogic - OPTIONAL - if set to true, will invert the comparison against target from < to >, default = false +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-08-23 Dan Added optional alarm limit to constructor +// 2018-10-17 Dan Added invertLogic parameter to constructor +// +// +//****************************************************************************************** + +#ifndef ST_PS_WATER_H +#define ST_PS_WATER_H + +#include "PollingSensor.h" + +namespace st +{ + class PS_Water: public PollingSensor + { + private: + byte m_nAnalogInputPin; //analog pin connected to the water sensor + int m_nSensorValue; //current sensor value + int m_nSensorLimit; //alarm limit + bool m_binvertLogic; //if false use <, if true use > for comparison of AI value versus limit + + public: + //constructor - called in your sketch's global variable declaration section + PS_Water(const __FlashStringHelper *name, unsigned int interval, int offset, byte analogInputPin, int limit = 100, bool invertLogic = false); + + //destructor + virtual ~PS_Water(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline byte getPin() const {return m_nAnalogInputPin;} + inline byte getSensorValue() const {return m_nSensorValue;} + + //sets + void setPin(byte pin); + + }; +} + + + +#endif \ No newline at end of file diff --git a/lib/ST_Anything/PollingSensor.cpp b/lib/ST_Anything/PollingSensor.cpp new file mode 100644 index 0000000..dd2f3af --- /dev/null +++ b/lib/ST_Anything/PollingSensor.cpp @@ -0,0 +1,113 @@ +//****************************************************************************************** +// File: PollingSensor.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: st::PollingSensor is a generic class which inherits from st::Sensor. This is the +// parent class for the st::PS_Illuminace, st::PS_Water, and PS_TemperatureHumidity classes. +// +// In general, this file should not need to be modified. +// +// st::PollingSensor() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// +// +//****************************************************************************************** + +#include "PollingSensor.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + bool PollingSensor::checkInterval() + { + //check for time overflow + if(millis()=m_nInterval) + { + m_nDeltaTime=0; + return true; + } + else + { + return false; + } + } + +//public + //constructor + PollingSensor::PollingSensor(const __FlashStringHelper *name, long interval, long offset): + Sensor(name), + m_nPreviousTime(0), + m_nDeltaTime(0), + m_nInterval(interval*1000), + m_nOffset(offset*1000) + { + + } + + //destructor + PollingSensor::~PollingSensor() + { + + } + + void PollingSensor::init() + { + getData(); + } + + void PollingSensor::refresh() + { + getData(); + } + + void PollingSensor::update() + { + if(checkInterval()) + { + getData(); + } + } + + void PollingSensor::getData() + { + if(debug) + { + Everything::sendSmartString(getName() + F(" triggered")); + } + } + + //debug flag to determine if debug print statements are executed (set value in your sketch) + bool PollingSensor::debug=false; +} \ No newline at end of file diff --git a/lib/ST_Anything/PollingSensor.h b/lib/ST_Anything/PollingSensor.h new file mode 100644 index 0000000..95e55fc --- /dev/null +++ b/lib/ST_Anything/PollingSensor.h @@ -0,0 +1,74 @@ +//****************************************************************************************** +// File: PollingSensor.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: st::PollingSensor is a generic class which inherits from st::Sensor. This is the +// parent class for the st::PS_Illuminace, st::PS_Water, and PS_TemperatureHumidity classes. +// +// In general, this file should not need to be modified. +// +// st::PollingSensor() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// +// +//****************************************************************************************** + +#ifndef ST_POLLINGSENSOR_H +#define ST_POLLINGSENSOR_H + +#include "Sensor.h" + +namespace st +{ + class PollingSensor: public Sensor + { + private: + unsigned long m_nPreviousTime; //in milliseconds - time of last poll + long m_nDeltaTime; //in milliseconds - elapsed time since last poll + long m_nInterval; //in milliseconds - polling interval for the sensor + long m_nOffset; //in milliseconds - offset to prevent all Polling sensors from running at the same time + + virtual bool checkInterval(); //returns true and resets m_nDeltaTime if m_nInterval has been reached + + public: + //constructor + PollingSensor(const __FlashStringHelper *name, long interval, long offset=0); + + //destructor + virtual ~PollingSensor(); + + //initialization function + virtual void init(); + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of each Device subclass object + virtual void refresh(); + + //update function + virtual void update(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + virtual void offset(long os) {m_nOffset=os;} //offset the delta time from its current value + + //sets + virtual void setInterval(long interval) {m_nInterval=interval;} + + //debug flag to determine if debug print statements are executed (set value in your sketch) + static bool debug; + + }; +} + + + +#endif \ No newline at end of file diff --git a/lib/ST_Anything/S_TimedRelay.cpp b/lib/ST_Anything/S_TimedRelay.cpp new file mode 100644 index 0000000..fec915a --- /dev/null +++ b/lib/ST_Anything/S_TimedRelay.cpp @@ -0,0 +1,206 @@ +//****************************************************************************************** +// File: S_TimedRelay.cpp +// Authors: Dan G Ogorchock +// +// Summary: S_TimedRelay is a class which implements the SmartThings "Relay" device capability. It features +// an automatic-turn-off time delay for a relay to emulate a button press. +// +// It inherits from the st::Sensor class and clones much from the st::Executor Class +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::S_TimedRelay sensor1(F("relaySwitch1"), PIN_RELAY, LOW, true, 1000, 0, 1, 0); +// +// st::S_TimedRelay() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pinOutput - REQUIRED - the Arduino Pin to be used as a digital output +// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Ouput should use inverted logic +// - long onTime - REQUIRED - the number of milliseconds to keep the output on, DEFAULTS to 1000 milliseconds +// - long offTime - OPTIONAL - the number of milliseconds to keep the output off, DEFAULTS to 0 +// - int numCycles - OPTIONAL - the number of times to repeat the on/off cycle, DEFAULTS to 1 +// - byte finalState - OPTIONAL - leave in X state after finishing sequence 0 = off, 1 = on , Defaults to 0 +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-12-29 Dan Ogorchock Original Creation +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2019-06-23 Brian Wilson Added finalState option +// 2020-10-20 Dan Ogorchock Fixed minor bug to ensure proper reporting of device state +// +// +//****************************************************************************************** + +#include "S_TimedRelay.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + void S_TimedRelay::writeStateToPin() + { + digitalWrite(m_nOutputPin, m_bInvertLogic ? !m_bCurrentState : m_bCurrentState); + } + +//public + //constructor + S_TimedRelay::S_TimedRelay(const __FlashStringHelper *name, byte pinOutput, bool startingState, bool invertLogic, unsigned long onTime, unsigned long offTime, unsigned int numCycles, byte finalState) : + Sensor(name), + m_bCurrentState(startingState), + m_bInvertLogic(invertLogic), + m_lOnTime(onTime), + m_lOffTime(offTime), + m_iNumCycles(numCycles), + m_iCurrentCount(numCycles), + m_nfinalState(finalState), + m_lTimeChanged(0), + m_bTimerPending(false) + { + setOutputPin(pinOutput); + + if (numCycles < 1) + { + m_iNumCycles = 1; + m_iCurrentCount = 1; + + Serial.println(F("S_TimedRelay:: INVALID Number of Cycles Requested! Must be at least 1. Setting to 1.")); + } + } + + //destructor + S_TimedRelay::~S_TimedRelay() + { + } + + void S_TimedRelay::init() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + } + + //update function + void S_TimedRelay::update() + { + if (m_iCurrentCount < m_iNumCycles) + { + //Turn off digital output if timer has expired + if ((m_bCurrentState == HIGH) && (millis() - m_lTimeChanged >= m_lOnTime)) + { + if (m_nfinalState == 1) { // final state will be on + //add one to the current count since we finished an on/off cycle, and turn on output if needed + m_iCurrentCount++; + if (m_iCurrentCount < m_iNumCycles) + { + m_bCurrentState = LOW; + writeStateToPin(); + m_lTimeChanged = millis(); + } + + } else { + m_bCurrentState = LOW; + writeStateToPin(); + m_lTimeChanged = millis(); + } + } + else if ((m_bCurrentState == LOW) && (millis() - m_lTimeChanged >= m_lOffTime)) + { + if (m_nfinalState == 0) { // final state will be off + //add one to the current count since we finished an on/off cycle, and turn on output if needed + m_iCurrentCount++; + if (m_iCurrentCount < m_iNumCycles) + { + m_bCurrentState = HIGH; + writeStateToPin(); + m_lTimeChanged = millis(); + } + } else { + m_bCurrentState = HIGH; + writeStateToPin(); + m_lTimeChanged = millis(); + } + } + + //Check to see if we just finished the requested number of cycles + if (m_iCurrentCount == m_iNumCycles) + { + //Decrement number of active timers + if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--; + m_bTimerPending = false; + + //Queue the relay status update the ST Cloud + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + } + } + } + + void S_TimedRelay::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + if (st::Device::debug) { + Serial.print(F("S_TimedRelay::beSmart s = ")); + Serial.println(s); + } + if ((s == F("on")) && (m_bCurrentState == LOW)) + { + m_bCurrentState = HIGH; + + //Save time turned on + m_lTimeChanged = millis(); + + //Increment number of active timers + if (!m_bTimerPending) + { + st::Everything::bTimersPending++; + m_bTimerPending = true; + } + //Queue the relay status update the ST Cloud + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + + //Set the initial count to zero + m_iCurrentCount = 0; + + //update the digital output + writeStateToPin(); + } + else if ((s == F("off")) && (m_bCurrentState == HIGH)) + { + m_bCurrentState = LOW; + + //Decrement number of active timers + if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--; + m_bTimerPending = false; + + //Queue the relay status update the ST Cloud + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + + //Reset the count to the number of required cycles to prevent Update() routine from running if someone sends an OFF command + m_iCurrentCount = m_iNumCycles; + + //update the digital output + writeStateToPin(); + } + else + { + //Queue the relay status update the ST Cloud + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + } + + } + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor + void S_TimedRelay::refresh() + { + //Queue the relay status update the ST Cloud + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + } + + void S_TimedRelay::setOutputPin(byte pin) + { + m_nOutputPin = pin; + pinMode(m_nOutputPin, OUTPUT); + writeStateToPin(); + } + +} diff --git a/lib/ST_Anything/S_TimedRelay.h b/lib/ST_Anything/S_TimedRelay.h new file mode 100644 index 0000000..c229326 --- /dev/null +++ b/lib/ST_Anything/S_TimedRelay.h @@ -0,0 +1,90 @@ +//****************************************************************************************** +// File: S_TimedRelay.h +// Authors: Dan G Ogorchock +// +// Summary: S_TimedRelay is a class which implements the SmartThings "Relay" device capability. It features +// an automatic-turn-off time delay for a relay to emulate a button press. +// +// It inherits from the st::Sensor class and clones much from the st::Executor Class +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::S_TimedRelay sensor1(F("relaySwitch1"), PIN_RELAY, LOW, true, 1000, 0, 1, 0); +// +// st::S_TimedRelay() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pinOutput - REQUIRED - the Arduino Pin to be used as a digital output +// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Ouput should use inverted logic +// - long onTime - REQUIRED - the number of milliseconds to keep the output on, DEFAULTS to 1000 milliseconds +// - long offTime - OPTIONAL - the number of milliseconds to keep the output off, DEFAULTS to 0 +// - int numCycles - OPTIONAL - the number of times to repeat the on/off cycle, DEFAULTS to 1 +// - byte finalState - OPTIONAL - leave in X state after finishing sequence 0 = off, 1 = on , Defaults to 0 +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-12-29 Dan Ogorchock Original Creation +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2019-06-23 Brian Wilson Added finalState option +// 2019-08-10 Dan Ogorchock Added public getStatus() +// +// +//****************************************************************************************** + +#ifndef ST_S_TIMEDRELAY_H +#define ST_S_TIMEDRELAY_H + +#include "Sensor.h" + +namespace st +{ + class S_TimedRelay : public Sensor //inherits from parent Sensor Class + { + private: + + //following are for the digital output + bool m_bCurrentState; //HIGH or LOW + bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic + byte m_nOutputPin; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED + unsigned long m_lOnTime; //number of milliseconds to keep digital output HIGH before automatically turning off + unsigned long m_lOffTime; //number of milliseconds to keep digital output LOW before automatically turning on + unsigned int m_iNumCycles; //number of on/off cycles of the digital output + unsigned int m_iCurrentCount; //current number of on/off cycles of the digital output + byte m_nfinalState; //desired final state of the output after the cycling has completed (typical value is 0) + unsigned long m_lTimeChanged; //time when the digital output was last changed + bool m_bTimerPending; //true if waiting on relay timer to expire + + void writeStateToPin(); //function to update the Arduino Digital Output Pin + + public: + //constructor - called in your sketch's global variable declaration section + S_TimedRelay(const __FlashStringHelper *name, byte pinOutput, bool startingState = LOW, bool invertLogic = false, unsigned long onTime = 1000, unsigned long offTime = 0, unsigned int numCycles = 1, byte finalState = 0); + + //destructor + virtual ~S_TimedRelay(); + + //initialization function + virtual void init(); + + //update function + void update(); + + //SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output) + virtual void beSmart(const String &str); + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor + virtual void refresh(); + + //gets + virtual byte getPin() const { return m_nOutputPin; } + virtual bool getTimerActive() const { return m_bTimerPending; } + virtual bool getStatus() const { return m_bCurrentState; } + + //sets + virtual void setOutputPin(byte pin); + }; +} + + +#endif diff --git a/lib/ST_Anything/Sensor.cpp b/lib/ST_Anything/Sensor.cpp new file mode 100644 index 0000000..eac6a87 --- /dev/null +++ b/lib/ST_Anything/Sensor.cpp @@ -0,0 +1,46 @@ +//****************************************************************************************** +// File: Sensor.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: st::Sensor is a generic class which inherits from st::Device. This is the +// parent class for the st::PollingSensor and st::InterruptSensor classes. +// In general, this file should not need to be modified. +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// +// +//****************************************************************************************** + +#include "Sensor.h" + +#include "Constants.h" + +namespace st +{ +//private + + +//public + //constructor + Sensor::Sensor(const __FlashStringHelper *name): + Device(name) + { + + } + + //destructor + Sensor::~Sensor() + { + + } + + void Sensor::beSmart(const String &str) + { + //Each derived class should implement this if they are interfacing with SmartThings over the internet. + } + +} \ No newline at end of file diff --git a/lib/ST_Anything/Sensor.h b/lib/ST_Anything/Sensor.h new file mode 100644 index 0000000..b7590f6 --- /dev/null +++ b/lib/ST_Anything/Sensor.h @@ -0,0 +1,50 @@ +//****************************************************************************************** +// File: Sensor.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: st::Sensor is a generic class which inherits from st::Device. This is the +// parent class for the st::PollingSensor and st::InterruptSensor classes. +// In general, this file should not need to be modified. +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2019-02-09 Dan Ogorchock Moved update() from Sensor to Device +// +// +//****************************************************************************************** + +#ifndef ST_SENSOR_H +#define ST_SENSOR_H + +#include "Device.h" + +namespace st +{ + //abstract + class Sensor: public Device + { + private: + + public: + //constructor + Sensor(const __FlashStringHelper *name); + + //destructor + virtual ~Sensor(); + + //SmartThings Shield data handler + virtual void beSmart(const String &str); + + //all derived classes must implement these pure virtual functions + virtual void init()=0; + + }; + + +} + + +#endif \ No newline at end of file diff --git a/lib/ST_Anything_AdafruitAM2320_TempHumid/PS_AdafruitAM2320_TempHumid.cpp b/lib/ST_Anything_AdafruitAM2320_TempHumid/PS_AdafruitAM2320_TempHumid.cpp new file mode 100644 index 0000000..9b253ef --- /dev/null +++ b/lib/ST_Anything_AdafruitAM2320_TempHumid/PS_AdafruitAM2320_TempHumid.cpp @@ -0,0 +1,171 @@ +//****************************************************************************************** +// File: PS_AdafruitAM2320_TempHumid.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_AdafruitAM2320_TempHumid is a class which implements the "Temperature Measurement" +// and "Relative Humidity Measurement" device capabilities. +// It inherits from the st::PollingSensor class. The current version uses I2C to measure the +// temperature and humidity from an AM2320 series sensor using the Adafruit_AM2320 library. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitAM2320_TempHumid sensor2("AM2320_1", 60, 0, "temperature1", "humidity1", false, 100); +// +// st::PS_AdafruitAM2320_TempHumid() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must be unique, but is not used for data transfer for this device +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - String strTemp - REQUIRED - name of temperature sensor to send to ST Cloud (e.g."temperature1") +// - String strHumid - REQUIRED - name of humidity sensor to send to ST Cloud (e.g. "humidity1") +// - bool In_C - OPTIONAL - true = Report Celsius, false = Report Farenheit (Farentheit is the default) +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// +// Filtering/Averaging +// +// Filtering the value sent to ST is performed per the following equation +// +// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue) +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2018-07-01 Dan & Daniel Original Creation +// +//****************************************************************************************** + +#include "PS_AdafruitAM2320_TempHumid.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + PS_AdafruitAM2320_TempHumid::PS_AdafruitAM2320_TempHumid(const __FlashStringHelper *name, unsigned int interval, int offset, String strTemp, String strHumid, bool In_C, byte filterConstant) : + PollingSensor(name, interval, offset), + am2320(), + m_fTemperatureSensorValue(-1.0), + m_fHumiditySensorValue(-1.0), + m_strTemperature(strTemp), + m_strHumidity(strHumid), + m_In_C(In_C) + { + //check for upper and lower limit and adjust accordingly + if ((filterConstant <= 0) || (filterConstant >= 100)) + { + m_fFilterConstant = 1.0; + } + else if (filterConstant <= 5) + { + m_fFilterConstant = 0.05; + } + else + { + m_fFilterConstant = float(filterConstant) / 100; + } + + } + + //destructor + PS_AdafruitAM2320_TempHumid::~PS_AdafruitAM2320_TempHumid() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_AdafruitAM2320_TempHumid::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_AdafruitAM2320_TempHumid::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_AdafruitAM2320_TempHumid::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //initialization routine - get first set of readings and send to ST cloud + void PS_AdafruitAM2320_TempHumid::init() + { + bool status = am2320.begin(); + if (st::PollingSensor::debug) + { + if (!status) { + Serial.println(); + Serial.println("Could not find a valid AM2320 sensor, check wiring!"); + Serial.println(); + delay(3000); + } + } + + getData(); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_AdafruitAM2320_TempHumid::getData() + { + + //Humidity + if (m_fHumiditySensorValue == -1.0) + { + Serial.println("First time through Humidity"); + m_fHumiditySensorValue = am2320.readHumidity(); //first time through, no filtering + } + else + { + m_fHumiditySensorValue = (m_fFilterConstant * am2320.readHumidity()) + (1 - m_fFilterConstant) * m_fHumiditySensorValue; + } + + //Temperature + if (m_fTemperatureSensorValue == -1.0) + { + Serial.println("First time through Temperature"); + //first time through, no filtering + if (m_In_C == false) + { + m_fTemperatureSensorValue = (am2320.readTemperature() * 1.8) + 32.0; //Scale from Celsius to Farenheit + } + else + { + m_fTemperatureSensorValue = am2320.readTemperature(); + } + } + else + { + if (m_In_C == false) + { + m_fTemperatureSensorValue = (m_fFilterConstant * ((am2320.readTemperature() * 1.8) + 32.0)) + (1 - m_fFilterConstant) * m_fTemperatureSensorValue; + } + else + { + m_fTemperatureSensorValue = (m_fFilterConstant * am2320.readTemperature()) + (1 - m_fFilterConstant) * m_fTemperatureSensorValue; + } + + } + + Everything::sendSmartString(m_strTemperature + " " + String(m_fTemperatureSensorValue)); + Everything::sendSmartString(m_strHumidity + " " + String(m_fHumiditySensorValue)); + + } + +} \ No newline at end of file diff --git a/lib/ST_Anything_AdafruitAM2320_TempHumid/PS_AdafruitAM2320_TempHumid.h b/lib/ST_Anything_AdafruitAM2320_TempHumid/PS_AdafruitAM2320_TempHumid.h new file mode 100644 index 0000000..84060f9 --- /dev/null +++ b/lib/ST_Anything_AdafruitAM2320_TempHumid/PS_AdafruitAM2320_TempHumid.h @@ -0,0 +1,82 @@ +//****************************************************************************************** +// File: PS_AdafruitAM2320_TempHumid.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_AdafruitAM2320_TempHumid is a class which implements the "Temperature Measurement" +// and "Relative Humidity Measurement" device capabilities. +// It inherits from the st::PollingSensor class. The current version uses I2C to measure the +// temperature and humidity from an AM2320 series sensor using the Adafruit_AM2320 library. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitAM2320_TempHumid sensor2("AM2320_1", 60, 0, "temperature1", "humidity1", false, 100); +// +// st::PS_AdafruitAM2320_TempHumid() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must be unique, but is not used for data transfer for this device +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - String strTemp - REQUIRED - name of temperature sensor to send to ST Cloud (e.g."temperature1") +// - String strHumid - REQUIRED - name of humidity sensor to send to ST Cloud (e.g. "humidity1") +// - bool In_C - OPTIONAL - true = Report Celsius, false = Report Farenheit (Farentheit is the default) +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// +// Filtering/Averaging +// +// Filtering the value sent to ST is performed per the following equation +// +// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue) +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2018-07-01 Dan & Daniel Original Creation +// +//****************************************************************************************** + +#ifndef ST_PS_AdafruitAM2320_TempHumid_H +#define ST_PS_AdafruitAM2320_TempHumid_H + +#include "PollingSensor.h" +#include + +namespace st +{ + class PS_AdafruitAM2320_TempHumid: public PollingSensor + { + private: + float m_fTemperatureSensorValue;//current Temperature value + float m_fHumiditySensorValue; //current Humidity Value + Adafruit_AM2320 am2320; //I2C AM2320 library object + String m_strTemperature; //name of temparature sensor to use when transferring data to ST Cloud / Hubitat + String m_strHumidity; //name of humidity sensor to use when transferring data to ST Cloud / Hubitat + bool m_In_C; //Return temp in C (true or false) + float m_fFilterConstant; //Filter constant % as floating point from 0.00 to 1.00 + + public: + //constructor - called in your sketch's global variable declaration section + PS_AdafruitAM2320_TempHumid(const __FlashStringHelper *name, unsigned int interval, int offset, String strTemp = "temperature1", String strHumid = "humidity1", bool In_C = false, byte filterConstant = 100); + + //destructor + virtual ~PS_AdafruitAM2320_TempHumid(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline float getTemperatureSensorValue() const { return m_fTemperatureSensorValue; } + inline float getHumiditySensorValue() const { return m_fHumiditySensorValue; } + }; +} +#endif diff --git a/lib/ST_Anything_AdafruitBME280_TempHumidPress/PS_AdafruitBME280_TempHumidPress.cpp b/lib/ST_Anything_AdafruitBME280_TempHumidPress/PS_AdafruitBME280_TempHumidPress.cpp new file mode 100644 index 0000000..f579349 --- /dev/null +++ b/lib/ST_Anything_AdafruitBME280_TempHumidPress/PS_AdafruitBME280_TempHumidPress.cpp @@ -0,0 +1,193 @@ +//****************************************************************************************** +// File: PS_AdafruitBME280_TempHumidPress.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_AdafruitBME280_TempHumidPress is a class which implements the "Temperature Measurement", +// "Relative Humidity Measurement", and "PressureMewasurement" device capabilities. +// It inherits from the st::PollingSensor class. The current version uses I2C to measure the +// temperature, humidity, and pressure from a BME280 series sensor using the Adafruit_BME280 library. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitBME280_TempHumidPress sensor2(F("bme280_1"), 60, 0, "temperature1", "humidity1", "pressure1", false, 100, 0x77); +// +// st::PS_AdafruitBME280_TempHumidPress() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must be unique, but is not used for data transfer for this device +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - String strTemp - REQUIRED - name of temperature sensor to send to ST Cloud (e.g."temperature1") +// - String strHumid - REQUIRED - name of humidity sensor to send to ST Cloud (e.g. "humidity1") +// - String strPressure - REQUIRED - name of pressure sensor to send to ST Cloud (e.g. "pressure1") +// - bool In_C - OPTIONAL - true = Report Celsius, false = Report Fahrenheit (Fahrenheit is the default) +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// - int address - OPTIONAL - I2C address of the sensor (defaults to 0x77 for the BME280) +// +// Filtering/Averaging +// +// Filtering the value sent to ST is performed per the following equation +// +// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue) +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2018-07-01 Dan & Daniel Original Creation +// +//****************************************************************************************** + +#include "PS_AdafruitBME280_TempHumidPress.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + PS_AdafruitBME280_TempHumidPress::PS_AdafruitBME280_TempHumidPress(const __FlashStringHelper *name, unsigned int interval, int offset, String strTemp, String strHumid, String strPressure, bool In_C, byte filterConstant, int address) : + PollingSensor(name, interval, offset), + bme(), + m_fTemperatureSensorValue(-1.0), + m_fHumiditySensorValue(-1.0), + m_fPressureSensorValue(-1.0), + m_strTemperature(strTemp), + m_strHumidity(strHumid), + m_strPressure(strPressure), + m_In_C(In_C), + m_nAddress(address) + { + //check for upper and lower limit and adjust accordingly + if ((filterConstant <= 0) || (filterConstant >= 100)) + { + m_fFilterConstant = 1.0; + } + else if (filterConstant <= 5) + { + m_fFilterConstant = 0.05; + } + else + { + m_fFilterConstant = float(filterConstant) / 100; + } + + } + + //destructor + PS_AdafruitBME280_TempHumidPress::~PS_AdafruitBME280_TempHumidPress() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_AdafruitBME280_TempHumidPress::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_AdafruitBME280_TempHumidPress::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_AdafruitBME280_TempHumidPress::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //initialization routine - get first set of readings and send to ST cloud + void PS_AdafruitBME280_TempHumidPress::init() + { + char buf[5]; + sprintf(buf, "%02X", m_nAddress); + + bool status = bme.begin(m_nAddress); + if (st::PollingSensor::debug) + { + if (!status) { + Serial.println(); + Serial.print("Error: Could not find a valid BME280 sensor at address 0x"); + Serial.print(buf); + Serial.println(", check wiring and address setting in sketch!"); + Serial.println(); + delay(3000); + } + } + + getData(); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_AdafruitBME280_TempHumidPress::getData() + { + + //Humidity + if (m_fHumiditySensorValue == -1.0) + { + Serial.println("First time through Humidity"); + m_fHumiditySensorValue = bme.readHumidity(); //first time through, no filtering + } + else + { + m_fHumiditySensorValue = (m_fFilterConstant * bme.readHumidity()) + (1 - m_fFilterConstant) * m_fHumiditySensorValue; + } + + //Temperature + if (m_fTemperatureSensorValue == -1.0) + { + Serial.println("First time through Temperature"); + //first time through, no filtering + if (m_In_C == false) + { + m_fTemperatureSensorValue = (bme.readTemperature() * 1.8) + 32.0; //Scale from Celsius to Farenheit + } + else + { + m_fTemperatureSensorValue = bme.readTemperature(); + } + } + else + { + if (m_In_C == false) + { + m_fTemperatureSensorValue = (m_fFilterConstant * ((bme.readTemperature() * 1.8) + 32.0)) + (1 - m_fFilterConstant) * m_fTemperatureSensorValue; + } + else + { + m_fTemperatureSensorValue = (m_fFilterConstant * bme.readTemperature()) + (1 - m_fFilterConstant) * m_fTemperatureSensorValue; + } + + } + + //Pressure + if (m_fPressureSensorValue == -1.0) + { + Serial.println("First time through Pressure"); + m_fPressureSensorValue = (bme.readPressure() / 100.0F); //first time through, no filtering + } + else + { + m_fPressureSensorValue = (m_fFilterConstant * (bme.readPressure() / 100.0F)) + (1 - m_fFilterConstant) * m_fPressureSensorValue; + } + + Everything::sendSmartString(m_strTemperature + " " + String(m_fTemperatureSensorValue)); + Everything::sendSmartString(m_strHumidity + " " + String(m_fHumiditySensorValue)); + Everything::sendSmartString(m_strPressure + " " + String(m_fPressureSensorValue)); + + } + +} diff --git a/lib/ST_Anything_AdafruitBME280_TempHumidPress/PS_AdafruitBME280_TempHumidPress.h b/lib/ST_Anything_AdafruitBME280_TempHumidPress/PS_AdafruitBME280_TempHumidPress.h new file mode 100644 index 0000000..4fe7ff0 --- /dev/null +++ b/lib/ST_Anything_AdafruitBME280_TempHumidPress/PS_AdafruitBME280_TempHumidPress.h @@ -0,0 +1,88 @@ +//****************************************************************************************** +// File: PS_AdafruitBME280_TempHumidPress.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_AdafruitBME280_TempHumidPress is a class which implements the "Temperature Measurement", +// "Relative Humidity Measurement", and "PressureMewasurement" device capabilities. +// It inherits from the st::PollingSensor class. The current version uses I2C to measure the +// temperature, humidity, and pressure from a BME280 series sensor using the Adafruit_BME280 library. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitBME280_TempHumidPress sensor2(F("bme280_1"), 60, 0, "temperature1", "humidity1", "pressure1", false, 100, 0x77); +// +// st::PS_AdafruitBME280_TempHumidPress() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must be unique, but is not used for data transfer for this device +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - String strTemp - REQUIRED - name of temperature sensor to send to ST Cloud (e.g."temperature1") +// - String strHumid - REQUIRED - name of humidity sensor to send to ST Cloud (e.g. "humidity1") +// - String strPressure - REQUIRED - name of pressure sensor to send to ST Cloud (e.g. "pressure1") +// - bool In_C - OPTIONAL - true = Report Celsius, false = Report Fahrenheit (Fahrenheit is the default) +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// - int address - OPTIONAL - I2C address of the sensor (defaults to 0x77 for the BME280) +// +// Filtering/Averaging +// +// Filtering the value sent to ST is performed per the following equation +// +// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue) +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2018-07-01 Dan & Daniel Original Creation +// +//****************************************************************************************** + +#ifndef ST_PS_AdafruitBME280_TempHumidPress_H +#define ST_PS_AdafruitBME280_TempHumidPress_H + +#include "PollingSensor.h" +#include + +namespace st +{ + class PS_AdafruitBME280_TempHumidPress: public PollingSensor + { + private: + int m_nAddress; //I2C Address of the sensor + float m_fTemperatureSensorValue;//current Temperature value + float m_fHumiditySensorValue; //current Humidity Value + float m_fPressureSensorValue; //current Pressure Value + Adafruit_BME280 bme; //I2C BME280 library object + String m_strTemperature; //name of temparature sensor to use when transferring data to ST Cloud / Hubitat + String m_strHumidity; //name of humidity sensor to use when transferring data to ST Cloud / Hubitat + String m_strPressure; //name of pressure sensor to use when transferring data to ST Cloud / Hubitat + bool m_In_C; //Return temp in C (true or false) + float m_fFilterConstant; //Filter constant % as floating point from 0.00 to 1.00 + + public: + //constructor - called in your sketch's global variable declaration section + PS_AdafruitBME280_TempHumidPress(const __FlashStringHelper *name, unsigned int interval, int offset, String strTemp = "temperature1", String strHumid = "humidity1", String strPressure = "pressure1", bool In_C = false, byte filterConstant = 100, int address = 0x77); + + //destructor + virtual ~PS_AdafruitBME280_TempHumidPress(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline float getTemperatureSensorValue() const { return m_fTemperatureSensorValue; } + inline float getHumiditySensorValue() const { return m_fHumiditySensorValue; } + inline float getPressureSensorValue() const { return m_fPressureSensorValue; } + }; +} +#endif diff --git a/lib/ST_Anything_AdafruitBMP280_TempPress/PS_AdafruitBMP280_TempPress.cpp b/lib/ST_Anything_AdafruitBMP280_TempPress/PS_AdafruitBMP280_TempPress.cpp new file mode 100644 index 0000000..ccaf9bc --- /dev/null +++ b/lib/ST_Anything_AdafruitBMP280_TempPress/PS_AdafruitBMP280_TempPress.cpp @@ -0,0 +1,178 @@ +//****************************************************************************************** +// File: PS_AdafruitBMP280_TempPress.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_AdafruitBMP280_TempPress is a class which implements the "Temperature Measurement" +// and "PressureMewasurement" device capabilities. +// It inherits from the st::PollingSensor class. The current version uses I2C to measure the +// temperature and pressure from a BMP280 series sensor using the Adafruit_BMP280 library. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitBMP280_TempPress sensor2("BMP280_1", 60, 0, "temperature1", "pressure1", false, 100, 0x77); +// +// st::PS_AdafruitBMP280_TempPress() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must be unique, but is not used for data transfer for this device +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - String strTemp - REQUIRED - name of temperature sensor to send to ST Cloud (e.g."temperature1") +// - String strPressure - REQUIRED - name of pressure sensor to send to ST Cloud (e.g. "pressure1") +// - bool In_C - OPTIONAL - true = Report Celsius, false = Report Farenheit (Farentheit is the default) +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// - int address - OPTIONAL - I2C address of the sensor (defaults to 0x77 for the BMP280) +// +// Filtering/Averaging +// +// Filtering the value sent to ST is performed per the following equation +// +// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue) +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2018-07-01 Dan & Daniel Original Creation +// +//****************************************************************************************** + +#include "PS_AdafruitBMP280_TempPress.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + PS_AdafruitBMP280_TempPress::PS_AdafruitBMP280_TempPress(const __FlashStringHelper *name, unsigned int interval, int offset, String strTemp, String strPressure, bool In_C, byte filterConstant, int address) : + PollingSensor(name, interval, offset), + bmp(), + m_fTemperatureSensorValue(-1.0), + m_fPressureSensorValue(-1.0), + m_strTemperature(strTemp), + m_strPressure(strPressure), + m_In_C(In_C), + m_nAddress(address) + { + //check for upper and lower limit and adjust accordingly + if ((filterConstant <= 0) || (filterConstant >= 100)) + { + m_fFilterConstant = 1.0; + } + else if (filterConstant <= 5) + { + m_fFilterConstant = 0.05; + } + else + { + m_fFilterConstant = float(filterConstant) / 100; + } + + } + + //destructor + PS_AdafruitBMP280_TempPress::~PS_AdafruitBMP280_TempPress() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_AdafruitBMP280_TempPress::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_AdafruitBMP280_TempPress::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_AdafruitBMP280_TempPress::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //initialization routine - get first set of readings and send to ST cloud + void PS_AdafruitBMP280_TempPress::init() + { + char buf[5]; + sprintf(buf, "%02X", m_nAddress); + + bool status = bmp.begin(m_nAddress); + if (st::PollingSensor::debug) + { + if (!status) { + Serial.println(); + Serial.print("Error: Could not find a valid BMP280 sensor at address 0x"); + Serial.print(buf); + Serial.println(", check wiring and address setting in sketch!"); + Serial.println(); + delay(3000); + } + } + + getData(); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_AdafruitBMP280_TempPress::getData() + { + + //Temperature + if (m_fTemperatureSensorValue == -1.0) + { + Serial.println("First time through Temperature"); + //first time through, no filtering + if (m_In_C == false) + { + m_fTemperatureSensorValue = (bmp.readTemperature() * 1.8) + 32.0; //Scale from Celsius to Farenheit + } + else + { + m_fTemperatureSensorValue = bmp.readTemperature(); + } + } + else + { + if (m_In_C == false) + { + m_fTemperatureSensorValue = (m_fFilterConstant * ((bmp.readTemperature() * 1.8) + 32.0)) + (1 - m_fFilterConstant) * m_fTemperatureSensorValue; + } + else + { + m_fTemperatureSensorValue = (m_fFilterConstant * bmp.readTemperature()) + (1 - m_fFilterConstant) * m_fTemperatureSensorValue; + } + + } + + //Pressure + if (m_fPressureSensorValue == -1.0) + { + Serial.println("First time through Pressure"); + m_fPressureSensorValue = (bmp.readPressure() / 100.0F); //first time through, no filtering + } + else + { + m_fPressureSensorValue = (m_fFilterConstant * (bmp.readPressure() / 100.0F)) + (1 - m_fFilterConstant) * m_fPressureSensorValue; + } + + Everything::sendSmartString(m_strTemperature + " " + String(m_fTemperatureSensorValue)); + Everything::sendSmartString(m_strPressure + " " + String(m_fPressureSensorValue)); + + } + +} \ No newline at end of file diff --git a/lib/ST_Anything_AdafruitBMP280_TempPress/PS_AdafruitBMP280_TempPress.h b/lib/ST_Anything_AdafruitBMP280_TempPress/PS_AdafruitBMP280_TempPress.h new file mode 100644 index 0000000..a06c8a8 --- /dev/null +++ b/lib/ST_Anything_AdafruitBMP280_TempPress/PS_AdafruitBMP280_TempPress.h @@ -0,0 +1,84 @@ +//****************************************************************************************** +// File: PS_AdafruitBMP280_TempPress.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_AdafruitBMP280_TempPress is a class which implements the "Temperature Measurement" +// and "PressureMewasurement" device capabilities. +// It inherits from the st::PollingSensor class. The current version uses I2C to measure the +// temperature and pressure from a BMP280 series sensor using the Adafruit_BMP280 library. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitBMP280_TempPress sensor2("BMP280_1", 60, 0, "temperature1", "pressure1", false, 100, 0x77); +// +// st::PS_AdafruitBMP280_TempPress() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must be unique, but is not used for data transfer for this device +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - String strTemp - REQUIRED - name of temperature sensor to send to ST Cloud (e.g."temperature1") +// - String strPressure - REQUIRED - name of pressure sensor to send to ST Cloud (e.g. "pressure1") +// - bool In_C - OPTIONAL - true = Report Celsius, false = Report Farenheit (Farentheit is the default) +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// - int address - OPTIONAL - I2C address of the sensor (defaults to 0x77 for the BMP280) +// +// Filtering/Averaging +// +// Filtering the value sent to ST is performed per the following equation +// +// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue) +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2018-07-01 Dan & Daniel Original Creation +// +//****************************************************************************************** + +#ifndef ST_PS_AdafruitBMP280_TempPress_H +#define ST_PS_AdafruitBMP280_TempPress_H + +#include "PollingSensor.h" +#include + +namespace st +{ + class PS_AdafruitBMP280_TempPress: public PollingSensor + { + private: + int m_nAddress; //I2C Address of the sensor + float m_fTemperatureSensorValue;//current Temperature value + float m_fPressureSensorValue; //current Pressure Value + Adafruit_BMP280 bmp; //I2C BMP280 library object + String m_strTemperature; //name of temparature sensor to use when transferring data to ST Cloud / Hubitat + String m_strPressure; //name of pressure sensor to use when transferring data to ST Cloud / Hubitat + bool m_In_C; //Return temp in C (true or false) + float m_fFilterConstant; //Filter constant % as floating point from 0.00 to 1.00 + + public: + //constructor - called in your sketch's global variable declaration section + PS_AdafruitBMP280_TempPress(const __FlashStringHelper *name, unsigned int interval, int offset, String strTemp = "temperature1", String strPressure = "pressure1", bool In_C = false, byte filterConstant = 100, int address = 0x77); + + //destructor + virtual ~PS_AdafruitBMP280_TempPress(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline float getTemperatureSensorValue() const { return m_fTemperatureSensorValue; } + inline float getPressureSensorValue() const { return m_fPressureSensorValue; } + }; +} +#endif diff --git a/lib/ST_Anything_AdafruitSHT31_TempHumid/PS_AdafruitSHT31_TempHumid.cpp b/lib/ST_Anything_AdafruitSHT31_TempHumid/PS_AdafruitSHT31_TempHumid.cpp new file mode 100644 index 0000000..eada032 --- /dev/null +++ b/lib/ST_Anything_AdafruitSHT31_TempHumid/PS_AdafruitSHT31_TempHumid.cpp @@ -0,0 +1,173 @@ +//****************************************************************************************** +// File: PS_AdafruitSHT31_TempHumid.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_AdafruitSHT31_TempHumid is a class which implements the "Temperature Measurement" +// and "Relative Humidity Measurement" device capabilities. +// It inherits from the st::PollingSensor class. The current version uses I2C to measure the +// temperature and humidity from an SHT31 series sensor using the Adafruit_SHT31 library. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitSHT31_TempHumid sensor1(F("SHT31_1)", 60, 0, "temperature1", "humidity1", false, 100, 0x44); +// +// st::PS_AdafruitSHT31_TempHumid() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must be unique, but is not used for data transfer for this device +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - String strTemp - REQUIRED - name of temperature sensor to send to ST Cloud (e.g."temperature1") +// - String strHumid - REQUIRED - name of humidity sensor to send to ST Cloud (e.g. "humidity1") +// - bool In_C - OPTIONAL - true = Report Celsius, false = Report Farenheit (Farentheit is the default) +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// - int address - OPTIONAL - I2C address of the sensor (defaults to 0x44 for the SHT31) +// +// Filtering/Averaging +// +// Filtering the value sent to ST is performed per the following equation +// +// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue) +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2019-03-24 Dan Ogorchock Original Creation +// +//****************************************************************************************** + +#include "PS_AdafruitSHT31_TempHumid.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + PS_AdafruitSHT31_TempHumid::PS_AdafruitSHT31_TempHumid(const __FlashStringHelper *name, unsigned int interval, int offset, String strTemp, String strHumid, bool In_C, byte filterConstant, int address) : + PollingSensor(name, interval, offset), + SHT31(), + m_fTemperatureSensorValue(-1.0), + m_fHumiditySensorValue(-1.0), + m_strTemperature(strTemp), + m_strHumidity(strHumid), + m_In_C(In_C), + m_nAddress(address) + { + //check for upper and lower limit and adjust accordingly + if ((filterConstant <= 0) || (filterConstant >= 100)) + { + m_fFilterConstant = 1.0; + } + else if (filterConstant <= 5) + { + m_fFilterConstant = 0.05; + } + else + { + m_fFilterConstant = float(filterConstant) / 100; + } + + } + + //destructor + PS_AdafruitSHT31_TempHumid::~PS_AdafruitSHT31_TempHumid() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_AdafruitSHT31_TempHumid::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_AdafruitSHT31_TempHumid::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_AdafruitSHT31_TempHumid::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //initialization routine - get first set of readings and send to ST cloud + void PS_AdafruitSHT31_TempHumid::init() + { + bool status = SHT31.begin(m_nAddress); + if (st::PollingSensor::debug) + { + if (!status) { + Serial.println(); + Serial.println("Could not find a valid SHT31 sensor, check wiring!"); + Serial.println(); + delay(3000); + } + } + + getData(); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_AdafruitSHT31_TempHumid::getData() + { + + //Humidity + if (m_fHumiditySensorValue == -1.0) + { + Serial.println("First time through Humidity"); + m_fHumiditySensorValue = SHT31.readHumidity(); //first time through, no filtering + } + else + { + m_fHumiditySensorValue = (m_fFilterConstant * SHT31.readHumidity()) + (1 - m_fFilterConstant) * m_fHumiditySensorValue; + } + + //Temperature + if (m_fTemperatureSensorValue == -1.0) + { + Serial.println("First time through Temperature"); + //first time through, no filtering + if (m_In_C == false) + { + m_fTemperatureSensorValue = (SHT31.readTemperature() * 1.8) + 32.0; //Scale from Celsius to Farenheit + } + else + { + m_fTemperatureSensorValue = SHT31.readTemperature(); + } + } + else + { + if (m_In_C == false) + { + m_fTemperatureSensorValue = (m_fFilterConstant * ((SHT31.readTemperature() * 1.8) + 32.0)) + (1 - m_fFilterConstant) * m_fTemperatureSensorValue; + } + else + { + m_fTemperatureSensorValue = (m_fFilterConstant * SHT31.readTemperature()) + (1 - m_fFilterConstant) * m_fTemperatureSensorValue; + } + + } + + Everything::sendSmartString(m_strTemperature + " " + String(m_fTemperatureSensorValue)); + Everything::sendSmartString(m_strHumidity + " " + String(m_fHumiditySensorValue)); + + } + +} \ No newline at end of file diff --git a/lib/ST_Anything_AdafruitSHT31_TempHumid/PS_AdafruitSHT31_TempHumid.h b/lib/ST_Anything_AdafruitSHT31_TempHumid/PS_AdafruitSHT31_TempHumid.h new file mode 100644 index 0000000..4a2f4ab --- /dev/null +++ b/lib/ST_Anything_AdafruitSHT31_TempHumid/PS_AdafruitSHT31_TempHumid.h @@ -0,0 +1,84 @@ +//****************************************************************************************** +// File: PS_AdafruitSHT31_TempHumid.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_AdafruitSHT31_TempHumid is a class which implements the "Temperature Measurement" +// and "Relative Humidity Measurement" device capabilities. +// It inherits from the st::PollingSensor class. The current version uses I2C to measure the +// temperature and humidity from an SHT31 series sensor using the Adafruit_SHT31 library. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitSHT31_TempHumid sensor1(F("SHT31_1)", 60, 0, "temperature1", "humidity1", false, 100, 0x44); +// +// st::PS_AdafruitSHT31_TempHumid() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must be unique, but is not used for data transfer for this device +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - String strTemp - REQUIRED - name of temperature sensor to send to ST Cloud (e.g."temperature1") +// - String strHumid - REQUIRED - name of humidity sensor to send to ST Cloud (e.g. "humidity1") +// - bool In_C - OPTIONAL - true = Report Celsius, false = Report Farenheit (Farentheit is the default) +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// - int address - OPTIONAL - I2C address of the sensor (defaults to 0x44 for the SHT31) +// +// Filtering/Averaging +// +// Filtering the value sent to ST is performed per the following equation +// +// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue) +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2019-03-24 Dan Ogorchock Original Creation +// +//****************************************************************************************** + +#ifndef ST_PS_AdafruitSHT31_TempHumid_H +#define ST_PS_AdafruitSHT31_TempHumid_H + +#include "PollingSensor.h" +#include + +namespace st +{ + class PS_AdafruitSHT31_TempHumid: public PollingSensor + { + private: + int m_nAddress; //I2C Address of the sensor + float m_fTemperatureSensorValue;//current Temperature value + float m_fHumiditySensorValue; //current Humidity Value + Adafruit_SHT31 SHT31; //I2C SHT31 library object + String m_strTemperature; //name of temparature sensor to use when transferring data to ST Cloud / Hubitat + String m_strHumidity; //name of humidity sensor to use when transferring data to ST Cloud / Hubitat + bool m_In_C; //Return temp in C (true or false) + float m_fFilterConstant; //Filter constant % as floating point from 0.00 to 1.00 + + public: + //constructor - called in your sketch's global variable declaration section + PS_AdafruitSHT31_TempHumid(const __FlashStringHelper *name, unsigned int interval, int offset, String strTemp = "temperature1", String strHumid = "humidity1", bool In_C = false, byte filterConstant = 100, int address = 0x44); + + //destructor + virtual ~PS_AdafruitSHT31_TempHumid(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline float getTemperatureSensorValue() const { return m_fTemperatureSensorValue; } + inline float getHumiditySensorValue() const { return m_fHumiditySensorValue; } + }; +} +#endif diff --git a/lib/ST_Anything_AdafruitTCS34725_Illum_Color/PS_AdafruitTCS34725_Illum_Color.cpp b/lib/ST_Anything_AdafruitTCS34725_Illum_Color/PS_AdafruitTCS34725_Illum_Color.cpp new file mode 100644 index 0000000..58c5c7b --- /dev/null +++ b/lib/ST_Anything_AdafruitTCS34725_Illum_Color/PS_AdafruitTCS34725_Illum_Color.cpp @@ -0,0 +1,132 @@ +//****************************************************************************************** +// File: PS_AdafruitTCS34725_Illum_Color.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_AdafruitTCS34725_Illum_Color is a class which implements the SmartThings "Illuminance Measurement" device capability. +// It inherits from the st::PollingSensor class. It uses I2C communication to measure the RGB Illuminace from a TCS34725 sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitTCS34725_Illum_Color sensor1(F("illuminancergb1"), 60, 0); +// +// st::PS_AdafruitTCS34725_Illum_Color() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - tcs34725IntegrationTime_t integrationTime - OPTIONAL - defaults to TCS34725_INTEGRATIONTIME_154MS +// - tcs34725Gain_t gain - OPTIONAL - defaults to TCS34725_GAIN_4X +// +// Valid Integration Time Values: +// TCS34725_INTEGRATIONTIME_2_4MS = 0xFF, /**< 2.4ms - 1 cycle - Max Count: 1024 */ +// TCS34725_INTEGRATIONTIME_24MS = 0xF6, /**< 24ms - 10 cycles - Max Count: 10240 */ +// TCS34725_INTEGRATIONTIME_50MS = 0xEB, /**< 50ms - 20 cycles - Max Count: 20480 */ +// TCS34725_INTEGRATIONTIME_101MS = 0xD5, /**< 101ms - 42 cycles - Max Count: 43008 */ +// TCS34725_INTEGRATIONTIME_154MS = 0xC0, /**< 154ms - 64 cycles - Max Count: 65535 */ +// TCS34725_INTEGRATIONTIME_700MS = 0x00 /**< 700ms - 256 cycles - Max Count: 65535 */ +// +// Valid Gain Values: +// TCS34725_GAIN_1X = 0x00, /**< No gain */ +// TCS34725_GAIN_4X = 0x01, /**< 4x gain */ +// TCS34725_GAIN_16X = 0x02, /**< 16x gain */ +// TCS34725_GAIN_60X = 0x03 /**< 60x gain */ + +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2017-09-07 Allan (vseven) Modified original PS_Illuminance library for use with the Adafruit TCS34725 sensor +// 2017-12-29 Allan (vseven) Fixed bug with improper init() definition per Dans guidance +// 2018-07-01 Dan Ogorchock Cleaned up the design, added ability to adjust configuration, and fixed the comments section +// +// +//****************************************************************************************** + +#include "PS_AdafruitTCS34725_Illum_Color.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + +//public + //constructor - called in your sketch's global variable declaration section + PS_AdafruitTCS34725_Illum_Color::PS_AdafruitTCS34725_Illum_Color(const __FlashStringHelper *name, unsigned int interval, int offset, tcs34725IntegrationTime_t integrationTime, tcs34725Gain_t gain) : + PollingSensor(name, interval, offset), + tcs(integrationTime, gain) + { + + } + + //destructor + PS_AdafruitTCS34725_Illum_Color::~PS_AdafruitTCS34725_Illum_Color() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_AdafruitTCS34725_Illum_Color::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_AdafruitTCS34725_Illum_Color::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_AdafruitTCS34725_Illum_Color::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + void PS_AdafruitTCS34725_Illum_Color::init() { + Serial.println("Initializing the TCS34725 sensor..."); + if (tcs.begin()) { + Serial.println("Found sensor. tcs.begin = true"); + } + else { + Serial.println("No TCS34725 found... check your connections"); + } + + delay(1000); //give sensor time to get its first data sample ready to be read + getData(); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_AdafruitTCS34725_Illum_Color::getData() + { + tcs.getRawData(&m_nred, &m_ngreen, &m_nblue, &m_nclear); + m_ncolorTemp = tcs.calculateColorTemperature(m_nred, m_ngreen, m_nblue); + m_nlux = tcs.calculateLux(m_nred, m_ngreen, m_nblue); + + //Serial.print("Color Temp: "); Serial.print(m_ncolorTemp, DEC); Serial.print(" K - "); + //Serial.print("Lux: "); Serial.print(m_nlux, DEC); Serial.print(" - "); + //Serial.print("R: "); Serial.print(m_nred, DEC); Serial.print(" "); + //Serial.print("G: "); Serial.print(m_ngreen, DEC); Serial.print(" "); + //Serial.print("B: "); Serial.print(m_nblue, DEC); Serial.print(" "); + //Serial.print("C: "); Serial.print(m_nclear, DEC); Serial.print(" "); + //Serial.println(" "); + + String strSensorValue = String(m_nlux, DEC) + ':' + String(m_ncolorTemp, DEC) + ':' + String(m_nred, DEC) + ':' + String(m_ngreen, DEC) + ':' + String(m_nblue, DEC) + ':' + String(m_nclear, DEC); + + //Send data to SmartThings/Hubitat + Everything::sendSmartString(getName() + " " + strSensorValue); + + } + +} diff --git a/lib/ST_Anything_AdafruitTCS34725_Illum_Color/PS_AdafruitTCS34725_Illum_Color.h b/lib/ST_Anything_AdafruitTCS34725_Illum_Color/PS_AdafruitTCS34725_Illum_Color.h new file mode 100644 index 0000000..9659dba --- /dev/null +++ b/lib/ST_Anything_AdafruitTCS34725_Illum_Color/PS_AdafruitTCS34725_Illum_Color.h @@ -0,0 +1,92 @@ +//****************************************************************************************** +// File: PS_AdafruitTCS34725_Illum_Color.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_AdafruitTCS34725_Illum_Color is a class which implements the SmartThings "Illuminance Measurement" device capability. +// It inherits from the st::PollingSensor class. It uses I2C communication to measure the RGB Illuminace from a TCS34725 sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitTCS34725_Illum_Color sensor1(F("illuminancergb1"), 60, 0); +// +// st::PS_AdafruitTCS34725_Illum_Color() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - tcs34725IntegrationTime_t integrationTime - OPTIONAL - defaults to TCS34725_INTEGRATIONTIME_154MS +// - tcs34725Gain_t gain - OPTIONAL - defaults to TCS34725_GAIN_4X +// +// Valid Integration Time Values: +// TCS34725_INTEGRATIONTIME_2_4MS = 0xFF, /**< 2.4ms - 1 cycle - Max Count: 1024 */ +// TCS34725_INTEGRATIONTIME_24MS = 0xF6, /**< 24ms - 10 cycles - Max Count: 10240 */ +// TCS34725_INTEGRATIONTIME_50MS = 0xEB, /**< 50ms - 20 cycles - Max Count: 20480 */ +// TCS34725_INTEGRATIONTIME_101MS = 0xD5, /**< 101ms - 42 cycles - Max Count: 43008 */ +// TCS34725_INTEGRATIONTIME_154MS = 0xC0, /**< 154ms - 64 cycles - Max Count: 65535 */ +// TCS34725_INTEGRATIONTIME_700MS = 0x00 /**< 700ms - 256 cycles - Max Count: 65535 */ +// +// Valid Gain Values: +// TCS34725_GAIN_1X = 0x00, /**< No gain */ +// TCS34725_GAIN_4X = 0x01, /**< 4x gain */ +// TCS34725_GAIN_16X = 0x02, /**< 16x gain */ +// TCS34725_GAIN_60X = 0x03 /**< 60x gain */ + +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2017-09-07 Allan (vseven) Modified original PS_Illuminance library for use with the Adafruit TCS34725 sensor +// 2017-12-29 Allan (vseven) Fixed bug with improper init() definition per Dans guidance +// 2018-07-01 Dan Ogorchock Cleaned up the design, added ability to adjust configuration, and fixed the comments section +// +// +//****************************************************************************************** + +#ifndef ST_PS_AdafruitTCS34725_Illum_Color_H +#define ST_PS_AdafruitTCS34725_Illum_Color_H + +#include "PollingSensor.h" +#include "Adafruit_TCS34725.h" + +namespace st +{ + class PS_AdafruitTCS34725_Illum_Color: public PollingSensor + { + private: + Adafruit_TCS34725 tcs; //Adafruit TCS34725 object + uint16_t m_nlux; //lux + uint16_t m_ncolorTemp; //color temperature + uint16_t m_nred; //red value + uint16_t m_ngreen; //green value + uint16_t m_nblue; //blue value + uint16_t m_nclear; //clear value + + public: + //constructor - called in your sketch's global variable declaration section + PS_AdafruitTCS34725_Illum_Color(const __FlashStringHelper *name, unsigned int interval, int offset, tcs34725IntegrationTime_t integrationTime = TCS34725_INTEGRATIONTIME_154MS, tcs34725Gain_t gain = TCS34725_GAIN_4X); + + //destructor + virtual ~PS_AdafruitTCS34725_Illum_Color(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + + //sets + + }; +} +#endif diff --git a/lib/ST_Anything_AdafruitTSL2561_Illuminance/PS_AdafruitTSL2561_Illuminance.cpp b/lib/ST_Anything_AdafruitTSL2561_Illuminance/PS_AdafruitTSL2561_Illuminance.cpp new file mode 100644 index 0000000..5080bb7 --- /dev/null +++ b/lib/ST_Anything_AdafruitTSL2561_Illuminance/PS_AdafruitTSL2561_Illuminance.cpp @@ -0,0 +1,133 @@ +//****************************************************************************************** +// File: PS_AdafruitTSL2561_Illuminance.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_AdafruitTSL2561_Illuminance is a class which implements the SmartThings "Illuminance Measurement" device capability. +// It inherits from the st::PollingSensor class. It uses I2C communication to measure the Illuminace from a TSL2561 sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitTSL2561_Illuminance sensor1(F("illuminance1"), 60, 0); (simple, uses defaults) +// For Example: st::PS_AdafruitTSL2561_Illuminance sensor1(F("illuminance1"), 60, 0, TSL2561_ADDR_FLOAT, TSL2561_INTEGRATIONTIME_13MS, TSL2561_GAIN_1X); (full user control of settings) +// +// st::PS_AdafruitTSL2561_Illuminance() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - uint8_t addr -OPTIONAL - defaults to TSL2561_ADDR_FLOAT +// - tsl2561IntegrationTime_t integrationTime - OPTIONAL - defaults to TSL2561_INTEGRATIONTIME_13MS +// - tsl2561Gain_t gain - OPTIONAL - defaults to TSL2561_GAIN_1X +// +// +// I2C address options +// TSL2561_ADDR_LOW (0x29) ///< Default address (pin pulled low) +// TSL2561_ADDR_FLOAT (0x39) ///< Default address (pin left floating) +// TSL2561_ADDR_HIGH (0x49) ///< Default address (pin pulled high) +// +// Valid Integration Time Values: +// TSL2561_INTEGRATIONTIME_13MS = 0x00, // 13.7ms +// TSL2561_INTEGRATIONTIME_101MS = 0x01, // 101ms +// TSL2561_INTEGRATIONTIME_402MS = 0x02 // 402ms +// +// Valid Gain Values: +// TSL2561_GAIN_1X = 0x00, // No gain +// TSL2561_GAIN_16X = 0x10 // 16x gain +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2018-07-02 Dan & Daniel Original Creation +// +// +//****************************************************************************************** + + +#include "PS_AdafruitTSL2561_Illuminance.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + +//public + //constructor - called in your sketch's global variable declaration section + PS_AdafruitTSL2561_Illuminance::PS_AdafruitTSL2561_Illuminance(const __FlashStringHelper *name, unsigned int interval, int offset, uint8_t addr, tsl2561IntegrationTime_t integrationTime, tsl2561Gain_t gain) : + PollingSensor(name, interval, offset), + tsl(addr) + { + tsl.setGain(gain); + tsl.setIntegrationTime(integrationTime); + } + + //destructor + PS_AdafruitTSL2561_Illuminance::~PS_AdafruitTSL2561_Illuminance() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_AdafruitTSL2561_Illuminance::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_AdafruitTSL2561_Illuminance::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_AdafruitTSL2561_Illuminance::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + void PS_AdafruitTSL2561_Illuminance::init() { + Serial.println("Initializing the TSL2561 sensor..."); + if (tsl.begin()) { + Serial.println("Found TSL2561 sensor."); + } + else { + Serial.println("No TSL2561 found... check your wiring and address"); + } + getData(); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_AdafruitTSL2561_Illuminance::getData() + { + /* Get a new sensor event */ + sensors_event_t event; + tsl.getEvent(&event); + //Serial.println(event.light); + + /* Display the results (light is measured in lux) */ + if ((event.light >= 0) && (event.light <= 65535)) + { + m_nlux = event.light; + //send data to SmartThings/Hubitat + Everything::sendSmartString(getName() + " " + String(m_nlux)); + } + else + { + /* If event.light = 0 lux the sensor is probably saturated + and no reliable data could be generated! */ + Serial.println("TSL2561 Sensor overload"); + } + + } + +} diff --git a/lib/ST_Anything_AdafruitTSL2561_Illuminance/PS_AdafruitTSL2561_Illuminance.h b/lib/ST_Anything_AdafruitTSL2561_Illuminance/PS_AdafruitTSL2561_Illuminance.h new file mode 100644 index 0000000..49dd45e --- /dev/null +++ b/lib/ST_Anything_AdafruitTSL2561_Illuminance/PS_AdafruitTSL2561_Illuminance.h @@ -0,0 +1,86 @@ +//****************************************************************************************** +// File: PS_AdafruitTSL2561_Illuminance.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_AdafruitTSL2561_Illuminance is a class which implements the SmartThings "Illuminance Measurement" device capability. +// It inherits from the st::PollingSensor class. It uses I2C communication to measure the Illuminace from a TSL2561 sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitTSL2561_Illuminance sensor1(F("illuminance1"), 60, 0); (simple, uses defaults) +// For Example: st::PS_AdafruitTSL2561_Illuminance sensor1(F("illuminance1"), 60, 0, TSL2561_ADDR_FLOAT, TSL2561_INTEGRATIONTIME_13MS, TSL2561_GAIN_1X); (full user control of settings) +// +// st::PS_AdafruitTSL2561_Illuminance() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - uint8_t addr -OPTIONAL - defaults to TSL2561_ADDR_FLOAT +// - tsl2561IntegrationTime_t integrationTime - OPTIONAL - defaults to TSL2561_INTEGRATIONTIME_13MS +// - tsl2561Gain_t gain - OPTIONAL - defaults to TSL2561_GAIN_1X +// +// +// I2C address options +// TSL2561_ADDR_LOW (0x29) ///< Default address (pin pulled low) +// TSL2561_ADDR_FLOAT (0x39) ///< Default address (pin left floating) +// TSL2561_ADDR_HIGH (0x49) ///< Default address (pin pulled high) +// +// Valid Integration Time Values: +// TSL2561_INTEGRATIONTIME_13MS = 0x00, // 13.7ms +// TSL2561_INTEGRATIONTIME_101MS = 0x01, // 101ms +// TSL2561_INTEGRATIONTIME_402MS = 0x02 // 402ms +// +// Valid Gain Values: +// TSL2561_GAIN_1X = 0x00, // No gain +// TSL2561_GAIN_16X = 0x10 // 16x gain +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2018-07-02 Dan & Daniel Original Creation +// +// +//****************************************************************************************** + +#ifndef ST_PS_AdafruitTSL2561_Illuminance_H +#define ST_PS_AdafruitTSL2561_Illuminance_H + +#include "PollingSensor.h" +#include "Adafruit_TSL2561_U.h" + +namespace st +{ + class PS_AdafruitTSL2561_Illuminance: public PollingSensor + { + private: + Adafruit_TSL2561_Unified tsl; //Adafruit TSL2561 object + uint16_t m_nlux; //lux + + public: + //constructor - called in your sketch's global variable declaration section + PS_AdafruitTSL2561_Illuminance(const __FlashStringHelper *name, unsigned int interval, int offset, uint8_t addr = TSL2561_ADDR_FLOAT, tsl2561IntegrationTime_t integrationTime = TSL2561_INTEGRATIONTIME_13MS, tsl2561Gain_t gain = TSL2561_GAIN_1X); + + //destructor + virtual ~PS_AdafruitTSL2561_Illuminance(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + + //sets + + }; +} +#endif diff --git a/lib/ST_Anything_AdafruitThermocouple/PS_AdafruitThermocouple.cpp b/lib/ST_Anything_AdafruitThermocouple/PS_AdafruitThermocouple.cpp new file mode 100644 index 0000000..af4489f --- /dev/null +++ b/lib/ST_Anything_AdafruitThermocouple/PS_AdafruitThermocouple.cpp @@ -0,0 +1,127 @@ +//****************************************************************************************** +// File: PS_AdafruitThermocouple.cpp +// Authors: Dan G Ogorchock +// +// Summary: PS_AdafruitThermocouple is a class which implements the SmartThings "Temperature Measurement" +// device capability. +// It inherits from the st::PollingSensor class. The current version uses a digital input to measure the +// temperature Adafruit MAX31855 series thermocouple sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitThermocouple sensor1(F("temperature1"), 120, 3, PIN_SCLK, PIN_CS, PIN_MISO); +// +// st::PS_TemperatureHumidity() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - int8_t pinSCLK - REQUIRED - the Arduino Pin to be used as the MAX31855 SCLK +// - int8_t pinCS - REQUIRED - the Arduino Pin to be used as the MAX31855 CS +// - int8_t pinMISO - REQUIRED - the Arduino Pin to be used as the MAX31855 MISO +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-03-24 Dan Ogorchock Original Creation +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2019-06-24 Dan Ogorchock Improved false reading handling +// +// +//****************************************************************************************** + +#include "PS_AdafruitThermocouple.h" + +#include "Constants.h" +#include "Everything.h" +#include +#include + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + PS_AdafruitThermocouple::PS_AdafruitThermocouple(const __FlashStringHelper *name, unsigned int interval, int offset, int8_t pinSCLK, int8_t pinCS, int8_t pinMISO): + PollingSensor(name, interval, offset), + m_dblTemperatureSensorValue(0.0), + m_Adafruit_MAX31855(Adafruit_MAX31855(pinSCLK, pinCS, pinMISO)) + { + + } + + //destructor + PS_AdafruitThermocouple::~PS_AdafruitThermocouple() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_AdafruitThermocouple::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_AdafruitThermocouple::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_AdafruitThermocouple::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //initialization routine - get first set of readings and send to ST cloud + void PS_AdafruitThermocouple::init() + { + getData(); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_AdafruitThermocouple::getData() + { + double tempTemperature; + double totalTemperature = 0.0; + int numGoodValues = 0; + + for (int i = 1; i <= 3; i++) { + tempTemperature = m_Adafruit_MAX31855.readFarenheit(); + if (isnan(tempTemperature)) + { + if (st::PollingSensor::debug) { + Serial.println(F("PS_AdafruitThermocouple:: Error Reading Thermocouple.")); + } + } + else + { + totalTemperature = totalTemperature + tempTemperature; + numGoodValues++; + } + } + + if (numGoodValues > 0) { + m_dblTemperatureSensorValue = totalTemperature / numGoodValues; + Everything::sendSmartString(getName() + " " + String(int(m_dblTemperatureSensorValue))); + } + else + { + Serial.println(F("PS_AdafruitThermocouple:: Error Reading Thermocouple multiple times. No good value measured this cycle.")); + } + + } + +} \ No newline at end of file diff --git a/lib/ST_Anything_AdafruitThermocouple/PS_AdafruitThermocouple.h b/lib/ST_Anything_AdafruitThermocouple/PS_AdafruitThermocouple.h new file mode 100644 index 0000000..d56a8d6 --- /dev/null +++ b/lib/ST_Anything_AdafruitThermocouple/PS_AdafruitThermocouple.h @@ -0,0 +1,79 @@ +//****************************************************************************************** +// File: PS_AdafruitThermocouple.h +// Authors: Dan G Ogorchock +// +// Summary: PS_AdafruitThermocouple is a class which implements the SmartThings "Temperature Measurement" +// device capability. +// It inherits from the st::PollingSensor class. The current version uses a digital input to measure the +// temperature Adafruit MAX31855 series thermocouple sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitThermocouple sensor1(F("temperature1"), 120, 3, PIN_SCLK, PIN_CS, PIN_MISO); +// +// st::PS_TemperatureHumidity() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - int8_t pinSCLK - REQUIRED - the Arduino Pin to be used as the MAX31855 SCLK +// - int8_t pinCS - REQUIRED - the Arduino Pin to be used as the MAX31855 CS +// - int8_t pinMISO - REQUIRED - the Arduino Pin to be used as the MAX31855 MISO +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-03-24 Dan Ogorchock Original Creation +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// +// +//****************************************************************************************** + +#ifndef ST_PS_ADAFRUITTHERMOCOUPLE_H +#define ST_PS_ADAFRUITTHERMOCOUPLE_H + +#include "PollingSensor.h" +#include +#include + +namespace st +{ + class PS_AdafruitThermocouple: public PollingSensor + { + private: + double m_dblTemperatureSensorValue; //current Temperature value + Adafruit_MAX31855 m_Adafruit_MAX31855; //Adafruit MAX31855 object + + public: + + //constructor - called in your sketch's global variable declaration section + PS_AdafruitThermocouple(const __FlashStringHelper *name, unsigned int interval, int offset, int8_t pinSCLK, int8_t pinCS, int8_t pinMISO); + + //destructor + virtual ~PS_AdafruitThermocouple(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline int getTemperatureSensorValue() const { return int(m_dblTemperatureSensorValue); } + + //sets + + }; +} + + + +#endif \ No newline at end of file diff --git a/lib/ST_Anything_AdafruitVEML7700_Illuminance/PS_AdafruitVEML7700_Illuminance.cpp b/lib/ST_Anything_AdafruitVEML7700_Illuminance/PS_AdafruitVEML7700_Illuminance.cpp new file mode 100644 index 0000000..02e09b9 --- /dev/null +++ b/lib/ST_Anything_AdafruitVEML7700_Illuminance/PS_AdafruitVEML7700_Illuminance.cpp @@ -0,0 +1,137 @@ +//****************************************************************************************** +// File: PS_AdafruitVEML7700_Illuminance.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_AdafruitVEML7700_Illuminance is a class which implements the SmartThings "Illuminance Measurement" device capability. +// It inherits from the st::PollingSensor class. It uses I2C communication to measure the Illuminace from a VEML7700 sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitVEML7700_Illuminance sensor1(F("illuminance1"), 60, 0); (simple, uses defaults) +// For Example: st::PS_AdafruitVEML7700_Illuminance sensor1(F("illuminance1"), 60, 0, VEML7700_IT_50MS, VEML7700_GAIN_1_8); (full user control of settings) +// +// st::PS_AdafruitVEML7700_Illuminance() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - uint8_t integrationTime - OPTIONAL - defaults to VEML7700_IT_50MS +// - uint8_t gain - OPTIONAL - defaults to VEML7700_GAIN_1_8 +// +// +// I2C address options +// VEML7700_I2CADDR_DEFAULT 0x10 //< Default address +// +// Valid Integration Time Values: +// VEML7700_IT_100MS 0x00 +// VEML7700_IT_200MS 0x01 +// VEML7700_IT_400MS 0x02 +// VEML7700_IT_800MS 0x03 +// VEML7700_IT_50MS 0x08 //< Default integration time +// VEML7700_IT_25MS 0x0C +// +// Valid Gain Values: +// VEML7700_GAIN_1 0x00 +// VEML7700_GAIN_2 0x01 +// VEML7700_GAIN_1_8 0x02 //< Default gain +// VEML7700_GAIN_1_4 0x03 +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2019-09-28 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + + +#include "PS_AdafruitVEML7700_Illuminance.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + +//public + //constructor - called in your sketch's global variable declaration section + PS_AdafruitVEML7700_Illuminance::PS_AdafruitVEML7700_Illuminance(const __FlashStringHelper *name, unsigned int interval, int offset, uint8_t integrationTime, uint8_t gain) : + PollingSensor(name, interval, offset), + veml(), + m_nIntegrationTime(integrationTime), + m_nGain(gain) + { + } + + //destructor + PS_AdafruitVEML7700_Illuminance::~PS_AdafruitVEML7700_Illuminance() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_AdafruitVEML7700_Illuminance::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_AdafruitVEML7700_Illuminance::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_AdafruitVEML7700_Illuminance::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + void PS_AdafruitVEML7700_Illuminance::init() { + Serial.println("Initializing the VEML7700 sensor..."); + if (veml.begin()) { + Serial.println("Found VEML7700 sensor."); + } + else { + Serial.println("No VEML7700 found... check your wiring and address"); + } + + veml.setGain(m_nGain); + veml.setIntegrationTime(m_nIntegrationTime); + delay(100); //slight delay to allow sensor to initialize for accurate first reading + getData(); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_AdafruitVEML7700_Illuminance::getData() + { + /* Get a new sensor data */ + + m_nLux = (long) veml.readLux(); + //Serial.println(m_nLux); + + /* Display the results (light is measured in lux) */ + if ((m_nLux >= 0) && (m_nLux <= 120000)) + { + //send data to SmartThings/Hubitat + Everything::sendSmartString(getName() + " " + String(m_nLux)); + } + else + { + /* No reliable data could be generated! */ + Serial.println("VEML7700 Sensor failure"); + } + + } + +} diff --git a/lib/ST_Anything_AdafruitVEML7700_Illuminance/PS_AdafruitVEML7700_Illuminance.h b/lib/ST_Anything_AdafruitVEML7700_Illuminance/PS_AdafruitVEML7700_Illuminance.h new file mode 100644 index 0000000..926295d --- /dev/null +++ b/lib/ST_Anything_AdafruitVEML7700_Illuminance/PS_AdafruitVEML7700_Illuminance.h @@ -0,0 +1,90 @@ +//****************************************************************************************** +// File: PS_AdafruitVEML7700_Illuminance.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_AdafruitVEML7700_Illuminance is a class which implements the SmartThings "Illuminance Measurement" device capability. +// It inherits from the st::PollingSensor class. It uses I2C communication to measure the Illuminace from a VEML7700 sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_AdafruitVEML7700_Illuminance sensor1(F("illuminance1"), 60, 0); (simple, uses defaults) +// For Example: st::PS_AdafruitVEML7700_Illuminance sensor1(F("illuminance1"), 60, 0, VEML7700_IT_50MS, VEML7700_GAIN_1_8); (full user control of settings) +// +// st::PS_AdafruitVEML7700_Illuminance() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - uint8_t integrationTime - OPTIONAL - defaults to VEML7700_IT_50MS +// - uint8_t gain - OPTIONAL - defaults to VEML7700_GAIN_1_8 +// +// +// I2C address options +// VEML7700_I2CADDR_DEFAULT 0x10 //< Default address +// +// Valid Integration Time Values: +// VEML7700_IT_100MS 0x00 +// VEML7700_IT_200MS 0x01 +// VEML7700_IT_400MS 0x02 +// VEML7700_IT_800MS 0x03 +// VEML7700_IT_50MS 0x08 //< Default integration time +// VEML7700_IT_25MS 0x0C +// +// Valid Gain Values: +// VEML7700_GAIN_1 0x00 +// VEML7700_GAIN_2 0x01 +// VEML7700_GAIN_1_8 0x02 //< Default gain +// VEML7700_GAIN_1_4 0x03 +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2019-09-28 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + +#ifndef ST_PS_AdafruitVEML7700_Illuminance_H +#define ST_PS_AdafruitVEML7700_Illuminance_H + +#include "PollingSensor.h" +#include "Adafruit_VEML7700.h" + +namespace st +{ + class PS_AdafruitVEML7700_Illuminance: public PollingSensor + { + private: + Adafruit_VEML7700 veml; //Adafruit VEML7700 object + uint8_t m_nGain; + uint8_t m_nIntegrationTime; + long m_nLux; //lux + + public: + //constructor - called in your sketch's global variable declaration section + PS_AdafruitVEML7700_Illuminance(const __FlashStringHelper *name, unsigned int interval, int offset, uint8_t integrationTime = VEML7700_IT_50MS, uint8_t gain = VEML7700_GAIN_1_8); + + //destructor + virtual ~PS_AdafruitVEML7700_Illuminance(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + + //sets + + }; +} +#endif diff --git a/lib/ST_Anything_Adafruit_MPR121/PS_Adafruit_MPR121.cpp b/lib/ST_Anything_Adafruit_MPR121/PS_Adafruit_MPR121.cpp new file mode 100644 index 0000000..989e8b6 --- /dev/null +++ b/lib/ST_Anything_Adafruit_MPR121/PS_Adafruit_MPR121.cpp @@ -0,0 +1,175 @@ +//****************************************************************************************** +// File: PS_Adafruit_MPR121.cpp +// Authors: Luca Masera +// +// Summary: PS_Adafruit_MPR121 is a class that inherits from the st::InterruptSensor class. +// +// Create an instance of this class in your sketch's global variable section. +// For Example: st::PS_Adafruit_MPR121 sensor(F("button1"), 5, 0x10, 0x20, 1000); +// +// st::PS_Adafruit_MPR121() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object, should be "touchButtons_Kitchen", "touchButtons_Desk", etc... +// - int8_t activatedButtonId - REQUIRED - the id of the sensor that is used to activate the touching capability +// - uint8_t sensibility5C = 0x10, together with sensibility5D sets the sensibility of the touch sensors +// - uint8_t sensibility5D = 0x20, +// - long reqNumMillisHeld = 1000 - milliseconds thesholdb between "Held" and "Pushed" +// +// Change History: +// +// Date Who What +// 2022-09-23 Luca Masera Corrected bugs within inizialization and check of buttons status +// 2022-09-22 Luca Masera Original creation +// +//****************************************************************************************** + +#include "PS_Adafruit_MPR121.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st { +// private + +// public +// constructor +PS_Adafruit_MPR121::PS_Adafruit_MPR121(const __FlashStringHelper *name, + int8_t activateButtonId, + uint8_t sensibility5C, + uint8_t sensibility5D, + long reqNumMillisHeld) + : InterruptSensor(name, 2, false), // use parent class' constructor + m_sensibility5C(sensibility5C), + m_sensibility5D(sensibility5D), + m_lreqNumMillisHeld(reqNumMillisHeld), + activateButtonId(activateButtonId){} + +// destructor +PS_Adafruit_MPR121::~PS_Adafruit_MPR121() {} + +void PS_Adafruit_MPR121::init() { + // get current status of motion sensor by calling parent class's + // init() routine - no need to duplicate it here! + InterruptSensor::init(); + + Serial.println("Adafruit MPR121 Capacitive Touch sensor"); + + // Default address is 0x5A, if tied to 3.3V its 0x5B + // If tied to SDA its 0x5C and if SCL then 0x5D + if (!cap.begin(m_sensibility5C, m_sensibility5D, 0x5A)) { + Serial.println(F("MPR121 not found, check wiring?")); + + } else { + Serial.println(F("MPR121 found!")); + refresh(); + } +} + +// called periodically by Everything class to ensure ST Cloud is kept up yo +// date. HOWEVER, not useful for the IS_Button. +void PS_Adafruit_MPR121::refresh() { + if (isBlockedStatus) { + isBlockedStatus = false; + Serial.println("Blocked status: trying to perform a soft reset to restart the sensor."); + + this->init(); + } + + // Send 'init' message to allow Parent Driver to set numberOfButtons + // attribute automatically + Everything::sendSmartString(getName() + F(" init")); +} + +void PS_Adafruit_MPR121::update() { // Get the currently touched pads +// get current time +long currentTime = millis(); + +// get current touch array +curr_touched = cap.touched(); + +// had an over current or out of range? +isBlockedStatus = cap.hadOverCurrent(curr_touched) || cap.wentOutOfRange(); + +if (!isBlockedStatus) { + + // A) if not active... + if (!isActive) { + // B) if the touch is to activate the sensor (ACTIVATE_BUTTON)... + if (bitRead(curr_touched, activateButtonId) && !(bitRead(old_touched, activateButtonId))) { + // register activation time and ... + Serial.println(F("activation touched")); + activationStart = currentTime; + + } else if ((bitRead(old_touched, activateButtonId)) && bitRead(old_touched, activateButtonId)) { + // C) if the activation time is bigger than the ACTIVATION_THRESOLD... + if (currentTime - activationStart > _ACTIVATION_THRESOLD) { + // activate the sensor and register active time + Serial.println(F("activated")); + waitingActive = currentTime; + isActive = true; + } + } + + // ... is active + } else { + // D) first check if still active, or at least hold + if ((currentTime - waitingActive > _ACTIVE_TIMEOUT) && !isHold) { + // if not, deactivate the sensor + Serial.println(F("deactivated")); + isActive = false; + + } else { + // is active or hold, check what's going on with the buttons + // for each button (we have 12), check the status of the bit in the touch array (ignore ACTIVATE_BUTTON) + for (uint8_t currentButton = 0; currentButton < 12; currentButton++) { + if (currentButton != activateButtonId) { + // E) if positive and different from the old status then ... + if (bitRead(curr_touched, currentButton) && !(bitRead(old_touched, currentButton))) { + //... is a touch: register the TOUCH and store the touch time (for hold status) + Serial.print("touched: "); + Serial.println(currentButton); + startTouch[currentButton] = currentTime; + waitingActive = currentTime; + Everything::sendSmartStringNow(getName() + String(currentButton) + _PUSHED); + + // F) if positive and equal to the old status then ... + } else if (bitRead(curr_touched, currentButton) && (bitRead(old_touched, currentButton))) { + // ... G) it could be a hold: if the HOLD_THRESOLD has been reached for the current button... + if (!(bitRead(isHold, currentButton)) && (currentTime - startTouch[currentButton] > HOLD_THRESOLD)) { + // ... register the HOLD and store a flag for the button + Serial.print("held: "); + Serial.println(currentButton); + bitSet(isHold, currentButton); + waitingActive = currentTime; + Everything::sendSmartString(getName() + String(currentButton) + _HELD); + } + + // H) if negative and different from the old status then ... + } else if (!(bitRead(curr_touched, currentButton)) && bitRead(old_touched, currentButton)) { + // ... it means that there's no touch anymore + // I) if it was hold... + if (bitRead(isHold, currentButton)) { + // ... reset the flag for the button + Serial.print("stop held: "); + Serial.println(currentButton); + bitClear(isHold, currentButton); + } + // register the RELEASE for the button + Serial.print("released: "); + Serial.println(currentButton); + Everything::sendSmartString(getName() + String(currentButton) + _RELEASED); + } + } + } + } + } + } + + old_touched = curr_touched; +} + + +void PS_Adafruit_MPR121::runInterrupt() {} + +void PS_Adafruit_MPR121::runInterruptEnded() {} + +} // namespace st \ No newline at end of file diff --git a/lib/ST_Anything_Adafruit_MPR121/PS_Adafruit_MPR121.h b/lib/ST_Anything_Adafruit_MPR121/PS_Adafruit_MPR121.h new file mode 100644 index 0000000..48276c1 --- /dev/null +++ b/lib/ST_Anything_Adafruit_MPR121/PS_Adafruit_MPR121.h @@ -0,0 +1,96 @@ +//****************************************************************************************** +// File: PS_Adafruit_MPR121.h +// Authors: Luca Masera +// +// Summary: PS_Adafruit_MPR121 is a class which implements the SmartThings +// "Contact Sensor" device capability. +// It inherits from the st::InterruptSensor class. +// +// Create an instance of this class in your sketch's +// global variable section For Example: +// st::PS_Adafruit_MPR121 sensor(F("touchButtons"), 5); +// +// st::PS_Adafruit_MPR121() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object, should be "touchButtons_Kitchen", "touchButtons_Desk", etc... +// - int8_t activatedButtonId - REQUIRED - the id of the sensor that is used to activate the touching capability +// - uint8_t sensibility5C = 0x10, together with sensibility5D sets the sensibility of the touch sensors +// - uint8_t sensibility5D = 0x20, +// - long reqNumMillisHeld = 1000 - milliseconds thesholdb between "Held" and "Pushed" +// - +//(default = 1000) +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2022-09-22 Luca Masera Original Creation +// +//****************************************************************************************** + +#ifndef ST_PS_ADAFRUIT_MPR121_H +#define ST_PS_ADAFRUIT_MPR121_H + +#include + +#include "InterruptSensor.h" + +namespace st { +class PS_Adafruit_MPR121 : public InterruptSensor { + private: + unsigned long m_lTimeBtnPressed; // time when the digital input went high + unsigned long m_lreqNumMillisHeld; // amount of time required to trigger "held" instead of "pushed" + + uint8_t m_sensibility5C; // couple of values used to set the default sensitivity of the sensors + uint8_t m_sensibility5D; + + bool m_bFirstRun = true; // used to prevent sending inadvertent button + // pushed/held message on startup + bool m_bHeldSent = false; // used to prevent sending multiple 'held' messages + bool isBlockedStatus = false; // ued to inform if the sensor is blocked and needs a reset + + const __FlashStringHelper *_PUSHED = F(" pushed"); + const __FlashStringHelper *_HELD = F(" held"); + const __FlashStringHelper *_RELEASED = F(" released"); + + u_int16_t _ACTIVATION_THRESOLD = 1000; + u_int16_t _ACTIVE_TIMEOUT = 2000; + u_int16_t HOLD_THRESOLD = 800; + boolean isActive = false; + + + int8_t activateButtonId; + uint16_t curr_touched, old_touched, isTouched, isHold; + long currentTime, activationStart, waitingActive, startTouch[12]; + + Adafruit_MPR121 cap = Adafruit_MPR121(); + + public: + // constructor - called in your sketch's global variable declaration section + PS_Adafruit_MPR121(const __FlashStringHelper *name, + int8_t activateButtonId, + uint8_t sensibility5C = 0x10, // defaults to low sensibility for almost touch + uint8_t sensibility5D = 0x20, + long reqNumMillisHeld = 1000); //defaults to 1 second + + // destructor + virtual ~PS_Adafruit_MPR121(); + + // initialization function + virtual void init(); + + // called periodically by Everything class to ensure ST Cloud is kept up to + // date. Not used for IS_Button. + virtual void refresh(); + + // handles what to do when interrupt is triggered + virtual void runInterrupt(); + + // handles what to do when interrupt is ended + virtual void runInterruptEnded(); + + // override update method + virtual void update(); + }; +} // namespace st + +#endif diff --git a/lib/ST_Anything_Adafruit_NeoPixel/EX_NEOPIX.cpp b/lib/ST_Anything_Adafruit_NeoPixel/EX_NEOPIX.cpp new file mode 100644 index 0000000..8b63a50 --- /dev/null +++ b/lib/ST_Anything_Adafruit_NeoPixel/EX_NEOPIX.cpp @@ -0,0 +1,129 @@ +//****************************************************************************************** +// File: EX_NEOPIX.cpp +// Authors: Justin Eltoft based on EX_RGB_Dim by Dan G Ogorchock +// +// Summary: EX_NEOPIX is a class which implements the SmartThings "Color Control", "Switch", and "Switch Level" device capabilities. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_NEOPIX executor1("rgbSwitch1", PIN_NEOPIX); +// +// st::EX_NEOPIX() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin_neopix - REQUIRED - the Arduino Pin to be used as the one wire bus for neopixels +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2020-06-20 Justin Eltoft Original Creation +// +//****************************************************************************************** +#include "EX_NEOPIX.h" +#include + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + void EX_NEOPIX::writeRGBToPins() + { + int subStringR; + int subStringG; + int subStringB; + + if (m_bCurrentState == HIGH) + { + // Our status is on so get the RGB value from the hex + String hexstring = m_sCurrentHEX; + long number = (long) strtol( &hexstring[1], NULL, 16); + // Split them up into r, g, b values + subStringR = number >> 16; + subStringG = number >> 8 & 0xFF; + subStringB = number & 0xFF; + } + else + { + // Status is off so turn off LED + subStringR = 00; + subStringG = 00; + subStringB = 00; + } + + // Write to outputs. Use ledc for ESP32, analogWrite for everything else. + if (st::Executor::debug) { + Serial.print(F("subString R:G:B = ")); + Serial.println(String(subStringR) + ":" + String(subStringG) + ":" + String(subStringB)); + } + + // Any adjustments to the colors can be done here before sending the commands. For example if red is always too bright reduce it: + // subStringR = subStringR * 0.95 + + m_pixel->setPixelColor(0, m_pixel->Color(subStringR, subStringG, subStringB)); + m_pixel->show(); + } + +//public + //constructor + EX_NEOPIX::EX_NEOPIX(const __FlashStringHelper *name, byte pinNeoPix): + Executor(name) + { + setPin(pinNeoPix); + } + + //destructor + EX_NEOPIX::~EX_NEOPIX() + { + + } + + void EX_NEOPIX::init() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + } + + void EX_NEOPIX::beSmart(const String &str) + { + String s=str.substring(str.indexOf(' ')+1); + if (st::Executor::debug) { + Serial.print(F("EX_NEOPIX::beSmart s = ")); + Serial.println(s); + } + if(s==F("on")) + { + m_bCurrentState=HIGH; + } + else if(s==F("off")) + { + m_bCurrentState=LOW; + } + else //must be a set color command + { + s.trim(); + m_sCurrentHEX = s; + } + + writeRGBToPins(); + + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off"))); + } + + void EX_NEOPIX::refresh() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off"))); + } + + void EX_NEOPIX::setPin(byte pin) + { + m_nPinNeoPix = pin; + + m_pixel = new Adafruit_NeoPixel(1, pin, NEO_GRB + NEO_KHZ800); + m_pixel->begin(); + + m_pixel->clear(); + m_pixel->show(); + + } +} diff --git a/lib/ST_Anything_Adafruit_NeoPixel/EX_NEOPIX.h b/lib/ST_Anything_Adafruit_NeoPixel/EX_NEOPIX.h new file mode 100644 index 0000000..704b2d4 --- /dev/null +++ b/lib/ST_Anything_Adafruit_NeoPixel/EX_NEOPIX.h @@ -0,0 +1,67 @@ +//****************************************************************************************** +// File: EX_NEOPIX.cpp +// Authors: Justin Eltoft based on EX_RGB_Dim by Dan G Ogorchock +// +// Summary: EX_NEOPIX is a class which implements the SmartThings "Color Control", "Switch", and "Switch Level" device capabilities. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_NEOPIX executor1("rgbSwitch1", PIN_NEOPIX); +// +// st::EX_NEOPIX() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pin_neopix - REQUIRED - the Arduino Pin to be used as the one wire bus for neopixels +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2020-06-20 Justin Eltoft Original Creation +// +//****************************************************************************************** +#ifndef ST_EX_NEOPIX +#define ST_EX_NEOPIX + +#include +#include "Executor.h" + +namespace st +{ + class EX_NEOPIX: public Executor + { + private: + Adafruit_NeoPixel *m_pixel; + bool m_bCurrentState; //HIGH or LOW + byte m_nPinNeoPix; //Arduino Pin used for Neopixel + String m_sCurrentHEX; //HEX value of color currently set + + void writeRGBToPins(); //function to update the Arduino PWM Output Pins + + public: + //constructor - called in your sketch's global variable declaration section + EX_NEOPIX(const __FlashStringHelper *name, byte pinNeoPix); + + //destructor + virtual ~EX_NEOPIX(); + + //initialization routine + virtual void init(); + + //SmartThings Shield data handler (receives command to turn "on" or "off" the switch along with HEX value for LEDs) + virtual void beSmart(const String &str); + + //called periodically to ensure state of the switch is up to date in the SmartThings Cloud (in case an event is missed) + virtual void refresh(); + + //gets + virtual byte getPin() const { return m_nPinNeoPix; } + + virtual bool getStatus() const { return m_bCurrentState; } //whether the switch is HIGH or LOW + virtual String getHEX() const { return m_sCurrentHEX; } // color value in HEX + + //sets + virtual void setPin(byte pin); + }; +} + +#endif diff --git a/lib/ST_Anything_Adafruit_Si7021_TempHumidity/PS_Adafruit_Si7021_TempHumidity.cpp b/lib/ST_Anything_Adafruit_Si7021_TempHumidity/PS_Adafruit_Si7021_TempHumidity.cpp new file mode 100644 index 0000000..7617512 --- /dev/null +++ b/lib/ST_Anything_Adafruit_Si7021_TempHumidity/PS_Adafruit_Si7021_TempHumidity.cpp @@ -0,0 +1,187 @@ +//****************************************************************************************** +// File: PS_Adafruit_BME280_TemperatureHumidityBarometric.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) & Josh Hill +// +// Summary: PS_Adafruit_Si7021_TempHumidity is a class which implements both the SmartThings "Temperature Measurement" +// and "Relative Humidity Measurement" device capabilities. +// It inherits from the st::PollingSensor class. The current version uses I2C to measure the +// temperature and humidity from an Si7021 sensor. This was tested with a generic Si7021 sensor from AliExpress. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_Adafruit_Si7021_TempHumidity sensor2("temphumid1", 120, 7, "temperature1", "humidity1", false); +// +// st::PS_Adafruit_Si7021_TempHumidity() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - String strTemp - OPTIONAL - name of temperature sensor to send to ST Cloud (defaults to "temperature") +// - String strHumid - OPTIONAL - name of humidity sensor to send to ST Cloud (defaults to "humidity") +// - bool In_C - OPTIONAL - true = Report Celsius, false = Report Farenheit (Farentheit is the default) +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// +// Filtering/Averaging +// +// Filtering the value sent to ST is performed per the following equation +// +// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue) +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-01-17 Dan Ogorchock Added optional temperature and humidity device names in constructor to allow multiple Temp/Humidity sensors +// 2015-01-17 Dan Ogorchock Added optional temperature and humidity device names in constructor to allow multiple Temp/Humidity sensors +// 2015-03-29 Dan Ogorchock Optimized use of the DHT library (made it static) to reduce SRAM memory usage at runtime. +// 2017-06-27 Dan Ogorchock Added optional Celsius reading argument +// 2017-08-17 Dan Ogorchock Added optional filter constant argument and to transmit floating point values to SmartThings +// 2018-03-24 Josh Hill Modified library to use Si7021 over I2C +// +//****************************************************************************************** + +#include "PS_Adafruit_Si7021_TempHumidity.h" + +#include "Constants.h" +#include "Everything.h" +#include "Adafruit_Si7021.h" + + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + PS_Adafruit_Si7021_TempHumidity::PS_Adafruit_Si7021_TempHumidity(const __FlashStringHelper *name, unsigned int interval, int offset, String strTemp, String strHumid, bool In_C, byte filterConstant) : + PollingSensor(name, interval, offset), + m_fTemperatureSensorValue(-1.0), + m_fHumiditySensorValue(-1.0), + m_strTemperature(strTemp), + m_strHumidity(strHumid), + m_In_C(In_C) + { + + //check for upper and lower limit and adjust accordingly + if ((filterConstant <= 0) || (filterConstant >= 100)) + { + m_fFilterConstant = 1.0; + } + else if (filterConstant <= 5) + { + m_fFilterConstant = 0.05; + } + else + { + m_fFilterConstant = float(filterConstant) / 100; + } + + } + + //destructor + PS_Adafruit_Si7021_TempHumidity::~PS_Adafruit_Si7021_TempHumidity() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_Adafruit_Si7021_TempHumidity::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_Adafruit_Si7021_TempHumidity::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_Adafruit_Si7021_TempHumidity::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //initialization routine - get first set of readings and send to ST cloud + void PS_Adafruit_Si7021_TempHumidity::init() + { + delay(1500); //Needed to prevent "Unknown Error" on first read of DHT Sensori (possibly not necessary with Si7021) + + bool status; + status = Si7021Sensor.begin(); + if (!status) { + Serial.println("Could not find a valid Si7021 sensor, check wiring!"); + while (1); + } + + getData(); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_Adafruit_Si7021_TempHumidity::getData() + { + // READ DATA + //Humidity + if (m_fHumiditySensorValue == -1.0) + { + Serial.println("First time through Humidity)"); + m_fHumiditySensorValue = Si7021Sensor.readHumidity(); //first time through, no filtering + } + else + { + m_fHumiditySensorValue = (m_fFilterConstant * Si7021Sensor.readHumidity()) + (1 - m_fFilterConstant) * m_fHumiditySensorValue; + } + + //Temperature + if (m_fTemperatureSensorValue == -1.0) + { + Serial.println("First time through Termperature)"); + //first time through, no filtering + if (m_In_C == false) + { + m_fTemperatureSensorValue = (Si7021Sensor.readTemperature() * 1.8) + 32.0; //Scale from Celsius to Farenheit + } + else + { + m_fTemperatureSensorValue = Si7021Sensor.readTemperature(); + } + } + else + { + if (m_In_C == false) + { + m_fTemperatureSensorValue = (m_fFilterConstant * ((Si7021Sensor.readTemperature() * 1.8) + 32.0)) + (1 - m_fFilterConstant) * m_fTemperatureSensorValue; + } + else + { + m_fTemperatureSensorValue = (m_fFilterConstant * Si7021Sensor.readTemperature()) + (1 - m_fFilterConstant) * m_fTemperatureSensorValue; + } + + } + + + // DISPLAY DATA + //Serial.print(m_nHumiditySensorValue, 1); + //Serial.print(F(",\t\t")); + //Serial.print(m_nTemperatureSensorValue, 1); + //Serial.println(); + + Everything::sendSmartString(m_strTemperature + " " + String(m_fTemperatureSensorValue)); + Everything::sendSmartString(m_strHumidity + " " + String(m_fHumiditySensorValue)); + } + + + //initialize static members + Adafruit_Si7021 PS_Adafruit_Si7021_TempHumidity::Si7021Sensor = Adafruit_Si7021(); + +} diff --git a/lib/ST_Anything_Adafruit_Si7021_TempHumidity/PS_Adafruit_Si7021_TempHumidity.h b/lib/ST_Anything_Adafruit_Si7021_TempHumidity/PS_Adafruit_Si7021_TempHumidity.h new file mode 100644 index 0000000..7aa7a10 --- /dev/null +++ b/lib/ST_Anything_Adafruit_Si7021_TempHumidity/PS_Adafruit_Si7021_TempHumidity.h @@ -0,0 +1,91 @@ +//****************************************************************************************** +// File: PS_Adafruit_Si7021_TempHumidity.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) & Josh Hill +// +// Summary: PS_Adafruit_Si7021_TempHumidity is a class which implements both the SmartThings "Temperature Measurement" +// and "Relative Humidity Measurement" device capabilities. +// It inherits from the st::PollingSensor class. The current version uses I2C to measure the +// temperature and humidity from an Si7021 sensor. This was tested with a generic Si7021 sensor from AliExpress. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_Adafruit_Si7021_TempHumidity sensor2("temphumid1", 120, 7, "temperature1", "humidity1", false); +// +// st::PS_Adafruit_Si7021_TempHumidity() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - String strTemp - OPTIONAL - name of temperature sensor to send to ST Cloud (defaults to "temperature") +// - String strHumid - OPTIONAL - name of humidity sensor to send to ST Cloud (defaults to "humidity") +// - bool In_C - OPTIONAL - true = Report Celsius, false = Report Farenheit (Farentheit is the default) +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// +// Filtering/Averaging +// +// Filtering the value sent to ST is performed per the following equation +// +// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue) +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-01-17 Dan Ogorchock Added optional temperature and humidity device names in constructor to allow multiple Temp/Humidity sensors +// 2015-01-17 Dan Ogorchock Added optional temperature and humidity device names in constructor to allow multiple Temp/Humidity sensors +// 2015-03-29 Dan Ogorchock Optimized use of the DHT library (made it static) to reduce SRAM memory usage at runtime. +// 2017-06-27 Dan Ogorchock Added optional Celsius reading argument +// 2017-08-17 Dan Ogorchock Added optional filter constant argument and to transmit floating point values to SmartThings +// 2018-03-24 Josh Hill Modified library to use Si7021 over I2C +// +//****************************************************************************************** + +#ifndef ST_PS_SI7021_H +#define ST_PS_SI7021_H + +#include "PollingSensor.h" +#include "Adafruit_Si7021.h" + +namespace st +{ + class PS_Adafruit_Si7021_TempHumidity: public PollingSensor + { + private: + float m_fTemperatureSensorValue;//current Temperature value + float m_fHumiditySensorValue; //current Humidity Value + static Adafruit_Si7021 Si7021Sensor; //I2C + + String m_strTemperature; //name of temparature sensor to use when transferring data to ST Cloud + String m_strHumidity; //name of temparature sensor to use when transferring data to ST Cloud + bool m_In_C; //Return temp in C + float m_fFilterConstant; //Filter constant % as floating point from 0.00 to 1.00 + + public: + + //constructor - called in your sketch's global variable declaration section + PS_Adafruit_Si7021_TempHumidity(const __FlashStringHelper *name, unsigned int interval, int offset, String strTemp = "temperature1", String strHumid = "humidity1", bool In_C = false, byte filterConstant = 100); + + //destructor + virtual ~PS_Adafruit_Si7021_TempHumidity(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline float getTemperatureSensorValue() const { return m_fTemperatureSensorValue; } + inline float getHumiditySensorValue() const { return m_fHumiditySensorValue; } + + }; +} +#endif diff --git a/lib/ST_Anything_BH1750_Illuminance/PS_BH1750_Illuminance.cpp b/lib/ST_Anything_BH1750_Illuminance/PS_BH1750_Illuminance.cpp new file mode 100644 index 0000000..aba9fe2 --- /dev/null +++ b/lib/ST_Anything_BH1750_Illuminance/PS_BH1750_Illuminance.cpp @@ -0,0 +1,108 @@ +//****************************************************************************************** +// File: PS_BH1750_Illuminance.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_BH1750_Illuminance is a class which implements the SmartThings "Illuminance Measurement" device capability. +// It inherits from the st::PollingSensor class. It uses I2C communication to measure the Illuminace from a MAX44009 sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_BH1750_Illuminance sensor1(F("illuminance1"), 60, 0); (simple, uses defaults) +// For Example: st::PS_BH1750_Illuminance sensor1(F("illuminance1"), 60, 0, BH1750_ADDR_LOW); (full user control of settings) +// +// st::PS_BH1750_Illuminance() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - uint8_t addr -OPTIONAL - defaults to BH1750_ADDR_LOW +// +// +// I2C address options +// BH1750_ADDR_LOW 0x23 //< Pin A0 pulled Low +// BH1750_ADDR_HIGH 0x5C //< Pin A0 pulled Hi +// +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2018-07-03 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + +#include "PS_BH1750_Illuminance.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + +//public + //constructor - called in your sketch's global variable declaration section + PS_BH1750_Illuminance::PS_BH1750_Illuminance(const __FlashStringHelper *name, unsigned int interval, int offset, uint8_t addr) : + PollingSensor(name, interval, offset), + myLux(addr) + { + + } + + //destructor + PS_BH1750_Illuminance::~PS_BH1750_Illuminance() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_BH1750_Illuminance::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_BH1750_Illuminance::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_BH1750_Illuminance::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + void PS_BH1750_Illuminance::init() { + + //initialize the BH1750 + myLux.begin(); + + //give sensor time to get its first data sample ready to be read + delay(1000); + + //read and transmit initial data from sensor + getData(); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_BH1750_Illuminance::getData() + { + /* Get a new sensor data */ + m_nLux = myLux.readLightLevel(); + + //Send data to SmartThings/Hubitat + Everything::sendSmartString(getName() + " " + String(m_nLux)); + + } + +} diff --git a/lib/ST_Anything_BH1750_Illuminance/PS_BH1750_Illuminance.h b/lib/ST_Anything_BH1750_Illuminance/PS_BH1750_Illuminance.h new file mode 100644 index 0000000..3f0601f --- /dev/null +++ b/lib/ST_Anything_BH1750_Illuminance/PS_BH1750_Illuminance.h @@ -0,0 +1,75 @@ +//****************************************************************************************** +// File: PS_BH1750_Illuminance.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_BH1750_Illuminance is a class which implements the SmartThings "Illuminance Measurement" device capability. +// It inherits from the st::PollingSensor class. It uses I2C communication to measure the Illuminace from a MAX44009 sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_BH1750_Illuminance sensor1(F("illuminance1"), 60, 0); (simple, uses defaults) +// For Example: st::PS_BH1750_Illuminance sensor1(F("illuminance1"), 60, 0, BH1750_ADDR_LOW); (full user control of settings) +// +// st::PS_BH1750_Illuminance() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - uint8_t addr -OPTIONAL - defaults to BH1750_ADDR_LOW +// +// +// I2C address options +// BH1750_ADDR_LOW 0x23 //< Pin A0 pulled Low +// BH1750_ADDR_HIGH 0x5C //< Pin A0 pulled Hi +// +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2018-07-03 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + +#ifndef ST_PS_BH1750_Illuminance_H +#define ST_PS_BH1750_Illuminance_H + +#include "PollingSensor.h" +#include "BH1750.h" + +namespace st +{ + class PS_BH1750_Illuminance: public PollingSensor + { + private: + BH1750 myLux; //BH1750 object + uint16_t m_nLux; //lux + + public: + //constructor - called in your sketch's global variable declaration section + PS_BH1750_Illuminance(const __FlashStringHelper *name, unsigned int interval, int offset, uint8_t addr = BH1750_ADDR_LOW); + + //destructor + virtual ~PS_BH1750_Illuminance(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + + //sets + + }; +} +#endif diff --git a/lib/ST_Anything_DS18B20_Temperature/PS_DS18B20_Temperature.cpp b/lib/ST_Anything_DS18B20_Temperature/PS_DS18B20_Temperature.cpp new file mode 100644 index 0000000..7fa5ccb --- /dev/null +++ b/lib/ST_Anything_DS18B20_Temperature/PS_DS18B20_Temperature.cpp @@ -0,0 +1,165 @@ +//****************************************************************************************** +// File: PS_DS18B20_Temperature.cpp +// Author: Dan G Ogorchock +// +// Summary: PS_DS18B20_Temperature is a class which implements both the SmartThings "Temperature Measurement" capability. +// It inherits from the st::PollingSensor class. The current version uses a digital pin to measure the +// temperature from a Dallas Semiconductor One Wire DS18B20 series sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_DS18B20_Temperature sensor1(F("temperature1"), 120, 0, PIN_TEMPERATURE, false); (for a single sensor) +// st::PS_DS18B20_Temperature sensor1(F("temperature"), 120, 0, PIN_TEMPERATURE, false, 10, 3); (for 3 sensors) +// +// st::PS_DS18B20_Temperature() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - either "temperature1" for a single sensor, or "temperature" for multiple sensors +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used for the One-Wire DS18B20 sensor conenction +// - bool In_C - OPTIONAL - true = Report Celsius, false = Report Farenheit (Farentheit is the default) +// - byte resolution - OPTIONAL - DS18B20 sensor resolution in bits. 9, 10, 11, or 12. Defaults to 10 for decent accuracy and performance +// - byte num_sensors - OPTIONAL - number of OneWire DS18B20 sensors attached to OneWire bus - Defaults to 1 +// - byte sensorStartingNum - OPTIONAL - Starting number for sending temperature sensor data when using multiple sensors on one pin - Defaults to 1 +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-10-08 Matt Boykin Original Creation +// 2016-02-19 Dan Ogorchock Cleaned Up for inclusing in the ST_Anything Project +// 2016-02-27 Dan Ogorchock Added support for multiple DS18B20 sensors +// 2017-08-18 Dan Ogorchock Modified to send floating point values to SmartThings +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2019-03-11 Dan Ogorchock Added new optional parameter for starting sensor number for data transfer +// 2019-07-05 Dan Ogorchock Fix bug in multiple sensor support logic +// +// +//****************************************************************************************** +#include "PS_DS18B20_Temperature.h" + +#include "Constants.h" +#include "Everything.h" +#include +#include +#include + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + PS_DS18B20_Temperature::PS_DS18B20_Temperature(const __FlashStringHelper *name, unsigned int interval, int offset, byte pin, bool In_C, byte resolution, byte num_sensors, byte sensorStartingNum) : + PollingSensor(name, interval, offset), + m_dblTemperatureSensorValue(0.0), + m_OneWireBus(pin), + m_DS18B20(&m_OneWireBus), + m_In_C(In_C), + m_Resolution(resolution), + m_numSensors(num_sensors), + m_sensorStartingNum(sensorStartingNum) + { + + } + + //destructor + PS_DS18B20_Temperature::~PS_DS18B20_Temperature() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_DS18B20_Temperature::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_DS18B20_Temperature::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_DS18B20_Temperature::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //initialization routine - get first set of readings and send to ST cloud + void PS_DS18B20_Temperature::init() + { + m_DS18B20.begin(); //Initialize the DallasTemperature library + m_DS18B20.setResolution(m_Resolution); //Set the temperature sensor resolution + m_DS18B20.requestTemperatures(); //Send the command to get temperatures once, to ensure clean data before sending to ST + delay(500); //Wait 500ms to let sensors stabilize + getData(); //Get temperature data and send to ST cloud + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_DS18B20_Temperature::getData() + { + if (st::PollingSensor::debug) { + Serial.print(F("PS_DS18B20_Temperature::Requesting temperatures...")); + } + + m_DS18B20.requestTemperatures(); // Send the command to get temperatures + + if (st::PollingSensor::debug) { + Serial.println(F("DONE")); + } + + byte maxSensorNum = m_sensorStartingNum + m_numSensors - 1; + for (int index = m_sensorStartingNum; index <= maxSensorNum; index++) + { + if (m_In_C) + { + m_dblTemperatureSensorValue = m_DS18B20.getTempCByIndex(index-m_sensorStartingNum); + } + else + { + m_dblTemperatureSensorValue = m_DS18B20.getTempFByIndex(index-m_sensorStartingNum); + } + + if (st::PollingSensor::debug) { + Serial.print(F("PS_DS18B20_Temperature:: Temperature for the device # ")); + Serial.print(index); + Serial.print(F(" is: ")); + Serial.println(m_dblTemperatureSensorValue); + } + + + if (isnan(m_dblTemperatureSensorValue)) + { + if (st::PollingSensor::debug) { + Serial.print(F("PS_DS18B20_Temperature:: Error Reading Sensor # ")); + Serial.println(index); + } + m_dblTemperatureSensorValue = -99.0; + } + + if (m_numSensors == 1) + { + Everything::sendSmartString(getName() + " " + String(m_dblTemperatureSensorValue)); + } + else + { + Everything::sendSmartString(getName() + index + " " + String(m_dblTemperatureSensorValue)); + } + } + } + +} + + + diff --git a/lib/ST_Anything_DS18B20_Temperature/PS_DS18B20_Temperature.h b/lib/ST_Anything_DS18B20_Temperature/PS_DS18B20_Temperature.h new file mode 100644 index 0000000..0e39553 --- /dev/null +++ b/lib/ST_Anything_DS18B20_Temperature/PS_DS18B20_Temperature.h @@ -0,0 +1,89 @@ +//****************************************************************************************** +// File: PS_DS18B20_Temperature.h +// Author: Dan G Ogorchock +// +// Summary: PS_DS18B20_Temperature is a class which implements both the SmartThings "Temperature Measurement" capability. +// It inherits from the st::PollingSensor class. The current version uses a digital pin to measure the +// temperature from a Dallas Semiconductor One Wire DS18B20 series sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_DS18B20_Temperature sensor1(F("temperature1"), 120, 0, PIN_TEMPERATURE, false); (for a single sensor) +// st::PS_DS18B20_Temperature sensor1(F("temperature"), 120, 0, PIN_TEMPERATURE, false, 10, 3); (for 3 sensors) +// +// st::PS_DS18B20_Temperature() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - either "temperature1" for a single sensor, or "temperature" for multiple sensors +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used for the One-Wire DS18B20 sensor conenction +// - bool In_C - OPTIONAL - true = Report Celsius, false = Report Farenheit (Farentheit is the default) +// - byte resolution - OPTIONAL - DS18B20 sensor resolution in bits. 9, 10, 11, or 12. Defaults to 10 for decent accuracy and performance +// - byte num_sensors - OPTIONAL - number of OneWire DS18B20 sensors attached to OneWire bus - Defaults to 1 +// - byte sensorStartingNum - OPTIONAL - Starting number for sending temperature sensor data when using multiple sensors on one pin - Defaults to 1 +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-10-08 Matt Boykin Original Creation +// 2016-02-19 Dan Ogorchock Cleaned Up for inclusing in the ST_Anything Project +// 2016-02-27 Dan Ogorchock Added support for multiple DS18B20 sensors +// 2017-08-18 Dan Ogorchock Modified to send floating point values to SmartThings +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2019-03-11 Dan Ogorchock Added new optional parameter for starting sensor number for data transfer +// +// +//****************************************************************************************** +#ifndef ST_PS_DS18B20_TEMPERATURE_H +#define ST_PS_DS18B20_TEMPERATURE_H + + +#include "PollingSensor.h" +#include +#include +#include + +namespace st +{ + class PS_DS18B20_Temperature : public PollingSensor + { + private: + float m_dblTemperatureSensorValue; //current Temperature value + OneWire m_OneWireBus; //OneWire Bus + DallasTemperature m_DS18B20; //Dallas Temperature object + byte m_Resolution; //DS18B20 Resolution in bits - 9, 10, 11, or 12 + bool m_In_C; //Return temp in C + byte m_numSensors; //number of DS18B20 sensors to report values for + byte m_sensorStartingNum; //starting number of the sensor for data transfer to avoid conflicts with other devices on other pins + + public: + + //constructor - called in your sketch's global variable declaration section + PS_DS18B20_Temperature(const __FlashStringHelper *name, unsigned int interval, int offset, byte pin, bool In_C = false, byte resolution = 10, byte num_sensors = 1, byte sensorStartingNum = 1); + + //destructor + virtual ~PS_DS18B20_Temperature(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline float getTemperatureSensorValue() const { return float(m_dblTemperatureSensorValue); } + + //sets + + }; +} + +#endif /* ST_PS_DS18B20_TEMPERATURE_H */ diff --git a/lib/ST_Anything_HX711_Scale/HX711.cpp b/lib/ST_Anything_HX711_Scale/HX711.cpp new file mode 100644 index 0000000..5a9e00c --- /dev/null +++ b/lib/ST_Anything_HX711_Scale/HX711.cpp @@ -0,0 +1,151 @@ +// +// FILE: HX711.cpp +// AUTHOR: Rob Tillaart +// VERSION: 0.2.1 +// PURPOSE: Library for Loadcells for UNO +// URL: https://github.com/RobTillaart/HX711 +// +// HISTORY: +// 0.1.0 2019-09-04 initial release +// 0.1.1 2019-09-09 change long to float (reduce footprint) +// 0.2.0 2020-06-15 refactor; add price functions; +// 0.2.1 2020-12-28 add arduino-ci + unit test + + +#include "HX711.h" + +HX711::HX711() +{ + reset(); +} + +HX711::~HX711() {} + +void HX711::begin(uint8_t dataPin, uint8_t clockPin) +{ + _dataPin = dataPin; + _clockPin = clockPin; + + pinMode(_dataPin, INPUT); + pinMode(_clockPin, OUTPUT); + digitalWrite(_clockPin, LOW); + + reset(); +} + +void HX711::reset() +{ + _offset = 0; + _scale = 1; + _gain = 128; +} + +bool HX711::is_ready() +{ + return digitalRead(_dataPin) == LOW; +} + +float HX711::read() +{ + // this waiting takes most time... + while (digitalRead(_dataPin) == HIGH) yield(); + + union + { + long value = 0; + uint8_t data[4]; + } v; + + noInterrupts(); + + // Pulse the clock pin 24 times to read the data. + v.data[2] = shiftIn(_dataPin, _clockPin, MSBFIRST); + v.data[1] = shiftIn(_dataPin, _clockPin, MSBFIRST); + v.data[0] = shiftIn(_dataPin, _clockPin, MSBFIRST); + + // TABLE 3 page 4 datasheet + // only default verified, so other values not supported yet + uint8_t m = 1; // default gain == 128 + if (_gain == 64) m = 3; + if (_gain == 32) m = 2; + + while (m > 0) + { + digitalWrite(_clockPin, HIGH); + digitalWrite(_clockPin, LOW); + m--; + } + + interrupts(); + + // SIGN extend + if (v.data[2] & 0x80) v.data[3] = 0xFF; + + _lastRead = millis(); + return 1.0 * v.value; +} + +// assumes tare() has been set. +void HX711::callibrate_scale(uint16_t weight, uint8_t times) +{ + _scale = (1.0 * weight) / (read_average(times) - _offset); +} + +void HX711::wait_ready(uint32_t ms) +{ + while (!is_ready()) + { + delay(ms); + } +} + +bool HX711::wait_ready_retry(uint8_t retries, uint32_t ms) +{ + while (retries--) + { + if (is_ready()) return true; + delay(ms); + } + return false; +} + +bool HX711::wait_ready_timeout(uint32_t timeout, uint32_t ms) +{ + uint32_t start = millis(); + while (millis() - start < timeout) + { + if (is_ready()) return true; + delay(ms); + } + return false; +} + +float HX711::read_average(uint8_t times) +{ + float sum = 0; + for (uint8_t i = 0; i < times; i++) + { + sum += read(); + yield(); + } + return sum / times; +} + +float HX711::get_units(uint8_t times) +{ + float units = get_value(times) * _scale; + return units; +}; + +void HX711::power_down() +{ + digitalWrite(_clockPin, LOW); + digitalWrite(_clockPin, HIGH); +} + +void HX711::power_up() +{ + digitalWrite(_clockPin, LOW); +} + +// -- END OF FILE -- diff --git a/lib/ST_Anything_HX711_Scale/HX711.h b/lib/ST_Anything_HX711_Scale/HX711.h new file mode 100644 index 0000000..e8d635f --- /dev/null +++ b/lib/ST_Anything_HX711_Scale/HX711.h @@ -0,0 +1,99 @@ +#pragma once +// +// FILE: HX711.h +// AUTHOR: Rob Tillaart +// VERSION: 0.2.1 +// PURPOSE: Library for Loadcells for UNO +// URL: https://github.com/RobTillaart/HX711 +// +// HISTORY: see HX711.cpp +// +// NOTES +// Superset of interface of HX711 class of Bogde +// float iso long as float has 23 bits mantisse. + + +#include "Arduino.h" + +#define HX711_LIB_VERSION (F("0.2.1")) + +class HX711 +{ +public: + HX711(); + ~HX711(); + + // fixed gain 128 for now + void begin(uint8_t dataPin, uint8_t clockPin); + + void reset(); + + // checks if loadcell is ready to read. + bool is_ready(); + + // wait until ready, + // check every ms + void wait_ready(uint32_t ms = 0); + // max # retries + bool wait_ready_retry(uint8_t retries = 3, uint32_t ms = 0); + // max timeout + bool wait_ready_timeout(uint32_t timeout = 1000, uint32_t ms = 0); + + // raw read + float read(); + // multiple raw reads + float read_average(uint8_t times = 10); + // corrected for offset + float get_value(uint8_t times = 1) { return read_average(times) - _offset; }; + // converted to proper units. + float get_units(uint8_t times = 1); + + // TARE + // call tare to calibrate zero + void tare(uint8_t times = 10) { _offset = read_average(times); }; + float get_tare() { return -_offset * _scale; }; + bool tare_set() { return _offset != 0; }; + + // CORE "CONSTANTS" -> read datasheet + // GAIN values: 128, 64 32 [only 128 tested & verified] + void set_gain(uint8_t gain = 128) { _gain = gain; }; + uint8_t get_gain() { return _gain; }; + // SCALE > 0 + void set_scale(float scale = 1.0) { _scale = 1 / scale; }; + float get_scale() { return 1 / _scale; }; + // OFFSET > 0 + void set_offset(long offset = 0) { _offset = offset; }; + long get_offset() { return _offset; }; + + // CALIBRATION + // clear the scale + // call tare() to set the zero offset + // put a known weight on the scale + // call callibrate_scale(weight) + // scale is calculated. + void callibrate_scale(uint16_t weight, uint8_t times = 10); + + // POWER MANAGEMENT + void power_down(); + void power_up(); + + // TIME OF LAST READ + uint32_t last_read() { return _lastRead; }; + + // PRICING (idem calories?) + float get_price(uint8_t times = 1) { return get_units(times) * _price; }; + void set_unit_price(float price) { _price = price; }; + float get_unit_price() { return _price; }; + +private: + uint8_t _dataPin; + uint8_t _clockPin; + + uint8_t _gain = 128; // default channel A + long _offset = 0; + float _scale = 1; + uint32_t _lastRead = 0; + float _price = 0; +}; + +// -- END OF FILE -- diff --git a/lib/ST_Anything_HX711_Scale/PS_HX711.cpp b/lib/ST_Anything_HX711_Scale/PS_HX711.cpp new file mode 100644 index 0000000..f04d1e8 --- /dev/null +++ b/lib/ST_Anything_HX711_Scale/PS_HX711.cpp @@ -0,0 +1,211 @@ +//****************************************************************************************** +// File: PS_HX711.h +// Authors: Malcolm Dobson + Tim OCallaghan (Based on original programming by Dan G Ogorchock & Daniel J Ogorchock (Father and Son) ) +// +// Summary: PS_HX711 is a class which implements only the SmartThings "Sensor" device capability. +// It inherits from the st::PollingSensor class. The current version is made to be used as a framework +// for more complicated programming +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_HX711 sensor1(F("weight1"), 120, 0); +// +// st::PS_HX711() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2017-10-20 Allan (vseven) Modified original PS_Illuminance library for use with a generic sensor +// 2017-12-28 Dan Ogorchock Fixed bug with improper init() definition +// 2021-01-19 Malcolm Dobson Redone to support HX711 weight sensor +// 2021-01-23 Tim OCallaghan Pass pins on constructor and add storing of calibration factor in EEPROM and don't tare in init +// 2021-01-24 Malcolm Dobson Save the offset also in eeprom and then read and set in init +// 2022-02-08 Dan Ogorchock Minor comments clean up +// +// +//****************************************************************************************** + +#include "PS_HX711.h" + +#include "Constants.h" +#include "Everything.h" +#include + +const int calVal_eepromAdress = 0; +namespace st +{ +//private + +//public + //constructor - called in your sketch's global variable declaration section + PS_HX711::PS_HX711(const __FlashStringHelper *name, byte dout_pin, byte clk_pin, unsigned int interval, int offset): + PollingSensor(name, interval, offset), m_nSensorValue(0) + { + m_n_dout_pin = dout_pin; + m_n_clk_pin = clk_pin; + } + + //destructor + PS_HX711::~PS_HX711() + { + + } + + //Incoming data handler (receives commands and/or configuration data from the hub) + void PS_HX711::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + String cmd = s.substring(0, s.indexOf(':')); + + if(cmd==F("calibrate")) { + cmd = s.substring(s.indexOf(':') + 1); + calibrate(cmd.toFloat()); + } + else if(s==F("tare")) { + tare(); + } + else if(s==F("updated")) { + updated(); + } + else if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_HX711::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_HX711::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + void PS_HX711::init() { + + Serial.println(F("Initiating the PS_HX711 class")); + // setup HX711 + scale.begin(m_n_dout_pin, m_n_clk_pin); // Start scale on specified pins + + //get calibration factor from eeprom + #if defined(ESP8266)|| defined(ESP32) + EEPROM.begin(512); + #endif + EEPROM.get(calVal_eepromAdress, calibration_factor); + EEPROM.get(calVal_eepromAdress + sizeof(int), calibration_offset); + + Serial.println(F("PS_HX711::init read the EEPROM")); + Serial.println(calibration_factor); + Serial.println(calibration_offset); + + scale.wait_ready(); //Ensure scale is ready, this is a blocking function + scale.set_scale(); + scale.set_offset(calibration_offset); // Sets the calibration offset. + Serial.println(F("Scale Set")); + // tjo commenting out tare(); + } + + void PS_HX711::calibrate(const float weight) + { + float raw; + Serial.print(F("calibrate routine called with parameter:")); + Serial.println(weight); + if (weight > 0.0) + { + scale.wait_ready(); + raw = scale.read_average(5); + calibration_factor = (raw - calibration_offset) / weight; + + WriteEEPROM(calVal_eepromAdress, calibration_factor); + Serial.println(F("calibration saved to EEPROM")); + updated(); + } + else { + Serial.println(F("calibration weight must be positive")); + } + } + +//called periodically to re-zero the scale + void PS_HX711::tare() + { + scale.wait_ready(); + scale.tare(); // Tare scale on startup + scale.wait_ready(); + updated(); + calibration_offset = scale.read_average(5); + WriteEEPROM(calVal_eepromAdress + sizeof(int), calibration_offset); + + Serial.print(F("Scale Zeroed, with offset:")); + Serial.println(calibration_offset); + } + + //function to get data from sensor and queue results for transfer to hub + void PS_HX711::getData() + { + Serial.println(F("getData routine called")); + + //Get the data + float raw; + scale.wait_ready(); + raw = scale.read_average(5); // Read average of 5 raw value from scale + + Serial.print(F("Raw: ")); + Serial.print(raw); + Serial.print(F(", Calibration factor: ")); // Prints calibration factor. + Serial.print(calibration_factor); + Serial.print(F(", lastValue: ")); // Prints lastValue . + Serial.println(lastValue); + + + // Assign the data to the sensor value. m_nSensorValue is a + // ST_Anything standard for the value of the sensor. + + + // Only publish new value if difference of 500 or more in raw value + if (abs(lastValue - raw) >= 500) { + float reading; + + scale.wait_ready(); // Wait till scale is ready, this is blocking if your hardware is not connected properly. + scale.set_scale(calibration_factor); // Sets the calibration factor. + reading = scale.get_units(5); // Read average of 5 values in g/Kg + + lastValue = raw; + String m_nSensorValue = String(reading, 2); + + // To make it easier to debug print out our name and sensor value before sending it + Serial.print(getName()); + Serial.println(m_nSensorValue); + + // Send the value to our parent which will then update the device handler + Everything::sendSmartString(getName() + " " + String(m_nSensorValue)); + } + } + + + void PS_HX711::WriteEEPROM(int address, int value) + { + #if defined(ESP8266)|| defined(ESP32) + EEPROM.begin(512); + #endif + EEPROM.put(address, value); + #if defined(ESP8266)|| defined(ESP32) + EEPROM.commit(); + #endif + } + +} \ No newline at end of file diff --git a/lib/ST_Anything_HX711_Scale/PS_HX711.h b/lib/ST_Anything_HX711_Scale/PS_HX711.h new file mode 100644 index 0000000..b3a2911 --- /dev/null +++ b/lib/ST_Anything_HX711_Scale/PS_HX711.h @@ -0,0 +1,93 @@ +//****************************************************************************************** +// File: PS_HX711.h +// Authors: Malcolm Dobson + Tim OCallaghan (Based on original programming by Dan G Ogorchock & Daniel J Ogorchock (Father and Son) ) +// +// Summary: PS_HX711 is a class which implements only the SmartThings "Sensor" device capability. +// It inherits from the st::PollingSensor class. The current version is made to be used as a framework +// for more complicated programming +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_HX711 sensor1(F("weight1"), 120, 0); +// +// st::PS_HX711() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2017-10-20 Allan (vseven) Modified original PS_Illuminance library for use with a generic sensor +// 2017-12-28 Dan Ogorchock Fixed bug with improper init() definition +// 2021-01-19 Malcolm Dobson Redone to support HX711 weight sensor +// 2021-01-23 Tim OCallaghan Pass pins on constructor and add storing of calibration factor in EEPROM and don't tare in init +// 2021-01-24 Malcolm Dobson Save the offset also in eeprom and then read and set in init +// 2022-02-08 Dan Ogorchock Minor comments clean up +// +// +//****************************************************************************************** + +#include "PollingSensor.h" +#include + +namespace st +{ + class PS_HX711: public PollingSensor + { + private: + char m_nSensorValue; //converted to a string so all data can be passed in one call + HX711 scale; + int calibration_factor = -16900; // Defines factor we'll use for calibrating. + int calibration_offset = 0; // Defines zero offset we'll use for calibrating. + int lastValue = -1; + byte m_n_dout_pin; //esp pin for hx711 dout + byte m_n_clk_pin; //esp pin for hx711 clk + public: + //constructor - called in your sketch's global variable declaration section + //this can be modified to accepting more varialbes into it by modifying the + //line. For example if you wanted to assign a pin or a variable you could add + //a ", int myVariable" after the offset below and then use that within your program. + //you would need to also update the associated line in the .cpp file. + PS_HX711(const __FlashStringHelper *name, byte dout_pin, byte clk_pin, unsigned int interval, int offset); + + //destructor + virtual ~PS_HX711(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //calibrate scale + void calibrate(const float weight); + + //reset scale to zero + void tare(); + + //update device, so next read will publish a new value + inline void updated() {lastValue = -1;} + + void WriteEEPROM(int address, int value); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline byte getSensorValue() const {return m_nSensorValue;} + + //sets + // set a calibration factor so the scale report accurate weight + void setCalibration(const int factor) {calibration_factor = factor;} + inline void clearLastValue() {lastValue = -1;} + }; +} diff --git a/lib/ST_Anything_MAX44009_Illuminance/PS_MAX44009_Illuminance.cpp b/lib/ST_Anything_MAX44009_Illuminance/PS_MAX44009_Illuminance.cpp new file mode 100644 index 0000000..6e8817f --- /dev/null +++ b/lib/ST_Anything_MAX44009_Illuminance/PS_MAX44009_Illuminance.cpp @@ -0,0 +1,117 @@ +//****************************************************************************************** +// File: PS_MAX44009_Illuminance.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_MAX44009_Illuminance is a class which implements the SmartThings "Illuminance Measurement" device capability. +// It inherits from the st::PollingSensor class. It uses I2C communication to measure the Illuminace from a MAX44009 sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_MAX44009_Illuminance sensor1(F("illuminance1"), 60, 0); (simple, uses defaults) +// For Example: st::PS_MAX44009_Illuminance sensor1(F("illuminance1"), 60, 0, MAX44009_A0_LOW); (full user control of settings) +// +// st::PS_MAX44009_Illuminance() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - uint8_t addr -OPTIONAL - defaults to MAX44009_A0_LOW +// +// +// I2C address options +// MAX44009_A0_LOW 0x4A //< Pin A0 pulled Low +// MAX44009_A0_HIGH 0x4B //< Pin A0 pulled Hi +// +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2018-07-03 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + +#include "PS_MAX44009_Illuminance.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + +//public + //constructor - called in your sketch's global variable declaration section + PS_MAX44009_Illuminance::PS_MAX44009_Illuminance(const __FlashStringHelper *name, unsigned int interval, int offset, uint8_t addr) : + PollingSensor(name, interval, offset), + myLux(addr, false) + { + + } + + //destructor + PS_MAX44009_Illuminance::~PS_MAX44009_Illuminance() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_MAX44009_Illuminance::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_MAX44009_Illuminance::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_MAX44009_Illuminance::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + void PS_MAX44009_Illuminance::init() { + + //Set mode of the MAX44009 to its default state + // From MAX44009 Datasheet: "Default mode. The IC measures lux intensity only + // once every 800ms regardless of integration time. This mode allows the part // to operate at its lowest possible supply current. myLux.setAutomaticMode(); + + //read and transmit initial data from sensor + getData(); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_MAX44009_Illuminance::getData() + { + /* Get a new sensor data */ + m_fLux = myLux.getLux(); + int err = myLux.getError(); + if (err != 0) + { + if (st::PollingSensor::debug) + { + Serial.print(F("MAX44009 sensor Error = ")); + Serial.println(err); + Serial.println(F("Check your wiring and I2C address.")); + } + } + else + { + //send data to SmartThings/Hubitat + Everything::sendSmartString(getName() + " " + String(m_fLux)); + } + } + +} diff --git a/lib/ST_Anything_MAX44009_Illuminance/PS_MAX44009_Illuminance.h b/lib/ST_Anything_MAX44009_Illuminance/PS_MAX44009_Illuminance.h new file mode 100644 index 0000000..3347c08 --- /dev/null +++ b/lib/ST_Anything_MAX44009_Illuminance/PS_MAX44009_Illuminance.h @@ -0,0 +1,75 @@ +//****************************************************************************************** +// File: PS_MAX44009_Illuminance.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_MAX44009_Illuminance is a class which implements the SmartThings "Illuminance Measurement" device capability. +// It inherits from the st::PollingSensor class. It uses I2C communication to measure the Illuminace from a MAX44009 sensor. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_MAX44009_Illuminance sensor1(F("illuminance1"), 60, 0); (simple, uses defaults) +// For Example: st::PS_MAX44009_Illuminance sensor1(F("illuminance1"), 60, 0, MAX44009_A0_LOW); (full user control of settings) +// +// st::PS_MAX44009_Illuminance() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - uint8_t addr -OPTIONAL - defaults to MAX44009_A0_LOW +// +// +// I2C address options +// MAX44009_A0_LOW 0x4A //< Pin A0 pulled Low +// MAX44009_A0_HIGH 0x4B //< Pin A0 pulled Hi +// +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2018-07-03 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + +#ifndef ST_PS_MAX44009_Illuminance_H +#define ST_PS_MAX44009_Illuminance_H + +#include "PollingSensor.h" +#include "Max44009.h" + +namespace st +{ + class PS_MAX44009_Illuminance: public PollingSensor + { + private: + Max44009 myLux; //MAX44009 object + float m_fLux; //lux + + public: + //constructor - called in your sketch's global variable declaration section + PS_MAX44009_Illuminance(const __FlashStringHelper *name, unsigned int interval, int offset, uint8_t addr = MAX44009_A0_LOW); + + //destructor + virtual ~PS_MAX44009_Illuminance(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + + //sets + + }; +} +#endif diff --git a/lib/ST_Anything_MCP23008/S_TimedRelay_MCP.cpp b/lib/ST_Anything_MCP23008/S_TimedRelay_MCP.cpp new file mode 100644 index 0000000..7085334 --- /dev/null +++ b/lib/ST_Anything_MCP23008/S_TimedRelay_MCP.cpp @@ -0,0 +1,200 @@ +//****************************************************************************************** +// File: S_TimedRelay_MCP.cpp +// Authors: Dan G Ogorchock +// +// Summary: S_TimedRelay_MCP is a class which implements the SmartThings "Relay" device capability. It features +// an automatic-turn-off time delay for a relay to emulate a button press. +// +// It inherits from the st::Sensor class and clones much from the st::Executor Class +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::S_TimedRelay_MCP sensor1(F("relaySwitch1"), PIN_RELAY, LOW, true, 1000, 0, 1, 0); +// +// st::S_TimedRelay_MCP() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pinOutput - REQUIRED - the Arduino Pin to be used as a digital output +// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Ouput should use inverted logic +// - long onTime - REQUIRED - the number of milliseconds to keep the output on, DEFGAULTS to 1000 milliseconds +// - long offTime - OPTIONAL - the number of milliseconds to keep the output off, DEFAULTS to 0 +// - int numCycles - OPTIONAL - the number of times to repeat the on/off cycle, DEFAULTS to 1 +// - byte finalState - OPTIONAL - leave in X state after finishing sequence 0 = off, 1 = on , Defaults to 0 +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-12-29 Dan Ogorchock Original Creation +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2019-06-23 Brian Wilson Added finalState option +// 2020-08-17 M2_ Modified for MCP23008. Changed digitalwrite to Adafruit_MCP23008.write, and pinMode to Adafruit_MCP23008.pinMode. That's it! +// +//****************************************************************************************** + +#include "S_TimedRelay_MCP.h" + +#include "Constants.h" +#include "Everything.h" +#include +namespace st +{ +//private + void S_TimedRelay_MCP::writeStateToPin() + { + Adafruit_MCP23008().digitalWrite(m_nOutputPin, m_bInvertLogic ? !m_bCurrentState : m_bCurrentState); + } + +//public + //constructor + S_TimedRelay_MCP::S_TimedRelay_MCP(const __FlashStringHelper *name, byte pinOutput, bool startingState, bool invertLogic, unsigned long onTime, unsigned long offTime, unsigned int numCycles, byte finalState) : + Sensor(name), + m_bCurrentState(startingState), + m_bInvertLogic(invertLogic), + m_lOnTime(onTime), + m_lOffTime(offTime), + m_iNumCycles(numCycles), + m_iCurrentCount(numCycles), + m_nfinalState(finalState), + m_lTimeChanged(0), + m_bTimerPending(false) + { + setOutputPin(pinOutput); + + if (numCycles < 1) + { + m_iNumCycles = 1; + m_iCurrentCount = 1; + + Serial.println(F("S_TimedRelay_MCP:: INVALID Number of Cycles Requested! Must be at least 1. Setting to 1.")); + } + } + + //destructor + S_TimedRelay_MCP::~S_TimedRelay_MCP() + { + } + + void S_TimedRelay_MCP::init() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + } + + //update function + void S_TimedRelay_MCP::update() + { + if (m_iCurrentCount < m_iNumCycles) + { + //Turn off digital output if timer has expired + if ((m_bCurrentState == HIGH) && (millis() - m_lTimeChanged >= m_lOnTime)) + { + if (m_nfinalState == 1) { // final state will be on + //add one to the current count since we finished an on/off cycle, and turn on output if needed + m_iCurrentCount++; + if (m_iCurrentCount < m_iNumCycles) + { + m_bCurrentState = LOW; + writeStateToPin(); + m_lTimeChanged = millis(); + } + + } else { + m_bCurrentState = LOW; + writeStateToPin(); + m_lTimeChanged = millis(); + } + } + else if ((m_bCurrentState == LOW) && (millis() - m_lTimeChanged >= m_lOffTime)) + { + if (m_nfinalState == 0) { // final state will be off + //add one to the current count since we finished an on/off cycle, and turn on output if needed + m_iCurrentCount++; + if (m_iCurrentCount < m_iNumCycles) + { + m_bCurrentState = HIGH; + writeStateToPin(); + m_lTimeChanged = millis(); + } + } else { + m_bCurrentState = HIGH; + writeStateToPin(); + m_lTimeChanged = millis(); + } + } + + //Check to see if we just finished the requested number of cycles + if (m_iCurrentCount == m_iNumCycles) + { + //Decrement number of active timers + if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--; + m_bTimerPending = false; + + //Queue the relay status update the ST Cloud + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + } + } + } + + void S_TimedRelay_MCP::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + if (st::Device::debug) { + Serial.print(F("S_TimedRelay_MCP::beSmart s = ")); + Serial.println(s); + } + if ((s == F("on")) && (m_bCurrentState == LOW)) + { + m_bCurrentState = HIGH; + + //Save time turned on + m_lTimeChanged = millis(); + + //Increment number of active timers + if (!m_bTimerPending) + { + st::Everything::bTimersPending++; + m_bTimerPending = true; + } + //Queue the relay status update the ST Cloud + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + + //Set the initial count to zero + m_iCurrentCount = 0; + + //update the digital output + writeStateToPin(); + } + else if ((s == F("off")) && (m_bCurrentState == HIGH)) + { + m_bCurrentState = LOW; + + //Decrement number of active timers + if (st::Everything::bTimersPending > 0) st::Everything::bTimersPending--; + m_bTimerPending = false; + + //Queue the relay status update the ST Cloud + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + + //Reset the count to the number of required cycles to prevent Update() routine from running if someone sends an OFF command + m_iCurrentCount = m_iNumCycles; + + //update the digital output + writeStateToPin(); + } + + } + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor + void S_TimedRelay_MCP::refresh() + { + //Queue the relay status update the ST Cloud + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + } + + void S_TimedRelay_MCP::setOutputPin(byte pin) + { + m_nOutputPin = pin; + Adafruit_MCP23008().pinMode(m_nOutputPin, OUTPUT); + writeStateToPin(); + } + +} diff --git a/lib/ST_Anything_MCP23008/S_TimedRelay_MCP.h b/lib/ST_Anything_MCP23008/S_TimedRelay_MCP.h new file mode 100644 index 0000000..c4ec006 --- /dev/null +++ b/lib/ST_Anything_MCP23008/S_TimedRelay_MCP.h @@ -0,0 +1,90 @@ +//****************************************************************************************** +// File: S_TimedRelay_MCP.h +// Authors: Dan G Ogorchock +// +// Summary: S_TimedRelay_MCP is a class which implements the SmartThings "Relay" device capability. It features +// an automatic-turn-off time delay for a relay to emulate a button press. +// +// It inherits from the st::Sensor class and clones much from the st::Executor Class +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::S_TimedRelay_MCP sensor1(F("relaySwitch1"), PIN_RELAY, LOW, true, 1000, 0, 1, 0); +// +// st::S_TimedRelay_MCP() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte pinOutput - REQUIRED - the Arduino Pin to be used as a digital output +// - bool startingState - REQUIRED - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// - bool invertLogic - REQUIRED - determines whether the Arduino Digital Ouput should use inverted logic +// - long onTime - REQUIRED - the number of milliseconds to keep the output on, DEFGAULTS to 1000 milliseconds +// - long offTime - OPTIONAL - the number of milliseconds to keep the output off, DEFAULTS to 0 +// - int numCycles - OPTIONAL - the number of times to repeat the on/off cycle, DEFAULTS to 1 +// - byte finalState - OPTIONAL - leave in X state after finishing sequence 0 = off, 1 = on , Defaults to 0 +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-12-29 Dan Ogorchock Original Creation +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2019-06-23 Brian Wilson Added finalState option +// 2019-08-10 Dan Ogorchock Added public getStatus() +// 2020-08-17 M2_ Modified for MCP23008. Only change was file name and class name. +// +//****************************************************************************************** + +#ifndef ST_S_TIMEDRELAY_MCP_H +#define ST_S_TIMEDRELAY_MCP_H + +#include "Sensor.h" + +namespace st +{ + class S_TimedRelay_MCP : public Sensor //inherits from parent Sensor Class + { + private: + + //following are for the digital output + bool m_bCurrentState; //HIGH or LOW + bool m_bInvertLogic; //determines whether the Arduino Digital Output should use inverted logic + byte m_nOutputPin; //Arduino Pin used as a Digital Output for the switch - often connected to a relay or an LED + unsigned long m_lOnTime; //number of milliseconds to keep digital output HIGH before automatically turning off + unsigned long m_lOffTime; //number of milliseconds to keep digital output LOW before automatically turning on + unsigned int m_iNumCycles; //number of on/off cycles of the digital output + unsigned int m_iCurrentCount; //current number of on/off cycles of the digital output + byte m_nfinalState; //desired final state of the output after the cycling has completed (typical value is 0) + unsigned long m_lTimeChanged; //time when the digital output was last changed + bool m_bTimerPending; //true if waiting on relay timer to expire + + void writeStateToPin(); //function to update the Arduino Digital Output Pin + + public: + //constructor - called in your sketch's global variable declaration section + S_TimedRelay_MCP(const __FlashStringHelper *name, byte pinOutput, bool startingState = LOW, bool invertLogic = false, unsigned long onTime = 1000, unsigned long offTime = 0, unsigned int numCycles = 1, byte finalState = 0); + + //destructor + virtual ~S_TimedRelay_MCP(); + + //initialization function + virtual void init(); + + //update function + void update(); + + //SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output) + virtual void beSmart(const String &str); + + //called periodically by Everything class to ensure ST Cloud is kept consistent with the state of the contact sensor + virtual void refresh(); + + //gets + virtual byte getPin() const { return m_nOutputPin; } + virtual bool getTimerActive() const { return m_bTimerPending; } + virtual bool getStatus() const { return m_bCurrentState; } + + //sets + virtual void setOutputPin(byte pin); + }; +} + + +#endif diff --git a/lib/ST_Anything_MKR_THERM/PS_MKR_THERM.cpp b/lib/ST_Anything_MKR_THERM/PS_MKR_THERM.cpp new file mode 100644 index 0000000..a57bfe4 --- /dev/null +++ b/lib/ST_Anything_MKR_THERM/PS_MKR_THERM.cpp @@ -0,0 +1,124 @@ +//****************************************************************************************** +// File: PS_MKR_THERM.cpp +// Authors: Dan G Ogorchock +// +// Summary: PS_MKR_THERM is a class which implements the SmartThings "Temperature Measurement" +// device capability. +// It inherits from the st::PollingSensor class. This class implements support for +// Arduino MKR THERM Thermocouple Shield. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_MKR_THERM sensor1(F("temperature1"), 120, 3); +// +// st::PS_TemperatureHumidity() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2019-06-23 Dan Ogorchock Original Creation +// 2019-06-24 Dan Ogorchock Improved false reading handling +// +// +//****************************************************************************************** + +#include "PS_MKR_THERM.h" + +#include "Constants.h" +#include "Everything.h" + +#include + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + PS_MKR_THERM::PS_MKR_THERM(const __FlashStringHelper *name, unsigned int interval, int offset): + PollingSensor(name, interval, offset), + m_dblTemperatureSensorValue(-99.0) + { + + } + + //destructor + PS_MKR_THERM::~PS_MKR_THERM() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_MKR_THERM::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_MKR_THERM::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_MKR_THERM::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //initialization routine - get first set of readings and send to ST cloud + void PS_MKR_THERM::init() + { + if (!THERM.begin()) { + Serial.println("Failed to initialize MKR THERM shield!"); + } + getData(); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_MKR_THERM::getData() + { + double tempTemperature; + double totalTemperature = 0.0; + int numGoodValues = 0; + + for (int i = 1; i <= 3; i++) { + tempTemperature = THERM.readTemperature(); + if (isnan(tempTemperature)) + { + if (st::PollingSensor::debug) { + Serial.println(F("PS_MKR_THERM:: Error Reading Thermocouple.")); + } + } + else + { + totalTemperature = totalTemperature + tempTemperature; + numGoodValues++; + } + } + + if (numGoodValues > 0) { + m_dblTemperatureSensorValue = totalTemperature/numGoodValues; + Everything::sendSmartString(getName() + " " + String(int(m_dblTemperatureSensorValue))); + } + else + { + Serial.println(F("PS_MKR_THERM:: Error Reading Thermocouple multiple times. No good value measured this cycle.")); + } + } + +} \ No newline at end of file diff --git a/lib/ST_Anything_MKR_THERM/PS_MKR_THERM.h b/lib/ST_Anything_MKR_THERM/PS_MKR_THERM.h new file mode 100644 index 0000000..351e455 --- /dev/null +++ b/lib/ST_Anything_MKR_THERM/PS_MKR_THERM.h @@ -0,0 +1,74 @@ +//****************************************************************************************** +// File: PS_MKR_THERM.h +// Authors: Dan G Ogorchock +// +// Summary: PS_MKR_THERM is a class which implements the SmartThings "Temperature Measurement" +// device capability. +// It inherits from the st::PollingSensor class. This class implements support for +// Arduino MKR THERM Thermocouple Shield. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_MKR_THERM sensor1(F("temperature1"), 120, 3); +// +// st::PS_TemperatureHumidity() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2019-06-23 Dan Ogorchock Original Creation +// +// +//****************************************************************************************** + +#ifndef ST_PS_MKR_THERM_H +#define ST_PS_MKR_THERM_H + +#include "PollingSensor.h" + +#include + +namespace st +{ + class PS_MKR_THERM: public PollingSensor + { + private: + double m_dblTemperatureSensorValue; //current Temperature value + + public: + + //constructor - called in your sketch's global variable declaration section + PS_MKR_THERM(const __FlashStringHelper *name, unsigned int interval, int offset); + + //destructor + virtual ~PS_MKR_THERM(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline int getTemperatureSensorValue() const { return int(m_dblTemperatureSensorValue); } + + //sets + + }; +} + + + +#endif \ No newline at end of file diff --git a/lib/ST_Anything_NeoPixelBus/EX_RGBW_NeoPixelBus_T.h b/lib/ST_Anything_NeoPixelBus/EX_RGBW_NeoPixelBus_T.h new file mode 100644 index 0000000..c96f882 --- /dev/null +++ b/lib/ST_Anything_NeoPixelBus/EX_RGBW_NeoPixelBus_T.h @@ -0,0 +1,173 @@ +//****************************************************************************************** +// File: EX_RGBW_NeoPixelBus_T.h +// Authors: Allan (vseven) based on EX_Switch_Dim by Dan G Ogorchock +// +// Summary: EX_RGBW_NeoPixelBus_T is a templated class which implements the SmartThings "Color Control", "Switch", and "Switch Level" device capabilities. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_RGBW_NeoPixelBus_T executor1("rgbSwitch1", PIXEL_COUNT, OUTPUT_PIN); +// +// Each strip can have a different LED feature (the RGB order) and method for writting the data. +// See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods for the full list. For example on a ESP32 you +// can call up to 8 different strips by using the RTM method as such: +// +// st::EX_RGBW_NeoPixelBus_T executor1("rgbSwitch1", 60, 25); +// st::EX_RGBW_NeoPixelBus_T executor2("rgbSwitch2", 150, 26); +// st::EX_RGBW_NeoPixelBus_T executor3("rgbSwitch3", 30, 27); +// +// st::EX_RGBW_NeoPixelBus_T() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name. +// - uint16_t pixelCount - REQUIRED - the number of programmable pixels in the RGB strip +// - uint8_t outputPIN1 - REQUIRED - the primary pin to use for data writes +// - uint8_t outputPIN2 - OPTIONAL - for methods that require two pins, like DotStar strips, this will be the second pin +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2016-04-30 Dan Ogorchock Original Creation +// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()" +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2017-10-06 Allan (vseven) Modified original code from EX_Switch_Dim to be used for RGB lighting +// 2020-08-01 Allan (vseven) Modified the EX_RGBW_Dim for use with addressable LED strips using the NeoPixelBus library +// 2020-08-14 Allan (vseven) Converted the library into a template library to allow multiple different LED strips +// +//****************************************************************************************** +#ifndef ST_EX_RGBW_NeoPixelBus_T +#define ST_EX_RGBW_NeoPixelBus_T + +#include "Executor.h" +#include "Constants.h" +#include "Everything.h" + +#include "NeoPixelBus.h" + +namespace st +{ + template + class EX_RGBW_NeoPixelBus_T: public Executor + { + private: + bool m_bCurrentState; //HIGH or LOW + String m_sCurrentHEX = "#000000"; //HEX value of color currently set + + // NeoPixelBus object. + NeoPixelBus m_nStrip; + + void writeCommandToOutput() + { + uint8_t R = 0; + uint8_t G = 0; + uint8_t B = 0; + uint8_t W = 0; + + if (st::Executor::debug) { + Serial.println("m_bCurrentState: " + String(m_bCurrentState)); + Serial.println("m_sCurrentHEX: " + String(m_sCurrentHEX)); + } + + if (m_bCurrentState == HIGH){ + // Our status is on so get the RGB value from the hex + String hexstring = m_sCurrentHEX; + long number = (long) strtol( &hexstring[1], NULL, 16); + // Split them up into r, g, b, and w values + R = number >> 24; + G = number >> 16 & 0xFF; + B = number >> 8 & 0xFF; + W = number & 0xFF; + } + + if (st::Executor::debug) { + Serial.print(F("subString R:G:B:W = ")); + Serial.println(String(R) + ":" + String(G) + ":" + String(B) + ":" + String(W)); + } + + // Write to our output + RgbwColor myColor = RgbwColor(R, G, B, W); + m_nStrip.ClearTo(myColor); + + if (st::Executor::debug) { + Serial.println(F("All pixels set. Sending show command.")); + } + + // then display it + m_nStrip.Show(); + } + + public: + //constructor - called in your sketch's global variable declaration section + EX_RGBW_NeoPixelBus_T(const __FlashStringHelper *name, uint16_t pixelCount, uint8_t outputPin1): + Executor(name), + m_nStrip(pixelCount,outputPin1) + { + + } + + EX_RGBW_NeoPixelBus_T(const __FlashStringHelper *name, uint16_t pixelCount, uint8_t outputPin1, uint8_t outputPin2): + Executor(name), + m_nStrip(pixelCount,outputPin1,outputPin2) + { + + } + + //destructor + ~EX_RGBW_NeoPixelBus_T() + { + + } + + //gets + bool getStatus() const { return m_bCurrentState; } //whether the switch is HIGH or LOW + String getHEX() const { return m_sCurrentHEX; } // color value in HEX + + //sets + + //initialize + void init() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + + if (st::Executor::debug) { + Serial.println("EX_RGBW_NeoPixelBus_T - " + getName() + " init called. Sending Begin to RGB strip to clear it out."); + } + // On startup make sure strip is turned off + m_nStrip.Begin(); + m_nStrip.Show(); + } + + //functions + void beSmart(const String &str) + { + String s=str.substring(str.indexOf(' ')+1); + if (st::Executor::debug) { + Serial.print(F("EX_RGBW_NeoPixelBus_T::beSmart s = ")); + Serial.println(s); + } + if(s==F("on")) + { + m_bCurrentState=HIGH; + } + else if(s==F("off")) + { + m_bCurrentState=LOW; + } + else //must be a set color command + { + s.trim(); + m_sCurrentHEX = s; + } + + writeCommandToOutput(); + + //Send data to SmartThings/Hubitat + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off"))); + } + + void refresh() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off"))); + } + }; +} +#endif diff --git a/lib/ST_Anything_NeoPixelBus/EX_RGB_NeoPixelBus_T.h b/lib/ST_Anything_NeoPixelBus/EX_RGB_NeoPixelBus_T.h new file mode 100644 index 0000000..6afd170 --- /dev/null +++ b/lib/ST_Anything_NeoPixelBus/EX_RGB_NeoPixelBus_T.h @@ -0,0 +1,180 @@ +//****************************************************************************************** +// File: EX_RGB_NeoPixelBus_T.h +// Authors: Allan (vseven) based on EX_Switch_Dim by Dan G Ogorchock +// +// Summary: EX_RGB_NeoPixelBus_T is a templated class which implements the SmartThings "Color Control", "Switch", and "Switch Level" device capabilities. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_RGB_NeoPixelBus_T executor1("rgbSwitch1", PIXEL_COUNT, OUTPUT_PIN); +// +// Each strip can have a different LED feature (the RGB order) and method for writting the data. +// See https://github.com/Makuna/NeoPixelBus/wiki/ESP32-NeoMethods for the full list. For example on a ESP32 you +// can call up to 8 different strips by using the RTM method as such: +// +// st::EX_RGB_NeoPixelBus_T executor1("rgbSwitch1", 60, 25); +// st::EX_RGB_NeoPixelBus_T executor2("rgbSwitch2", 150, 26); +// st::EX_RGB_NeoPixelBus_T executor3("rgbSwitch3", 30, 27); +// +// st::EX_RGB_NeoPixelBus_T() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name. +// - uint16_t pixelCount - REQUIRED - the number of programmable pixels in the RGB strip +// - uint8_t outputPIN1 - REQUIRED - the primary pin to use for data writes +// - uint8_t outputPIN2 - OPTIONAL - for methods that require two pins, like DotStar strips, this will be the second pin +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2016-04-30 Dan Ogorchock Original Creation +// 2018-08-14 Dan Ogorchock Modified to avoid compiler errors on ESP32 since it currently does not support "analogWrite()" +// 2017-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// 2017-10-06 Allan (vseven) Modified original code from EX_Switch_Dim to be used for RGB lighting +// 2020-08-01 Allan (vseven) Modified the EX_RGB_Dim for use with addressable LED strips using the NeoPixelBus library +// 2020-08-14 Allan (vseven) Converted the library into a template library to allow multiple different LED strips +// +//****************************************************************************************** +#ifndef ST_EX_RGB_NeoPixelBus_T +#define ST_EX_RGB_NeoPixelBus_T + +#include "Executor.h" +#include "Constants.h" +#include "Everything.h" + +#include "NeoPixelBus.h" + +namespace st +{ + template + class EX_RGB_NeoPixelBus_T: public Executor + { + private: + bool m_bCurrentState; //HIGH or LOW + String m_sCurrentHEX = "#000000"; //HEX value of color currently set + + // NeoPixelBus object. + NeoPixelBus m_nStrip; + + void writeCommandToOutput() + { + uint8_t R = 0; + uint8_t G = 0; + uint8_t B = 0; + + if (st::Executor::debug) { + Serial.println("m_bCurrentState: " + String(m_bCurrentState)); + Serial.println("m_sCurrentHEX: " + String(m_sCurrentHEX)); + } + + if (m_bCurrentState == HIGH){ + // Our status is on so get the RGB value from the hex + String hexstring = m_sCurrentHEX; + long number = (long) strtol( &hexstring[1], NULL, 16); + // Split them up into r, g, and b values + R = number >> 16; + G = number >> 8 & 0xFF; + B = number & 0xFF; + + } else { + // Status is off so turn off LED + R = 0; + G = 0; + B = 0; + } + + if (st::Executor::debug) { + Serial.print(F("subString R:G:B = ")); + Serial.println(String(R) + ":" + String(G) + ":" + String(B)); + Serial.print(F("Total number of pixels reported by strip: ")); + Serial.println(String(m_nStrip.PixelCount())); + } + + + // Write to our output + RgbColor myColor = RgbColor(R, G, B); + m_nStrip.ClearTo(myColor); + + if (st::Executor::debug) { + Serial.println(F("All pixels set. Sending show command.")); + } + + // then display it + m_nStrip.Show(); + } + + public: + //constructor - called in your sketch's global variable declaration section + EX_RGB_NeoPixelBus_T(const __FlashStringHelper *name, uint16_t pixelCount, uint8_t outputPin1): + Executor(name), + m_nStrip(pixelCount,outputPin1) + { + + } + + EX_RGB_NeoPixelBus_T(const __FlashStringHelper *name, uint16_t pixelCount, uint8_t outputPin1, uint8_t outputPin2): + Executor(name), + m_nStrip(pixelCount,outputPin1,outputPin2) + { + + } + + //destructor + ~EX_RGB_NeoPixelBus_T() + { + + } + + //gets + bool getStatus() const { return m_bCurrentState; } //whether the switch is HIGH or LOW + String getHEX() const { return m_sCurrentHEX; } // color value in HEX + + //sets + + //initialize + void init() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + + if (st::Executor::debug) { + Serial.println("EX_RGB_NeoPixelBus_T - " + getName() + " init called. Sending Begin to RGB strip to clear it out."); + } + // On startup make sure strip is turned off + m_nStrip.Begin(); + m_nStrip.Show(); + } + + //functions + void beSmart(const String &str) + { + String s=str.substring(str.indexOf(' ')+1); + if (st::Executor::debug) { + Serial.print(F("EX_RGB_NeoPixelBus_T::beSmart s = ")); + Serial.println(s); + } + if(s==F("on")) + { + m_bCurrentState=HIGH; + } + else if(s==F("off")) + { + m_bCurrentState=LOW; + } + else //must be a set color command + { + s.trim(); + m_sCurrentHEX = s; + } + + writeCommandToOutput(); + + //Send data to SmartThings/Hubitat + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off"))); + } + + void refresh() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off"))); + } + }; +} +#endif diff --git a/lib/ST_Anything_RCSwitch/EX_RCSwitch.cpp b/lib/ST_Anything_RCSwitch/EX_RCSwitch.cpp new file mode 100644 index 0000000..8c288fa --- /dev/null +++ b/lib/ST_Anything_RCSwitch/EX_RCSwitch.cpp @@ -0,0 +1,116 @@ +//****************************************************************************************** +// File: EX_RCSwitch.cpp +// Author: Dan G Ogorchock +// +// Summary: EX_RCSwitch is a class which implements the SmartThings "Switch" device capability. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_RCSwitch executor1("switch1", PIN_RCSWITCH, 35754004, 26, 18976788, 26, 174, 1, 15, LOW); +// +// st::EX_RCSwitch() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte transmitterPin - REQUIRED - the Arduino Pin to be used as a digital output for the RCSwitch object's transmitter pin +// - unsigned long onCode - REQUIRED - the "on" code for RCSwitch send() command +// - unsigned int onLength - REQUIRED - the "on" code's length for RCSwitch send() command +// - unsigned long offCode - REQUIRED - the "off" code for RCSwitch send() command +// - unsigned int offLength - REQUIRED - the "off" code's length for RCSwitch send() command +// - unsigned int pulseLength - REQUIRED - the length of the RF pulse for RCSwitch send() command +// - byte protocol - OPTIONAL - defaults to "1" - the protocol for RCSwitch send() command +// - byte repeatTransmits - OPTIONAL - defaults to "15" - the number of repeated transmits for RCSwitch send() command +// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-26 Dan Ogorchock Original Creation +// 2015-05-20 Dan Ogorchock Improved to work with Etekcity ZAP 3F 433Mhz RF Outlets +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// +//****************************************************************************************** + +#include "EX_RCSwitch.h" + +#include "Constants.h" +#include "Everything.h" + +namespace st +{ +//private + void EX_RCSwitch::writeStateToPin() + { + if (m_bCurrentState) + { + m_myRCSwitch.send(m_onCode, m_onLength); + } + else + { + m_myRCSwitch.send(m_offCode, m_offLength); + } + } + + + +//public + //constructor + EX_RCSwitch::EX_RCSwitch(const __FlashStringHelper *name, byte transmitterPin, unsigned long onCode, unsigned int onLength, unsigned long offCode, unsigned int offLength, unsigned int pulseLength, byte protocol, byte repeatTransmits, bool startingState) : + Executor(name), + m_bCurrentState(startingState), + m_myRCSwitch(RCSwitch()), + m_onCode(onCode), + m_onLength(onLength), + m_offCode(offCode), + m_offLength(offLength) + { + setPin(transmitterPin); + m_myRCSwitch.setProtocol(protocol); // set protocol (default is 1, will work for most outlets) + m_myRCSwitch.setRepeatTransmit(repeatTransmits); // set number of transmission repetitions. + m_myRCSwitch.setPulseLength(pulseLength); // Set pulse length. + + } + + //destructor + EX_RCSwitch::~EX_RCSwitch() + { + + } + + void EX_RCSwitch::init() + { + writeStateToPin(); + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH ? F("on") : F("off"))); + } + + void EX_RCSwitch::beSmart(const String &str) + { + String s=str.substring(str.indexOf(' ')+1); + if (st::Executor::debug) { + Serial.print(F("EX_RCSwitch::beSmart s = ")); + Serial.println(s); + } + if(s==F("on")) + { + m_bCurrentState=HIGH; + } + else if(s==F("off")) + { + m_bCurrentState=LOW; + } + + writeStateToPin(); + + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off"))); + } + + void EX_RCSwitch::refresh() + { + Everything::sendSmartString(getName() + " " + (m_bCurrentState == HIGH?F("on"):F("off"))); + } + + void EX_RCSwitch::setPin(byte pin) + { + m_nPin = pin; + m_myRCSwitch.enableTransmit((int)m_nPin); + } +} \ No newline at end of file diff --git a/lib/ST_Anything_RCSwitch/EX_RCSwitch.h b/lib/ST_Anything_RCSwitch/EX_RCSwitch.h new file mode 100644 index 0000000..2a298fa --- /dev/null +++ b/lib/ST_Anything_RCSwitch/EX_RCSwitch.h @@ -0,0 +1,78 @@ +//****************************************************************************************** +// File: EX_RCSwitch.h +// Author: Dan G Ogorchock +// +// Summary: EX_RCSwitch is a class which implements the SmartThings "Switch" device capability. +// It inherits from the st::Executor class. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::EX_RCSwitch executor1("switch1", PIN_RCSWITCH, 35754004, 26, 18976788, 26, 174, 1, 15, LOW); +// +// st::EX_RCSwitch() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - byte transmitterPin - REQUIRED - the Arduino Pin to be used as a digital output for the RCSwitch object's transmitter pin +// - unsigned long onCode - REQUIRED - the "on" code for RCSwitch send() command +// - unsigned int onLength - REQUIRED - the "on" code's length for RCSwitch send() command +// - unsigned long offCode - REQUIRED - the "off" code for RCSwitch send() command +// - unsigned int offLength - REQUIRED - the "off" code's length for RCSwitch send() command +// - unsigned int pulseLength - REQUIRED - the length of the RF pulse for RCSwitch send() command +// - byte protocol - OPTIONAL - defaults to "1" - the protocol for RCSwitch send() command +// - byte repeatTransmits - OPTIONAL - defaults to "15" - the number of repeated transmits for RCSwitch send() command +// - bool startingState - OPTIONAL - the value desired for the initial state of the switch. LOW = "off", HIGH = "on" +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-26 Dan Ogorchock Original Creation +// 2015-05-20 Dan Ogorchock Improved to work with Etekcity ZAP 3F 433Mhz RF Outlets +// 2018-08-30 Dan Ogorchock Modified comment section above to comply with new Parent/Child Device Handler requirements +// +//****************************************************************************************** +#ifndef ST_EX_RCSWITCH +#define ST_EX_RCSWITCH + +#include "RCSwitch.h" +#include "Executor.h" + +namespace st +{ + class EX_RCSwitch: public Executor + { + private: + bool m_bCurrentState; //HIGH or LOW + byte m_nPin; //Arduino Pin used as a RC Transmitter + RCSwitch m_myRCSwitch; //RCSwitch Object + unsigned long m_onCode; //RCSwitch On Code + unsigned int m_onLength; //RCSwitch On Length + unsigned long m_offCode; //RCSwitch Off Code + unsigned int m_offLength; //RCSwitch Off Length + + void writeStateToPin(); //function to update the Arduino digital output pin via RCSwitch switchOn and switchOff commands + + public: + //constructor - called in your sketch's global variable declaration section + EX_RCSwitch(const __FlashStringHelper *name, byte transmitterPin, unsigned long onCode, unsigned int onLength, unsigned long offCode, unsigned int offLength, unsigned int pulseLength, byte protocol = 1, byte repeatTransmits = 15, bool startingState = LOW); + + //destructor + virtual ~EX_RCSwitch(); + + //initialization routine + virtual void init(); + + //SmartThings Shield data handler (receives command to turn "on" or "off" the switch (digital output) + virtual void beSmart(const String &str); + + //called periodically to ensure state of the switch is up to date in the SmartThings Cloud (in case an event is missed) + virtual void refresh(); + + //gets + virtual byte getPin() const {return m_nPin;} + + //sets + virtual void setPin(byte pin); + + }; +} + +#endif \ No newline at end of file diff --git a/lib/ST_Anything_TemperatureHumidity/PS_TemperatureHumidity.cpp b/lib/ST_Anything_TemperatureHumidity/PS_TemperatureHumidity.cpp new file mode 100644 index 0000000..d140692 --- /dev/null +++ b/lib/ST_Anything_TemperatureHumidity/PS_TemperatureHumidity.cpp @@ -0,0 +1,250 @@ +//****************************************************************************************** +// File: PS_TemperatureHumidity.cpp +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_TemperatureHumidity is a class which implements both the SmartThings "Temperature Measurement" +// and "Relative Humidity Measurement" device capabilities. +// It inherits from the st::PollingSensor class. The current version uses a digital input to measure the +// temperature and humidity from a DHT series sensor. This was tested with both the DHT11 and DHT22. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_TemperatureHumidity sensor2(F("temphumid1"), 120, 7, PIN_TEMPERATUREHUMIDITY, st::PS_TemperatureHumidity::DHT22, "temperature1", "humidity1", false); +// +// st::PS_TemperatureHumidity() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - DHT_SENSOR DHTSensorType - REQUIRED - the type of DHT sensor (DHT11, DHT21, DHT22, DHT33, or DHT44) +// - String strTemp - OPTIONAL - name of temperature sensor to send to ST Cloud (defaults to "temperature") +// - String strHumid - OPTIONAL - name of humidity sensor to send to ST Cloud (defaults to "humidity") +// - bool In_C - OPTIONAL - true = Report Celsius, false = Report Farenheit (Farentheit is the default) +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// +// Filtering/Averaging +// +// Filtering the value sent to ST is performed per the following equation +// +// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue) +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-01-17 Dan Ogorchock Added optional temperature and humidity device names in constructor to allow multiple Temp/Humidity sensors +// 2015-01-17 Dan Ogorchock Added optional temperature and humidity device names in constructor to allow multiple Temp/Humidity sensors +// 2015-03-29 Dan Ogorchock Optimized use of the DHT library (made it static) to reduce SRAM memory usage at runtime. +// 2017-06-27 Dan Ogorchock Added optional Celsius reading argument +// 2017-08-17 Dan Ogorchock Added optional filter constant argument and to transmit floating point values to SmartThings +// +//****************************************************************************************** + +#include "PS_TemperatureHumidity.h" + +#include "Constants.h" +#include "Everything.h" +#include + +namespace st +{ +//private + + +//public + //constructor - called in your sketch's global variable declaration section + PS_TemperatureHumidity::PS_TemperatureHumidity(const __FlashStringHelper *name, unsigned int interval, int offset, byte digitalInputPin, DHT_SENSOR DHTSensorType, String strTemp, String strHumid, bool In_C, byte filterConstant) : + PollingSensor(name, interval, offset), + m_fTemperatureSensorValue(-1.0), + m_fHumiditySensorValue(-1.0), + m_bDHTSensorType(DHTSensorType), + m_strTemperature(strTemp), + m_strHumidity(strHumid), + m_In_C(In_C) + { + setPin(digitalInputPin); + + //check for upper and lower limit and adjust accordingly + if ((filterConstant <= 0) || (filterConstant >= 100)) + { + m_fFilterConstant = 1.0; + } + else if (filterConstant <= 5) + { + m_fFilterConstant = 0.05; + } + else + { + m_fFilterConstant = float(filterConstant) / 100; + } + + } + + //destructor + PS_TemperatureHumidity::~PS_TemperatureHumidity() + { + + } + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + void PS_TemperatureHumidity::beSmart(const String &str) + { + String s = str.substring(str.indexOf(' ') + 1); + + if (s.toInt() != 0) { + st::PollingSensor::setInterval(s.toInt() * 1000); + if (st::PollingSensor::debug) { + Serial.print(F("PS_TemperatureHumidity::beSmart set polling interval to ")); + Serial.println(s.toInt()); + } + } + else { + if (st::PollingSensor::debug) + { + Serial.print(F("PS_TemperatureHumidity::beSmart cannot convert ")); + Serial.print(s); + Serial.println(F(" to an Integer.")); + } + } + } + + //initialization routine - get first set of readings and send to ST cloud + void PS_TemperatureHumidity::init() + { + delay(1500); //Needed to prevent "Unknown Error" on first read of DHT Sensor + getData(); + } + + //function to get data from sensor and queue results for transfer to ST Cloud + void PS_TemperatureHumidity::getData() + { + // READ DATA + int8_t chk = 0; + switch (m_bDHTSensorType) { + case DHT11: + //Serial.println(F("PS_TemperatureHumidity: DTH11 Read")); + chk = DHT.read11(m_nDigitalInputPin); + break; + case DHT21: + //Serial.println(F("PS_TemperatureHumidity: DTH21 Read")); + chk = DHT.read21(m_nDigitalInputPin); + break; + case DHT22: + //Serial.println(F("PS_TemperatureHumidity: DTH22 Read")); + chk = DHT.read22(m_nDigitalInputPin); + break; + case DHT33: + //Serial.println(F("PS_TemperatureHumidity: DTH33 Read")); + chk = DHT.read33(m_nDigitalInputPin); + break; + case DHT44: + //Serial.println(F("PS_TemperatureHumidity: DTH44 Read")); + chk = DHT.read44(m_nDigitalInputPin); + break; + default: + Serial.println(F("PS_TemperatureHumidity: Invalid DHT Sensor Type")); + } + + + switch (chk) + { + case DHTLIB_OK: + + //Humidity + if (m_fHumiditySensorValue == -1.0) + { + Serial.println("First time through Humidity"); + m_fHumiditySensorValue = DHT.humidity; //first time through, no filtering + } + else + { + m_fHumiditySensorValue = (m_fFilterConstant * DHT.humidity) + (1 - m_fFilterConstant) * m_fHumiditySensorValue; + } + + //Temperature + if (m_fTemperatureSensorValue == -1.0) + { + Serial.println("First time through Temperature"); + //first time through, no filtering + if (m_In_C == false) + { + m_fTemperatureSensorValue = (DHT.temperature * 1.8) + 32.0; //Scale from Celsius to Farenheit + } + else + { + m_fTemperatureSensorValue = DHT.temperature; + } + } + else + { + if (m_In_C == false) + { + m_fTemperatureSensorValue = (m_fFilterConstant * ((DHT.temperature * 1.8) + 32.0)) + (1 - m_fFilterConstant) * m_fTemperatureSensorValue; + } + else + { + m_fTemperatureSensorValue = (m_fFilterConstant * DHT.temperature) + (1 - m_fFilterConstant) * m_fTemperatureSensorValue; + } + + } + + + break; + case DHTLIB_ERROR_CHECKSUM: + if (st::PollingSensor::debug) { + Serial.println(F("PS_TemperatureHumidity: DHT Checksum error")); + } + break; + case DHTLIB_ERROR_TIMEOUT: + if (st::PollingSensor::debug) { + Serial.println(F("PS_TemperatureHumidity: DHT Time out error")); + } + break; + //case DHTLIB_ERROR_CONNECT: + // if (st::PollingSensor::debug) { + // Serial.println(F("PS_TemperatureHumidity: DHT Connect error")); + // } + // break; + //case DHTLIB_ERROR_ACK_L: + // if (st::PollingSensor::debug) { + // Serial.println(F("PS_TemperatureHumidity: DHT Ack Low error")); + // } + // break; + //case DHTLIB_ERROR_ACK_H: + // if (st::PollingSensor::debug) { + // Serial.println(F("PS_TemperatureHumidity: DHT Ack High error")); + // } + // break; + default: + if (st::PollingSensor::debug) { + Serial.println(F("PS_TemperatureHumidity: DHT Unknown error")); + } + break; + + + } + // DISPLAY DATA + //Serial.print(m_nHumiditySensorValue, 1); + //Serial.print(F(",\t\t")); + //Serial.print(m_nTemperatureSensorValue, 1); + //Serial.println(); + + Everything::sendSmartString(m_strTemperature + " " + String(m_fTemperatureSensorValue)); + Everything::sendSmartString(m_strHumidity + " " + String(m_fHumiditySensorValue)); + } + + void PS_TemperatureHumidity::setPin(byte pin) + { + m_nDigitalInputPin=pin; + } + + + //initialize static members + dht PS_TemperatureHumidity::DHT; //DHT library object +} diff --git a/lib/ST_Anything_TemperatureHumidity/PS_TemperatureHumidity.h b/lib/ST_Anything_TemperatureHumidity/PS_TemperatureHumidity.h new file mode 100644 index 0000000..0bc980c --- /dev/null +++ b/lib/ST_Anything_TemperatureHumidity/PS_TemperatureHumidity.h @@ -0,0 +1,99 @@ +//****************************************************************************************** +// File: PS_TemperatureHumidity.h +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: PS_TemperatureHumidity is a class which implements both the SmartThings "Temperature Measurement" +// and "Relative Humidity Measurement" device capabilities. +// It inherits from the st::PollingSensor class. The current version uses a digital input to measure the +// temperature and humidity from a DHT series sensor. This was tested with both the DHT11 and DHT22. +// +// Create an instance of this class in your sketch's global variable section +// For Example: st::PS_TemperatureHumidity sensor2(F("temphumid1"), 120, 7, PIN_TEMPERATUREHUMIDITY, st::PS_TemperatureHumidity::DHT22, "temperature1", "humidity1", false); +// +// st::PS_TemperatureHumidity() constructor requires the following arguments +// - String &name - REQUIRED - the name of the object - must match the Groovy ST_Anything DeviceType tile name +// - long interval - REQUIRED - the polling interval in seconds +// - long offset - REQUIRED - the polling interval offset in seconds - used to prevent all polling sensors from executing at the same time +// - byte pin - REQUIRED - the Arduino Pin to be used as a digital output +// - DHT_SENSOR DHTSensorType - REQUIRED - the type of DHT sensor (DHT11, DHT21, DHT22, DHT33, or DHT44) +// - String strTemp - OPTIONAL - name of temperature sensor to send to ST Cloud (defaults to "temperature") +// - String strHumid - OPTIONAL - name of humidity sensor to send to ST Cloud (defaults to "humidity") +// - bool In_C - OPTIONAL - true = Report Celsius, false = Report Farenheit (Farentheit is the default) +// - byte filterConstant - OPTIONAL - Value from 5% to 100% to determine how much filtering/averaging is performed 100 = none (default), 5 = maximum +// +// Filtering/Averaging +// +// Filtering the value sent to ST is performed per the following equation +// +// filteredValue = (filterConstant/100 * currentValue) + ((1 - filterConstant/100) * filteredValue) +// +// This class supports receiving configuration data from the SmartThings cloud via the ST App. A user preference +// can be configured in your phone's ST App, and then the "Configure" tile will send the data for all sensors to +// the ST Shield. For PollingSensors, this data is handled in the beSMart() function. +// +// TODO: Determine a method to persist the ST Cloud's Polling Interval data +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2015-01-17 Dan Ogorchock Added optional temperature and humidity device names in constructor to allow multiple Temp/Humidity sensors +// 2015-01-17 Dan Ogorchock Added optional temperature and humidity device names in constructor to allow multiple Temp/Humidity sensors +// 2015-03-29 Dan Ogorchock Optimized use of the DHT library (made it static) to reduce SRAM memory usage at runtime. +// 2017-06-27 Dan Ogorchock Added optional Celsius reading argument +// 2017-08-17 Dan Ogorchock Added optional filter constant argument and to transmit floating point values to SmartThings +// +//****************************************************************************************** + +#ifndef ST_PS_TEMPERATUREHUMIDITY_H +#define ST_PS_TEMPERATUREHUMIDITY_H + +#include "PollingSensor.h" +#include + +namespace st +{ + class PS_TemperatureHumidity: public PollingSensor + { + private: + byte m_nDigitalInputPin; //digital pin connected to the DHT sensor + float m_fTemperatureSensorValue;//current Temperature value + float m_fHumiditySensorValue; //current Humidity Value + static dht DHT; //DHT library object + byte m_bDHTSensorType; //DHT Sensor Type + String m_strTemperature; //name of temparature sensor to use when transferring data to ST Cloud + String m_strHumidity; //name of temparature sensor to use when transferring data to ST Cloud + bool m_In_C; //Return temp in C + float m_fFilterConstant; //Filter constant % as floating point from 0.00 to 1.00 + + public: + //types of DHT sensors supported by the dht library + enum DHT_SENSOR { DHT11, DHT21, DHT22, DHT33, DHT44 }; + + //constructor - called in your sketch's global variable declaration section + PS_TemperatureHumidity(const __FlashStringHelper *name, unsigned int interval, int offset, byte digitalInputPin, DHT_SENSOR DHTSensorType, String strTemp = "temperature1", String strHumid = "humidity1", bool In_C = false, byte filterConstant = 100); + + //destructor + virtual ~PS_TemperatureHumidity(); + + //SmartThings Shield data handler (receives configuration data from ST - polling interval, and adjusts on the fly) + virtual void beSmart(const String &str); + + //initialization routine + virtual void init(); + + //function to get data from sensor and queue results for transfer to ST Cloud + virtual void getData(); + + //gets + inline byte getPin() const { return m_nDigitalInputPin; } + inline float getTemperatureSensorValue() const { return m_fTemperatureSensorValue; } + inline float getHumiditySensorValue() const { return m_fHumiditySensorValue; } + + //sets + void setPin(byte pin); + + }; +} +#endif diff --git a/lib/SmartThings/README.md b/lib/SmartThings/README.md new file mode 100644 index 0000000..8815ef8 --- /dev/null +++ b/lib/SmartThings/README.md @@ -0,0 +1,162 @@ +History: +- v2.0 2017-02-11 Initial Release +- v2.1 2017-02-20 Added support for Arduino + ESP-01 hardware combination +- v2.2 2017-04-26 Added additional optional argument to each constructor which can be queried to determine maximum data transfer rate for each type of communication. This field is not used directly by the SmartThings library. It is used by ST_Anything's Everything Class. +- v2.3 2017-05-25 Added support for the W5500 Ethernet Shield. This required the library to be split into multiple library folders to avoid duplicate class defintions at compile/link time. +- v2.4 2017-08-16 Added support for the ESP32 +- v2.5 2017-01-06 Added Arduino OTA support for the ESP8266 boards + +SmartThings v2.x +================ +This is a new version of the old SmartThings Arduino Library created by SmartThings for use with their Zigbee-based ThingShield. Recently, SmartThings has decided to no longer produce nor support the ThingShield. In an attempt to provide the Maker Community with alternatives, I decided to re-architect the C++ Class hierarchy of the SmartThings library to include continued support for the old ThingShield, as well as adding new support for the Arduino + Ethernet W5100 shield, Arduino + ESP-01 WiFi board, and the standalone NodeMCU ESP8266 and ESP-01 boards. This allows users five options for connecting their DIY projects to SmartThings. + +This library currently implements the following C++ Classes and associated constructors: +-st::SmartThings (base class, not to be used in your sketch!) + -st::SmartThingsThingShield (use this class "#include " if using an Arduino attached to a ESP-01 (AT Firmware) for WiFi) + -st::SmartThingsESP8266WiFi (use this class "#include Examples->SmartThings + - Select the example sketch that matches your hardware + - Select File->Save As and select your "Sketches" folder, and click "Save" + - If using Arduino/W5100, Arduino/ESP-01 or ESP8266, find the lines of the Sketch where it says "<---You must edit this line!" + - The Arduino must be assigned a static TCP/IP address, Gateway, DNS, Subnet Mask, MAC Address (W5100 only), SSID + Password (WiFiEsp + ESP8266 only) + - *** NOTE: If using the W5100 Shield, YOU MUST ASSIGN IT A UNIQUE MAC ADDRESS in the sketch! Please leave the first octet in the MAC Address '06' as certain MAC addresses are UNICAST while others are MULTICAST. Your MAC must be UNICAST and be a 'Locally Administered Address' Please see https://en.wikipedia.org/wiki/MAC_address#Address_details for more information *** + - *** NOTE: If using the W5500 Shield, YOU MUST ASSIGN IT THE MAC ADDRESS that came with the shield in the sketch! + - Note: If using an ESP-01 with an Arduino, the example assumes you're using an Arduino MEGA 2560. Attach the ESP-01 to Hardware Serial "Serial1" *** THE ARDUINO + ESP01 is currently not very stable! + - Your IDE Serial Monitor Window should be set to 9600 baud + - With the Serial Monitor windows open, load your sketch and watch the output + - If using an Arduino/ESP-01, NodeMCU ESP8266 board, ESP-01, or ESP32 the MAC Address will be printed out in the serial monitor window. Write this down as you will need it to configure the Device using your ST App on your phone. (Note: MAC Address must later be entered with no delimeters in the form of "06AB23CD45EF" (without quotes!)) + +##SmartThings IDE Device Handler Installation Instructions +- Create an account and/or log into the SmartThings Developers Web IDE. + +Arduino/ThingShield +- If using a ThingShield, join it to the SmartThings hub by using the ST App on your phone - Add new device +- Install the ThingShield example Device Handler + - Click on "My Device Handlers" from the navigation menu. + - Click on "+ New Device Handler" button. + - Select the "From Code" Tab near the top of the page + - Paste the code from the `On_Off_LED_ThingShield.device.groovy` file from the `..Arduino\libraries\SmartThings\extras` folder + - Click on "Create" near the bottom of the page. + - Click on "Save" in the IDE. + - Click on "Publish" -> "For Me" in the IDE. + - Click on "My Devices" from navigation menu + - Select your "Arduino ThingShield" device from the list + - Click the Edit button at the bottom of the screen + - Change the Type to "On/Off ThingShield" + - Click the Update button at the bottom of the screen + - On your phone, you should now see a device that has simple On/Off tile + +Ethernet Arduino/W5100, Arduino/W5500, Arduino/ESP-01, NodeMCU ESP8266, ESP-01, or ESP32 +- Install the Ethernet example Device Handler + - Click on "+ New Device Handler" button. + - Select the "From Code" Tab near the top of the page + - Paste the code from the `On_Off_LED_Ethernet.device.groovy` file from the `..Arduino\libraries\SmartThings\extras` folder + - Click on "Create" near the bottom of the page. + - Click on "Save" in the IDE. + - Click on "Publish" -> "For Me" in the IDE. + - Click on "My Devices" from navigation menu + - Click on the "+ New Device" button + - Enter a "Name" (whatever you like) + - Enter a "Label" (whatever you like) + - Change the Type to "On/Off Ethernet" + - Change "Version" to "Published" + - Select your "Location" + - Select your "Hub" + - Click "Create" + - On your phone, you should now see a device that has simple "On/Off" tile and a "Configure" tile + - One your phone, after selecting the new device, click on the settings icon (small gear in top right corner) + - Enter your Arduino or ESP8266 device's TCP/IP Address, Port, and MAC Address (you should already know these from when you configured your sketch) + - Note: MAC Address should be entered with no delimeters in the form of "06AB23CD45EF" (no quotes!) + - Click "Done" + - CLick the "Configure" tile to make sure the 'networkDeviceID' for your new ST Device is set to the MAC address you just entered + + - Note: If you're trying to use a ESP-01 WiFi board with an Arduino MEGA, please make sure the ESP-01 is running the "AT Firmware" and figure out the baudrate ahead of time. Please use the examples in the WiFiEsp library to get the ESP-01 wired and working on "Serial1" before attempting to use this library. If you need further help on this, please Google "Arduino MEGA ESP-01" and I am sure you will find some good guides. Also, please note that the Arduino boards really are not rated to power the ESP-01 from the Arduino's 3.3v pin. I had to use an external 3.3v power supply for the ESP-01 to get everything working reliably. Just remember to tie the 3.3v powersupply GND to the Arduino GND. Do NOT connect the +3.3v power supply to the Arduino's 3.3v pin. This would be bad! You may also want to "level shift" the Arduino's 5v Tx pin down to 3.3v before connecting it to the Rx pin on the ESP-01. Some folks online say it is a must, others say the ESP-01 input is 5v tolerant. YMMV. + +. +. +. + +###WARNING - Geeky Material Ahead!!! + +. +. +. + +The following applies only to using the ThingShield! + +If you want to use the new SmartThings v2.x libary with your existing ThingShield sketches (or to just learn more about how all this stuff works, keep reading...) + +Remember to "#include " to use the new v2.x SmartThings library with the ThingShield. + +The Arduino UNO uses the SoftwareSerial library constructor since the UNO has only one Hardware UART port ("Serial") which is used by the USB port for programming and debugging. +Arduino UNO R3 SoftwareSerial: +- Use the NEW SoftwareSerial constructor passing in pinRX=3 and pinTX=2 + - st::SmartThingsThingShield(uint8_t pinRX, uint8_t pinTX, SmartThingsCallout_t *callout) call. +- Make sure the ThingShield's switch in the "D2/D3" position +- Be certain to not use Pins 2 & 3 in your Arduino sketch for I/O since they are electrically connected to the ThingShield. Pin6 is also reserved by the ThingShield. Best to avoid using it. Also, pins 0 & 1 are used for USB communications, so do not use them if possible. + +The new v2.x SmartThings ThingShield library automatically disables support for Software Serial if using a Leonardo or MEGA based Arduino board. + +The Arduino MEGA 2560 must use HardwareSerial "Serial1, Serial2, or Serial3" for communications with the ThingShield. +MEGA 2560 Hardware Serial: +- Use the new Hardware Serial constructor passing in a pointer to a Hardware Serial device (&Serial1, &Serial2, &Serial3) + - definition st::SmartThingsThingShield(HardwareSerial* serial, SmartThingsCallout_t *callout); + - sample st::SmartThingsThingShield(&Serial3, callout); +- Make sure the ThingShield's switch in the "D2/D3" position +- Be certain to not use Pins 2 & 3 in your Arduino sketch for I/O since they are electrically connected to the ThingShield. Pin6 is also reserved by the ThingShield. Best to avoid using it. +- On the MEGA, Serial1 uses pins 18/19, Serial2 uses pins 16/17, and Serial3 uses pins 14/15 +- You will need to wire the MEGA's HardwareSerial port's pins to pins 2 & 3 on the ThingShield. For example, using Serial3, wire Pin 2 to Pin 14 AND Pin3 to Pin 15. + +The Arduino Leonardo must use HardwareSerial "Serial1" for communications with the ThingShield. +Leonardo Hardware Serial: +- Use the new Hardware Serial constructor passing in a pointer to a Hardware Serial device (&Serial1) + - definition st::SmartThingsThingShield(HardwareSerial* serial, SmartThingsCallout_t *callout); + - sample st::SmartThingsThingShield(&Serial1, callout); +- Make sure the ThingShield's switch in the "D0/D1" position +- Be certain to not use Pins 0 & 1 in your Arduino sketch for I/O since they are electrically connected to the ThingShield. Pin6 is also reserved by the ThingShield. Best to avoid using it. + + + diff --git a/lib/SmartThings/SmartThings.cpp b/lib/SmartThings/SmartThings.cpp new file mode 100644 index 0000000..c79c0a1 --- /dev/null +++ b/lib/SmartThings/SmartThings.cpp @@ -0,0 +1,34 @@ +//******************************************************************************* +// SmartThings Arduino Library Base Class +// +// License +// (C) Copyright 2017 Dan Ogorchock +// +// History +// 2017-02-04 Dan Ogorchock Created +//******************************************************************************* +#include + +namespace st +{ + //******************************************************************************* + // SmartThings Constructor + //******************************************************************************* + SmartThings::SmartThings(SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + _calloutFunction(callout), + _shieldType(shieldType), + _isDebugEnabled(enableDebug), + m_nTransmitInterval(transmitInterval) + { + + } + + //***************************************************************************** + //SmartThings::~SmartThings() + //***************************************************************************** + SmartThings::~SmartThings() + { + + } + +} diff --git a/lib/SmartThings/SmartThings.h b/lib/SmartThings/SmartThings.h new file mode 100644 index 0000000..dbdd431 --- /dev/null +++ b/lib/SmartThings/SmartThings.h @@ -0,0 +1,67 @@ +//******************************************************************************* +// SmartThings Arduino Library Base Class +// +// License +// (C) Copyright 2017 Dan Ogorchock +// +// History +// 2017-02-04 Dan Ogorchock Created +//******************************************************************************* +#ifndef __SMARTTHINGS_H__ +#define __SMARTTHINGS_H__ + +#include + +//******************************************************************************* +// Callout Function Definition for Messages Received from SmartThings +//******************************************************************************* +typedef void SmartThingsCallout_t(String message); + +namespace st +{ + class SmartThings + { + private: + + protected: + SmartThingsCallout_t *_calloutFunction; + bool _isDebugEnabled; + String _shieldType; + int m_nTransmitInterval; + + public: + + //******************************************************************************* + // SmartThings Constructor + //******************************************************************************* + SmartThings(SmartThingsCallout_t *callout, String shieldType = "Unknown", bool enableDebug = false, int transmitInterval = 100); + + //******************************************************************************* + // SmartThings Destructor + //******************************************************************************* + virtual ~SmartThings(); + + //******************************************************************************* + /// Initialize SmartThings Library + //******************************************************************************* + virtual void init(void) = 0; //all derived classes must implement this pure virtual function + + //******************************************************************************* + /// Run SmartThings Library + //******************************************************************************* + virtual void run(void) = 0; //all derived classes must implement this pure virtual function + + //******************************************************************************* + /// Send Message to the Hub + //******************************************************************************* + virtual void send(String message) = 0; //all derived classes must implement this pure virtual function + + //******************************************************************************* + /// Send Message to the Hub + //******************************************************************************* + virtual int getTransmitInterval() const { return m_nTransmitInterval; } + + }; + +} +#endif diff --git a/lib/SmartThings/SmartThingsEthernet.cpp b/lib/SmartThings/SmartThingsEthernet.cpp new file mode 100644 index 0000000..0a5090b --- /dev/null +++ b/lib/SmartThings/SmartThingsEthernet.cpp @@ -0,0 +1,67 @@ +//******************************************************************************* +// SmartThings Arduino Ethernet Library +// +// License +// (C) Copyright 2017 Dan Ogorchock +// +// History +// 2017-02-04 Dan Ogorchock Created +//******************************************************************************* + +#include "SmartThingsEthernet.h" + +namespace st +{ + //******************************************************************************* + // SmartThingsEthernet Constructor - Static IP + //******************************************************************************* + SmartThingsEthernet::SmartThingsEthernet(IPAddress localIP, IPAddress localGateway, IPAddress localSubnetMask, IPAddress localDNSServer, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval, bool DHCP) : + SmartThings(callout, shieldType, enableDebug, transmitInterval), + st_localIP(localIP), + st_localGateway(localGateway), + st_localSubnetMask(localSubnetMask), + st_localDNSServer(localDNSServer), + st_hubIP(hubIP), + st_serverPort(serverPort), + st_hubPort(hubPort), + st_DHCP(DHCP) + { + + } + + //******************************************************************************* + // SmartThingsEthernet Constructor - Static IP (Abbreviated version for WiFiEsp library) + //******************************************************************************* + SmartThingsEthernet::SmartThingsEthernet(IPAddress localIP, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval, bool DHCP) : + SmartThings(callout, shieldType, enableDebug, transmitInterval), + st_localIP(localIP), + st_hubIP(hubIP), + st_serverPort(serverPort), + st_hubPort(hubPort), + st_DHCP(DHCP) + { + + } + + //******************************************************************************* + // SmartThingsEthernet Constructor - DHCP + //******************************************************************************* + SmartThingsEthernet::SmartThingsEthernet(uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval, bool DHCP) : + SmartThings(callout, shieldType, enableDebug, transmitInterval), + st_hubIP(hubIP), + st_serverPort(serverPort), + st_hubPort(hubPort), + st_DHCP(DHCP) + { + + } + + //***************************************************************************** + //SmartThingsEthernet::~SmartThingsEthernet() + //***************************************************************************** + SmartThingsEthernet::~SmartThingsEthernet() + { + + } + +} diff --git a/lib/SmartThings/SmartThingsEthernet.h b/lib/SmartThings/SmartThingsEthernet.h new file mode 100644 index 0000000..454c3c4 --- /dev/null +++ b/lib/SmartThings/SmartThingsEthernet.h @@ -0,0 +1,106 @@ +//******************************************************************************* +// SmartThings Arduino Ethernet Library +// +// License +// (C) Copyright 2017 Dan Ogorchock +// +// History +// 2017-02-04 Dan Ogorchock Created +// 2017-05-02 Dan Ogorchock Add support for W5500 Ethernet2 Shield +// 2018-01-06 Dan Ogorchock Added RSSI Interval as user-definable interval +// 2020-07-26 Dan Ogorchock Changed the final RSSI interval from 60 seconds to 900 seconds +//******************************************************************************* + +#ifndef __SMARTTHINGSETHERNET_H__ +#define __SMARTTHINGSETHERNET_H__ + +#include "SmartThings.h" + +//Adjust the RSSI Transmit Interval below as you see fit (in milliseconds) +// Note: When the board first boots, it transmits frequently, then slows over +// time to the interval below. +#define RSSI_TX_INTERVAL 900000 + +//******************************************************************************* +// Using Ethernet Shield +//******************************************************************************* +#include +/* +//#if defined ARDUINO_ARCH_AVR +//#include +//#include +//#elif defined ARDUINO_ARCH_ESP8266 +//#include +//#endif +*/ +namespace st +{ + class SmartThingsEthernet: public SmartThings + { + private: + + protected: + IPAddress st_localIP; + IPAddress st_localGateway; + IPAddress st_localSubnetMask; + IPAddress st_localDNSServer; + IPAddress st_hubIP; + uint16_t st_serverPort; + uint16_t st_hubPort; + bool st_DHCP; + + public: + + //******************************************************************************* + /// @brief SmartThings Ethernet Constructor - STATIC + /// @param[in] localIP - TCP/IP Address of the Arduino + /// @param[in] localGateway - TCP/IP Gateway Address of local LAN (your Router's LAN Address) + /// @param[in] localSubnetMask - Subnet Mask of the Arduino + /// @param[in] localDNSServer - DNS Server + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsEthernet(IPAddress localIP, IPAddress localGateway, IPAddress localSubnetMask, IPAddress localDNSServer, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "EthernetShield", bool enableDebug = false, int transmitInterval = 100, bool DHCP = false); + + //Abrreviated STATIC version for Arduino + ESP-01 WiFiEsp library (no Gateway, Subnet Mask, or DNS can be user provided) + SmartThingsEthernet(IPAddress localIP, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "EthernetShield", bool enableDebug = false, int transmitInterval = 100, bool DHCP = false); + + //******************************************************************************* + /// @brief SmartThings Ethernet Constructor - DHCP + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsEthernet(uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "EthernetShield", bool enableDebug = false, int transmitInterval = 100, bool DHCP = true); + + //******************************************************************************* + /// Destructor + //******************************************************************************* + ~SmartThingsEthernet(); + + //******************************************************************************* + /// Initialize SmartThings Library + //******************************************************************************* + virtual void init(void) = 0; //all derived classes must implement this pure virtual function + + //******************************************************************************* + /// Run SmartThings Library + //******************************************************************************* + virtual void run(void) = 0; //all derived classes must implement this pure virtual function + + //******************************************************************************* + /// Send Message to the Hub + //******************************************************************************* + virtual void send(String message) = 0; //all derived classes must implement this pure virtual function + + + }; +} +#endif diff --git a/lib/SmartThings/SmartThingsThingShield.cpp b/lib/SmartThings/SmartThingsThingShield.cpp new file mode 100644 index 0000000..d401314 --- /dev/null +++ b/lib/SmartThings/SmartThingsThingShield.cpp @@ -0,0 +1,538 @@ +//******************************************************************************* +/// @file +/// @brief +/// SmartThingsThingShield Arduino Library +/// @section License +/// (C) Copyright 2013 Physical Graph +/// +/// Updates by Daniel Ogorchock 12/30/2014 - Arduino Mega 2560 HW Serial support +/// -Numerous performance and size optimizations (helpful on UNO with only 2K SRAM) +/// -Arduino UNO should use the SoftwareSerial library Constructor since the UNO has +/// only one Hardware UART port ("Serial") which is used by the USB port for +/// programming and debugging typically. UNO can use the Hardware "Serial" +/// if desired, but USB programming and debug will be troublesome. +/// Leonardo and Mega can use SoftwareSerial BUT cannot use Pin3 for Rx - use +/// Pin10 for Rx and add jumper from Pin10 to Pin3. +/// -Arduino LEONARDO should use the Hardware Serial Constructor since it has 1 UART +/// separate from the USB port. "Serial1" port uses pins 0(Rx) and 1(Tx). +/// -Arduino MEGA should use the Hardware Serial Constructor since it has 4 UARTs. +/// "Serial3" port uses pins 14(Tx) and 15(Rx). Wire Pin14 to Pin2 and Pin15 to Pin3. +/// -Be certain to not use Pins 2 & 3 in your Arduino sketch for I/O since they are +/// electrically connected to the ThingShield if set to D2/D3. +/// -Note - Pin6 is reserved by the ThingShield as well. Best to avoid using it. +/// -The SoftwareSerial library has the following known limitations: +/// - If using multiple software serial ports, only one can receive data at a time. +/// - Not all pins on the Mega and Mega 2560 support change interrupts, so only +/// the following can be used for RX: 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, +/// A8(62), A9(63), A10(64), A11(65), A12(66), A13(67), A14(68), A15(69). +/// - Not all pins on the Leonardo and Micro support change interrupts, so only +/// the following can be used for RX : 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). +/// -2016-06-04 Dan Ogorchock Added improved support for Arduino Leonardo +/// -2017-02-04 Dan Ogorchock Modified to be a subclass of new SmartThings base class +/// -2017-02-08 Dan Ogorchock Cleaned up. Now uses HardwareSerial* objects directly. +//******************************************************************************* +#include "SmartThingsThingShield.h" + +namespace st +{ + //***************************************************************************** + void SmartThingsThingShield::debugPrintBuffer(String prefix, uint8_t * pBuf, uint_fast8_t nBuf) + { + if (_isDebugEnabled) + { + Serial.print(prefix); + for (uint_fast8_t i = 0; i < nBuf; i++) + { + Serial.print(char(pBuf[i])); + } + Serial.println(); + } + } + + //***************************************************************************** + bool SmartThingsThingShield::isRxLine(uint8_t * pLine) + { + // line starts with "T00000000:RX" + return ((pLine[0] == 'T') && (pLine[9] == ':') && (pLine[10] == 'R') && (pLine[11] == 'X')); + } + + //******************************************************************************* + bool SmartThingsThingShield::isAsciiHex(uint8_t ascii) + { + bool retVal = false; + if ( + ((ascii >= 'A') && (ascii <= 'F')) || + ((ascii >= 'a') && (ascii <= 'f')) || + ((ascii >= '0') && (ascii <= '9')) + ) + { + retVal = true; + } + return retVal; + } + + //******************************************************************************* + /// @note this function doesn't check for hex validity before converting + //******************************************************************************* + uint8_t SmartThingsThingShield::asciiToHexU8(uint8_t pAscii[2]) + { + uint8_t hex; + hex = ((pAscii[0] - (((pAscii[0] >> 6) & 0x1) * 0x37)) & 0xF); + hex <<= 4; + hex |= ((pAscii[1] - (((pAscii[1] >> 6) & 0x1) * 0x37)) & 0xF); + return hex; + } + + //***************************************************************************** + uint_fast8_t SmartThingsThingShield::translatePayload(uint8_t *pBuf, uint_fast8_t nBuf) + { + uint_fast8_t payloadLength = 0; // return value + uint_fast8_t payloadStart = 0; + uint_fast8_t payloadEnd = 0; + + uint_fast8_t i; + + // find [ ] message from the back of the message + for (i = nBuf - 1; i > 0; i--) + { + if (pBuf[i] == ']') + { + payloadEnd = i; + } + else if (pBuf[i] == '[') + { + payloadStart = i; + break; + } + } + + if (_isDebugEnabled) + { + Serial.print(F("payload start: ")); + Serial.print(payloadStart); + Serial.print(F(" end: ")); + Serial.print(payloadEnd); + Serial.print(F(" : ")); + for (i = payloadStart + 1; i < payloadEnd; i++) + { + Serial.print(pBuf[i]); + Serial.print(' '); + } + Serial.println(); + } + + if ((payloadStart != 0) && (payloadEnd != 0) && (payloadEnd - payloadStart > 4) && (pBuf[payloadStart + 1] == '0') && (pBuf[payloadStart + 2] == 'A')) + { // if valid message then parse + i = payloadStart + 4; // start+3 should be ' ' + while (i < payloadEnd) + { + if (pBuf[i] != ' ') + { + if (isAsciiHex(pBuf[i]) && isAsciiHex(pBuf[i + 1])) + { + pBuf[payloadLength++] = asciiToHexU8(&(pBuf[i++])); + } + } + i++; + } + } + + pBuf[payloadLength] = 0x0; // null-terminate the string + return payloadLength; + } + + //***************************************************************************** + void SmartThingsThingShield::_process(void) + { + uint32_t nowMilliseconds = millis(); + + if ((nowMilliseconds < _lastShieldMS) || ((nowMilliseconds - _lastShieldMS) > 5000)) + { + _shieldGetNetworkInfo(); + _lastShieldMS = nowMilliseconds; + } + else if ((_networkState == STATE_JOINED) && + ((nowMilliseconds < _lastPingMS) || ((nowMilliseconds - _lastPingMS) > 60000))) + { // ping every minutes or on rollover + send("ping"); + _lastPingMS = nowMilliseconds; + } + } + + //***************************************************************************** + void SmartThingsThingShield::handleLine(void) + { + if (_nBufRX > 0) + { + if (isRxLine(_pBufRX)) + { + debugPrintBuffer("->| ", _pBufRX, _nBufRX); + { + uint_fast8_t messageBufLength = translatePayload(_pBufRX, _nBufRX); + + if (messageBufLength > 0) + { + debugPrintBuffer("->| payload :: ", (uint8_t *)_pBufRX, messageBufLength); + + _calloutFunction(String((char *)_pBufRX)); // call out to main application + } + else + { + debugPrintBuffer("->| no payload from :: ", _pBufRX, _nBufRX); + } + } + } + else + { //XXX Totally slapped together since this is temp-- will go away with command set change + uint_fast8_t i = 0; + bool found = false; + if (_nBufRX >= 32) //netinfo:0022A3000000B675,E30E,02 + { + while (i < _nBufRX) + { + if ( + (_pBufRX[i] == 'n') && + (_pBufRX[i + 1] == 'e') && + (_pBufRX[i + 2] == 't') && + (_pBufRX[i + 3] == 'i') && + (_pBufRX[i + 4] == 'n') && + (_pBufRX[i + 5] == 'f') && + (_pBufRX[i + 6] == 'o') && + (_pBufRX[i + 7] == ':') && + (_pBufRX[i + 24] == ',') && + (_pBufRX[i + 29] == ',') + ) + { + // parse off EUI + if ( + isAsciiHex(_pBufRX[i + 8]) && + isAsciiHex(_pBufRX[i + 9]) && + isAsciiHex(_pBufRX[i + 10]) && + isAsciiHex(_pBufRX[i + 11]) && + isAsciiHex(_pBufRX[i + 12]) && + isAsciiHex(_pBufRX[i + 13]) && + isAsciiHex(_pBufRX[i + 14]) && + isAsciiHex(_pBufRX[i + 15]) && + isAsciiHex(_pBufRX[i + 16]) && + isAsciiHex(_pBufRX[i + 17]) && + isAsciiHex(_pBufRX[i + 18]) && + isAsciiHex(_pBufRX[i + 19]) && + isAsciiHex(_pBufRX[i + 20]) && + isAsciiHex(_pBufRX[i + 21]) && + isAsciiHex(_pBufRX[i + 22]) && + isAsciiHex(_pBufRX[i + 23]) && + + isAsciiHex(_pBufRX[i + 25]) && + isAsciiHex(_pBufRX[i + 26]) && + isAsciiHex(_pBufRX[i + 27]) && + isAsciiHex(_pBufRX[i + 28]) && + + isAsciiHex(_pBufRX[i + 30]) && + isAsciiHex(_pBufRX[i + 31]) + ) + { + uint8_t tempNetStat = asciiToHexU8(&(_pBufRX[i + 30])); + if (tempNetStat <= STATE_LEAVING) // make sure it maps to the enum + { + _networkState = (SmartThingsNetworkState_t)tempNetStat; + + _nodeID = asciiToHexU8(&(_pBufRX[i + 25])); + _nodeID <<= 8; + _nodeID |= asciiToHexU8(&(_pBufRX[i + 27])); + + _eui64[7] = asciiToHexU8(&(_pBufRX[i + 8])); + _eui64[6] = asciiToHexU8(&(_pBufRX[i + 10])); + _eui64[5] = asciiToHexU8(&(_pBufRX[i + 12])); + _eui64[4] = asciiToHexU8(&(_pBufRX[i + 14])); + _eui64[3] = asciiToHexU8(&(_pBufRX[i + 16])); + _eui64[2] = asciiToHexU8(&(_pBufRX[i + 18])); + _eui64[1] = asciiToHexU8(&(_pBufRX[i + 20])); + _eui64[0] = asciiToHexU8(&(_pBufRX[i + 22])); + + debugPrintBuffer(" |~> ", &(_pBufRX[i]), 32); + found = true; + } + } + } + i++; + } + } + if (found == false) + debugPrintBuffer("->| IGNORING :: ", _pBufRX, _nBufRX); + } + _nBufRX = 0; + } + } + //***************************************************************************** + void SmartThingsThingShield::_shieldGetNetworkInfo(void) + { + _mySerial->print(F("custom netinfo\n")); + + if (_isDebugEnabled) + { + Serial.print(F(" |<~ custom netinfo\n")); + } + } + + //***************************************************************************** + // Thing API | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + // V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V + //***************************************************************************** + + // SoftwareSerial Constructor +#ifndef DISABLE_SOFTWARESERIAL + SmartThingsThingShield::SmartThingsThingShield(uint8_t pinRX, uint8_t pinTX, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThings(callout, shieldType, enableDebug, transmitInterval), + //_SerialPort(SW_SERIAL), + _lastPingMS(0xFFFFFF00), + _lastShieldMS(0xFFFFFF00), + _networkState(STATE_UNKNOWN), + _nBufRX(0) + { + _mySerial = new SoftwareSerial(pinRX, pinTX); + _mySerial->begin(2400); + } +#else + //Hardware Serial Constructor + SmartThingsThingShield::SmartThingsThingShield(HardwareSerial* hwSerialPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThings(callout, shieldType, enableDebug, transmitInterval), + _mySerial(hwSerialPort), + _lastPingMS(0xFFFFFF00), + _lastShieldMS(0xFFFFFF00), + _networkState(STATE_UNKNOWN), + _nBufRX(0) + { +// _isDebugEnabled = hwSerialPort != Serial ? enableDebug : false; //Do not allow debug print statements if using Hardware Serial (pins 0,1) for ST Communications + _mySerial->begin(2400); + } +#endif + //***************************************************************************** + //SmartThings::~SmartThings() + SmartThingsThingShield::~SmartThingsThingShield() + { + } + + //******************************************************************************* + /// Initialize SmartThings Thingshield Library + //******************************************************************************* + void SmartThingsThingShield::init(void) + { + unsigned long tmpTime = millis(); + do + { + //updateNetworkState(); + run(); + delay(10); + updateNetworkState(); + } while ((_networkState != STATE_JOINED) && ((millis() - tmpTime) < 5000)); + + if (_isDebugEnabled) + { + if (_networkState != STATE_JOINED) + { + Serial.println(F("SmartThingsThingShield: Intialization timed out waiting for shield to connect.")); + } + else + { + Serial.println(F("SmartThingsThingShield: Intialization Successful. Shield connected.")); + } + } + } + + + //***************************************************************************** + void SmartThingsThingShield::run(void) + { + uint8_t readByte; + + while ((_nBufRX < SMARTTHINGS_RX_BUFFER_SIZE) && _mySerial->available()) + { + + readByte = _mySerial->read(); + + if ((readByte == 0x0D) || (readByte == 0x0A)) + { // handle data from SmartThing Hub line-by-line, execute user's callback function for each line + handleLine(); + } + else + { + // keep track of everything that comes in until we reach a newline + // TODO(cwvh): validate bufferlength 1988-10-19 + //if (_nBufRX > 200) + // panic("too many characters!"); + _pBufRX[_nBufRX++] = readByte; + } + + } + _process(); + } + + //***************************************************************************** + void SmartThingsThingShield::send(String message) + { + // e.g. thing.print("raw 0x0 {00 00 0A 0A 62 75 74 74 6f 6e 20 64 6f 77 6e }"); + _mySerial->print(F("raw 0x0 { 00 00 0A 0A ")); + + if (_isDebugEnabled) + { + Serial.print(F("<-| raw 0x0 { 00 00 0A 0A ")); + } + + for (int i = 0; i < message.length(); i++) + { + _mySerial->print(message[i], HEX); + _mySerial->print(' '); + + if (_isDebugEnabled) + { + Serial.print(message[i], HEX); + Serial.print(' '); + } + } + + _mySerial->print(F("}\nsend 0x0 1 1\n")); + + if (_isDebugEnabled) + { + Serial.print(F("}\nsend 0x0 1 1\n")); + } + } + + //***************************************************************************** + void SmartThingsThingShield::shieldSetLED(uint8_t red, uint8_t green, uint8_t blue) + { + if (red > 9) red = 9; + if (green > 9) green = 9; + if (blue > 9) blue = 9; + + _mySerial->print(F("custom rgb ")); + _mySerial->write((red + '0')); + _mySerial->print(' '); + _mySerial->write((green + '0')); + _mySerial->print(' '); + _mySerial->write((blue + '0')); + _mySerial->print(F(" \n")); + + if (_isDebugEnabled) + { + Serial.print(F(" |<~ custom rgb ")); + Serial.write(red + '0'); + Serial.print(' '); + Serial.write(green + '0'); + Serial.print(' '); + Serial.write(blue + '0'); + Serial.print(F(" \n")); + } + } + + + //***************************************************************************** + SmartThingsNetworkState_t SmartThingsThingShield::shieldGetLastNetworkState(void) + { + return _networkState; + } + + //***************************************************************************** + SmartThingsNetworkState_t SmartThingsThingShield::shieldGetNetworkState(void) + { + _shieldGetNetworkInfo(); + return _networkState; + } + + //***************************************************************************** + uint16_t SmartThingsThingShield::shieldGetNodeID(void) + { + _shieldGetNetworkInfo(); + return _nodeID; + } + + //***************************************************************************** + void SmartThingsThingShield::shieldGetEUI64(uint8_t eui[8]) + { + _shieldGetNetworkInfo(); + { + uint_fast8_t i = 7; + do + { + eui[i] = _eui64[i]; + } while (i--); + } + } + + //***************************************************************************** + void SmartThingsThingShield::shieldFindNetwork(void) + { + _mySerial->print(F("custom find\n")); + + if (_isDebugEnabled) + { + Serial.print(F(" |<~ custom find\n")); + + } + } + + //***************************************************************************** + void SmartThingsThingShield::shieldLeaveNetwork(void) + { + _mySerial->print(F("custom leave\n")); + + + if (_isDebugEnabled) + { + Serial.print(F(" |<~ custom leave\n")); + } + } + + //******************************************************************************* + // Update the network State/LED + //******************************************************************************* + void SmartThingsThingShield::updateNetworkState() //get the current zigbee network status of the ST Shield + { + static SmartThingsNetworkState_t tempState = shieldGetLastNetworkState(); + + if (_isDebugEnabled) + { + Serial.println(F("Called updateNetworkState()")); + } + + if (tempState != _networkState) + { + if (_isDebugEnabled) + { + Serial.print(F("Called updateNetworkState() tmpState =")); + Serial.println(tempState); + } + + switch (_networkState) + { + case STATE_NO_NETWORK: + if (_isDebugEnabled) Serial.println(F("Everything: NO_NETWORK")); + shieldSetLED(2, 0, 0); // red + break; + case STATE_JOINING: + if (_isDebugEnabled) Serial.println(F("Everything: JOINING")); + shieldSetLED(2, 0, 0); // red + break; + case STATE_JOINED: + if (_isDebugEnabled) Serial.println(F("Everything: JOINED")); + shieldSetLED(0, 0, 0); // off + break; + case STATE_JOINED_NOPARENT: + if (_isDebugEnabled) Serial.println(F("Everything: JOINED_NOPARENT")); + shieldSetLED(2, 0, 2); // purple + break; + case STATE_LEAVING: + if (_isDebugEnabled) Serial.println(F("Everything: LEAVING")); + shieldSetLED(2, 0, 0); // red + break; + default: + case STATE_UNKNOWN: + if (_isDebugEnabled) Serial.println(F("Everything: UNKNOWN")); + shieldSetLED(0, 2, 0); // green + break; + } + _networkState = tempState; + } + } + +} \ No newline at end of file diff --git a/lib/SmartThings/SmartThingsThingShield.h b/lib/SmartThings/SmartThingsThingShield.h new file mode 100644 index 0000000..4cb9c39 --- /dev/null +++ b/lib/SmartThings/SmartThingsThingShield.h @@ -0,0 +1,212 @@ +//******************************************************************************* +/// @file +/// @brief +/// SmartThingsThingShield Arduino Library +/// @section License +/// (C) Copyright 2013 Physical Graph +/// +/// Updates by Daniel Ogorchock 12/30/2014 - Arduino Mega 2560 HW Serial support +/// -Numerous performance and size optimizations (helpful on UNO with only 2K SRAM) +/// -Arduino UNO should use the SoftwareSerial library Constructor since the UNO has +/// only one Hardware UART port ("Serial") which is used by the USB port for +/// programming and debugging typically. UNO can use the Hardware "Serial" +/// if desired, but USB programming and debug will be troublesome. +/// Leonardo and Mega can use SoftwareSerial BUT cannot use Pin3 for Rx - use +/// Pin10 for Rx and add jumper from Pin10 to Pin3. +/// -Arduino LEONARDO should use the Hardware Serial Constructor since it has 1 UART +/// separate from the USB port. "Serial1" port uses pins 0(Rx) and 1(Tx). +/// -Arduino MEGA should use the Hardware Serial Constructor since it has 4 UARTs. +/// "Serial3" port uses pins 14(Tx) and 15(Rx). Wire Pin14 to Pin2 and Pin15 to Pin3. +/// -Be certain to not use Pins 2 & 3 in your Arduino sketch for I/O since they are +/// electrically connected to the ThingShield if set to D2/D3. +/// -Note - Pin6 is reserved by the ThingShield as well. Best to avoid using it. +/// -The SoftwareSerial library has the following known limitations: +/// - If using multiple software serial ports, only one can receive data at a time. +/// - Not all pins on the Mega and Mega 2560 support change interrupts, so only +/// the following can be used for RX: 10, 11, 12, 13, 14, 15, 50, 51, 52, 53, +/// A8(62), A9(63), A10(64), A11(65), A12(66), A13(67), A14(68), A15(69). +/// - Not all pins on the Leonardo and Micro support change interrupts, so only +/// the following can be used for RX : 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). +/// -2016-06-04 Dan Ogorchock Added improved support for Arduino Leonardo +/// -2017-02-04 Dan Ogorchock Modified to be a subclass of new SmartThings base class +/// -2017-02-08 Dan Ogorchock Cleaned up. Now uses HardwareSerial* objects directly. +/// -2017-08-14 Dan Ogorchock Disabled SoftwareSerial support if compiling ESP32 board +//******************************************************************************* +#ifndef __SMARTTHINGS_THINGSHIELD_H__ +#define __SMARTTHINGS_THINGSHIELD_H__ + +#include "SmartThings.h" + +//******************************************************************************* +#define BOARD_TYPE_UNO 0 +#define BOARD_TYPE_LEONARDO 1 +#define BOARD_TYPE_MEGA 2 +//******************************************************************************* + +#include + +//******************************************************************************* +// Set the correct board type automatically +//******************************************************************************* +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) +#define BOARD_TYPE BOARD_TYPE_UNO +//#define DISABLE_SOFTWARESERIAL // uncomment to disable SoftwareSerial to save some program space if neccessary while using HW Serial +#elif defined(__AVR_ATmega32U4__) +#define BOARD_TYPE BOARD_TYPE_LEONARDO +#define DISABLE_SOFTWARESERIAL //Assume HW Serial is being used. Saves some program space while using HW Serial +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#define BOARD_TYPE BOARD_TYPE_MEGA +#define DISABLE_SOFTWARESERIAL //Assume HW Serial is being used. Saves some program space while using HW Serial +#elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_ESP32) +#define DISABLE_SOFTWARESERIAL //The SAMD chip (e.g. MKR1000) and ESP32 do not support SoftwareSerial +#else //assume user is using an UNO for the unknown case +#define BOARD_TYPE BOARD_TYPE_UNO +//#define DISABLE_SOFTWARESERIAL // uncomment to disable SoftwareSerial to save some program space if neccessary while using HW Serial +#endif + +#ifndef DISABLE_SOFTWARESERIAL +#include +#endif + +//******************************************************************************* +#define SMARTTHINGS_RX_BUFFER_SIZE 256 // if > 255: change _nBufRX to u16 +#define SMARTTHINGS_SHIELDTYPE_SIZE 32 // if > 255: change _shieldTypeLen to u16 + +namespace st +{ + //******************************************************************************* + /// @brief ZigBee Network State Definition + //******************************************************************************* + typedef enum + { + STATE_NO_NETWORK, + STATE_JOINING, + STATE_JOINED, + STATE_JOINED_NOPARENT, + STATE_LEAVING, + STATE_UNKNOWN + } SmartThingsNetworkState_t; + + //******************************************************************************* + + class SmartThingsThingShield: public SmartThings + { + private: +#ifndef DISABLE_SOFTWARESERIAL + SoftwareSerial* _mySerial; +#else + HardwareSerial* _mySerial; +#endif + //SmartThingsSerialType_t _SerialPort; + + uint32_t _lastPingMS; + uint32_t _lastShieldMS; + SmartThingsNetworkState_t _networkState; + uint8_t _eui64[8]; + uint16_t _nodeID; + + uint8_t _pBufRX[SMARTTHINGS_RX_BUFFER_SIZE]; + uint_fast8_t _nBufRX; + + void _shieldGetNetworkInfo(void); + void _process(void); + + void debugPrintBuffer(String prefix, uint8_t * pBuf, uint_fast8_t nBuf); + bool isRxLine(uint8_t * pLine); + bool isAsciiHex(uint8_t ascii); + uint8_t asciiToHexU8(uint8_t pAscii[2]); + uint_fast8_t translatePayload(uint8_t *pBuf, uint_fast8_t nBuf); + void handleLine(void); + + public: + //******************************************************************************* + /// @brief SmartThings SoftwareSerial Constructor + /// @param[in] pinRX - Receive Pin for the SoftwareSerial Port to the Arduino + /// @param[in] pinTX - Transmit Pin for the SoftwareSerial Port to the Arduino + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* +#ifndef DISABLE_SOFTWARESERIAL + SmartThingsThingShield(uint8_t pinRX, uint8_t pinTX, SmartThingsCallout_t *callout, String shieldType = "ThingShield", bool enableDebug = false, int transmitInterval = 1000); +#else + //******************************************************************************* + /// @brief SmartThings HardwareSerial Constructor + /// @param[in] hwSerialPort - HardwareSerial Port of the Arduino (i.e. &Serial, &Serial1, &Serial2, &Serial3) + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsThingShield(HardwareSerial* hwSerialPort, SmartThingsCallout_t *callout, String shieldType = "ThingShield", bool enableDebug = false, int transmitInterval = 1000); +#endif + //******************************************************************************* + /// @brief Destructor + //******************************************************************************* + virtual ~SmartThingsThingShield(); + + //******************************************************************************* + /// @brief Initialize SmartThings Library + //******************************************************************************* + virtual void init(void); + + //******************************************************************************* + /// @brief Run SmartThings Library + //******************************************************************************* + virtual void run(void); + + //******************************************************************************* + /// @brief Send Message out over ZigBee to the Hub + /// @param[in] message to send + //******************************************************************************* + virtual void send(String message); + + //******************************************************************************* + /// @brief Set SmartThings Shield MultiColor LED + /// @param[in] red: intensity {0=off to 9=max} + /// @param[in] green: intensity {0=off to 9=max} + /// @param[in] blue: intensity {0=off to 9=max} + //******************************************************************************* + void shieldSetLED(uint8_t red, uint8_t green, uint8_t blue); + + //******************************************************************************* + /// @brief Get Last Read Shield State + /// @return Last Read Network State + //******************************************************************************* + SmartThingsNetworkState_t shieldGetLastNetworkState(void); + + //******************************************************************************* + /// @brief Get Last Read Shield State and Trigger Refresh of Network Info + /// @return Last Read Network State + //******************************************************************************* + SmartThingsNetworkState_t shieldGetNetworkState(void); + + //******************************************************************************* + /// @brief Get Last Read NodeID and Trigger Refresh of Network Info + /// @return Last Read NodeID + //******************************************************************************* + uint16_t shieldGetNodeID(void); + + //******************************************************************************* + /// @brief Get Last Read EUI64 and Trigger Refresh of Network Info + /// @return Last Read EUI64 + //******************************************************************************* + void shieldGetEUI64(uint8_t eui[8]); + + //******************************************************************************* + /// @brief Find and Join a Network + //******************************************************************************* + void shieldFindNetwork(void); + + //******************************************************************************* + /// @brief Leave the Current ZigBee Network + //******************************************************************************* + void shieldLeaveNetwork(void); + + //******************************************************************************* + // Update the network State/LED + //******************************************************************************* + void updateNetworkState(void); //get the current zigbee network status of the ST Shield + + }; +} +#endif diff --git a/lib/SmartThings/examples/SmartThings_On_Off_LED_ESP01WiFi/SmartThings_On_Off_LED_ESP01WiFi.ino b/lib/SmartThings/examples/SmartThings_On_Off_LED_ESP01WiFi/SmartThings_On_Off_LED_ESP01WiFi.ino new file mode 100644 index 0000000..976195e --- /dev/null +++ b/lib/SmartThings/examples/SmartThings_On_Off_LED_ESP01WiFi/SmartThings_On_Off_LED_ESP01WiFi.ino @@ -0,0 +1,123 @@ +//***************************************************************************** +/// @file +/// @brief +/// Arduino SmartThings Ethernet ESP01 WiFi On/Off with LED Example +/// +/// Revised by Dan Ogorchock on 2017-02-21 to work with new "SmartThings v2.0" Library +/// +/// Notes: The ESP-01 communicates via WiFi to your home network router, +/// then to the ST Hub, and eventually to the ST cloud servers. +/// +/// The ESP-01 module has 2 GPIO pins, 0 and 2. There is no onboard +/// LED, so you will need to wire an external LED to GPIO2 for this example. +/// +//***************************************************************************** + +#include + +//***************************************************************************** +// Pin Definitions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +#define PIN_LED 2 //ESP-01 has 2 GPIO pins - GPIO0 (0) and GPIO2 (2) + +//***************************************************************************** +// Global Variables | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +SmartThingsCallout_t messageCallout; // call out function forward decalaration + +//****************************************************************************************** +//ESP8266 WiFi Information CHANGE THIS INFORMATION ACCORDINGLY FOR YOUR NETWORK! +//****************************************************************************************** +String str_ssid = "yourSSIDhere"; // <---You must edit this line! +String str_password = "yourWiFiPasswordhere"; // <---You must edit this line! +IPAddress ip(192, 168, 1, 209); // Device IP Address // <---You must edit this line! +IPAddress gateway(192, 168, 1, 1); //router gateway // <---You must edit this line! +IPAddress subnet(255, 255, 255, 0); //LAN subnet mask // <---You must edit this line! +IPAddress dnsserver(192, 168, 1, 1); //DNS server // <---You must edit this line! +const unsigned int serverPort = 8090; // port to run the http server on + +// Smartthings Hub Information +IPAddress hubIp(192, 168, 1, 149); // smartthings hub ip // <---You must edit this line! +const unsigned int hubPort = 39500; // smartthings hub port + + +//Create a SmartThings Ethernet ESP8266WiFi object +st::SmartThingsESP8266WiFi smartthing(str_ssid, str_password, ip, gateway, subnet, dnsserver, serverPort, hubIp, hubPort, messageCallout); + +bool isDebugEnabled; // enable or disable debug in this example + +//***************************************************************************** +// Local Functions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +void on() +{ + digitalWrite(PIN_LED, HIGH); // turn LED on + smartthing.send("on"); // send message to cloud +} + +//***************************************************************************** +void off() +{ + digitalWrite(PIN_LED, LOW); // turn LED off + smartthing.send("off"); // send message to cloud +} + +//***************************************************************************** +// API Functions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +void setup() +{ + // setup default state of global variables + isDebugEnabled = true; + + if (isDebugEnabled) + { // setup debug serial port + Serial.begin(9600); // setup serial with a baud rate of 9600 + Serial.println(""); + Serial.println("setup.."); // print out 'setup..' on start + } + + // setup hardware pins + pinMode(PIN_LED, OUTPUT); // define PIN_LED as an output + digitalWrite(PIN_LED, LOW); // set value to LOW (off) + + //Run the SmartThings init() routine to make sure the ThingShield is connected to the ST Hub + smartthing.init(); + + //synch up the ST cloud + smartthing.send("off"); // send message to cloud +} + +//***************************************************************************** +void loop() +{ + // run smartthing logic + smartthing.run(); +} + +//***************************************************************************** +void messageCallout(String message) +{ + // if debug is enabled print out the received message + if (isDebugEnabled) + { + Serial.print("Received message: '"); + Serial.print(message); + Serial.println("' "); + } + + // if message contents equals to 'on' then call on() function + // else if message contents equals to 'off' then call off() function + if (message.equals("on")) + { + on(); + } + else if (message.equals("off")) + { + off(); + } +} diff --git a/lib/SmartThings/examples/SmartThings_On_Off_LED_ESP8266WiFi/SmartThings_On_Off_LED_ESP8266WiFi.ino b/lib/SmartThings/examples/SmartThings_On_Off_LED_ESP8266WiFi/SmartThings_On_Off_LED_ESP8266WiFi.ino new file mode 100644 index 0000000..0822c95 --- /dev/null +++ b/lib/SmartThings/examples/SmartThings_On_Off_LED_ESP8266WiFi/SmartThings_On_Off_LED_ESP8266WiFi.ino @@ -0,0 +1,142 @@ +//***************************************************************************** +/// @file +/// @brief +/// Arduino SmartThings Ethernet ESP8266 WiFi On/Off with LED Example +/// +/// Revised by Dan Ogorchock on 2017-02-11 to work with new "SmartThings v2.0" Library +/// +/// Notes: The NodeMCU ESP communicates via WiFi to your home network router, +/// then to the ST Hub, and eventually to the ST cloud servers. +/// +/// +//***************************************************************************** + +#include + +//***************************************************************************** +// Pin Definitions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +//****************************************************************************************** +//NodeMCU ESP8266 Pin Definitions (makes it much easier as these match the board markings) +//****************************************************************************************** +#define LED_BUILTIN 16 +#define BUILTIN_LED 16 + +#define D0 16 +#define D1 5 +#define D2 4 +#define D3 0 +#define D4 2 +#define D5 14 +#define D6 12 +#define D7 13 +#define D8 15 +#define D9 3 +#define D10 1 + + +#define PIN_LED LED_BUILTIN //Onboard LED + +//***************************************************************************** +// Global Variables | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +SmartThingsCallout_t messageCallout; // call out function forward decalaration + +//****************************************************************************************** +//ESP8266 WiFi Information CHANGE THIS INFORMATION ACCORDINGLY FOR YOUR NETWORK! +//****************************************************************************************** +String str_ssid = "yourSSIDhere"; // <---You must edit this line! +String str_password = "yourWiFiPasswordhere"; // <---You must edit this line! +IPAddress ip(192, 168, 1, 202); // Device IP Address // <---You must edit this line! +IPAddress gateway(192, 168, 1, 1); //router gateway // <---You must edit this line! +IPAddress subnet(255, 255, 255, 0); //LAN subnet mask // <---You must edit this line! +IPAddress dnsserver(192, 168, 1, 1); //DNS server // <---You must edit this line! +const unsigned int serverPort = 8090; // port to run the http server on + +// Smartthings Hub Information +IPAddress hubIp(192, 168, 1, 149); // smartthings hub ip // <---You must edit this line! +const unsigned int hubPort = 39500; // smartthings hub port + + +//Create a SmartThings Ethernet ESP8266WiFi object +st::SmartThingsESP8266WiFi smartthing(str_ssid, str_password, ip, gateway, subnet, dnsserver, serverPort, hubIp, hubPort, messageCallout); + +bool isDebugEnabled; // enable or disable debug in this example + + +//***************************************************************************** +// Local Functions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +void on() +{ + digitalWrite(PIN_LED, LOW); // turn LED on + smartthing.send("on"); // send message to cloud +} + +//***************************************************************************** +void off() +{ + digitalWrite(PIN_LED, HIGH); // turn LED off + smartthing.send("off"); // send message to cloud +} + +//***************************************************************************** +// API Functions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +void setup() +{ + // setup default state of global variables + isDebugEnabled = true; + + if (isDebugEnabled) + { // setup debug serial port + Serial.begin(9600); // setup serial with a baud rate of 9600 + Serial.println(""); + Serial.println("setup.."); // print out 'setup..' on start + } + + // setup hardware pins + pinMode(PIN_LED, OUTPUT); // define PIN_LED as an output + digitalWrite(PIN_LED, HIGH); // set value to HIGH (off) + + //Run the SmartThings init() routine to make sure the ThingShield is connected to the ST Hub + smartthing.init(); + + //synch up the ST cloud + smartthing.send("off"); // send message to cloud +} + +//***************************************************************************** +void loop() +{ + // run smartthing logic + smartthing.run(); +} + +//***************************************************************************** +void messageCallout(String message) +{ + // if debug is enabled print out the received message + if (isDebugEnabled) + { + Serial.print("Received message: '"); + Serial.print(message); + Serial.println("' "); + } + + // if message contents equals to 'on' then call on() function + // else if message contents equals to 'off' then call off() function + if (message.equals("on")) + { + on(); + } + else if (message.equals("off")) + { + off(); + } +} + diff --git a/lib/SmartThings/examples/SmartThings_On_Off_LED_EthernetW5x00/SmartThings_On_Off_LED_EthernetW5x00.ino b/lib/SmartThings/examples/SmartThings_On_Off_LED_EthernetW5x00/SmartThings_On_Off_LED_EthernetW5x00.ino new file mode 100644 index 0000000..e56fead --- /dev/null +++ b/lib/SmartThings/examples/SmartThings_On_Off_LED_EthernetW5x00/SmartThings_On_Off_LED_EthernetW5x00.ino @@ -0,0 +1,135 @@ +//***************************************************************************** +/// @file +/// @brief +/// Arduino SmartThings Ethernet W5x00 On/Off with LED Example +/// +/// Revised by Dan Ogorchock on 2017-02-10 to work with new "SmartThings v2.0" Library +/// +/// Notes: Arduino communicates with both the W5x00 and SD card using the SPI bus (through the ICSP header). +/// This is on digital pins 10, 11, 12, and 13 on the Uno and pins 50, 51, and 52 on the Mega. +/// On both boards, pin 10 is used to select the W5x00 and pin 4 for the SD card. +/// These pins cannot be used for general I/O. On the Mega, the hardware SS pin, 53, +/// is not used to select either the W5x00 or the SD card, but it must be kept as an output +/// or the SPI interface won't work. +/// See https://www.arduino.cc/en/Main/ArduinoEthernetShieldV1 for details on the W5x00 Sield +/// +/// +//***************************************************************************** + +#include + +//***************************************************************************** +// Pin Definitions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +// "RESERVED" pins for W5x00 Ethernet Shield - best to avoid +#define PIN_4_RESERVED 4 //reserved by W5x00 Shield on both UNO and MEGA +#define PIN_1O_RESERVED 10 //reserved by W5x00 Shield on both UNO and MEGA +#define PIN_11_RESERVED 11 //reserved by W5x00 Shield on UNO +#define PIN_12_RESERVED 12 //reserved by W5x00 Shield on UNO +#define PIN_13_RESERVED 13 //reserved by W5x00 Shield on UNO +#define PIN_50_RESERVED 50 //reserved by W5x00 Shield on MEGA +#define PIN_51_RESERVED 51 //reserved by W5x00 Shield on MEGA +#define PIN_52_RESERVED 52 //reserved by W5x00 Shield on MEGA +#define PIN_53_RESERVED 53 //reserved by W5x00 Shield on MEGA + +#define PIN_LED 13 //Onboard LED + +//***************************************************************************** +// Global Variables | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +SmartThingsCallout_t messageCallout; // call out function forward decalaration + +//****************************************************************************************** +//W5x00 Ethernet Shield Information CHANGE THIS INFORMATION ACCORDINGLY FOR YOUR NETWORK! +//****************************************************************************************** +byte mac[] = {0x06,0x02,0x03,0x04,0x05,0x06}; //MAC address, leave first octet 0x06, change others to be unique // <---You must edit this line! +IPAddress ip(192, 168, 1, 204); //Arduino device IP Address // <---You must edit this line! +IPAddress gateway(192, 168, 1, 1); //router gateway // <---You must edit this line! +IPAddress subnet(255, 255, 255, 0); //LAN subnet mask // <---You must edit this line! +IPAddress dnsserver(192, 168, 1, 1); //DNS server // <---You must edit this line! +const unsigned int serverPort = 8090; // port to run the http server on + +// Smartthings hub information +IPAddress hubIp(192,168,1,149); // smartthings hub ip // <---You must edit this line! +const unsigned int hubPort = 39500; // smartthings hub port + +//Create a SmartThings Ethernet W5x00 object +st::SmartThingsEthernetW5x00 smartthing(mac, ip, gateway, subnet, dnsserver, serverPort, hubIp, hubPort, messageCallout); + +bool isDebugEnabled; // enable or disable debug in this example +int stateLED; // state to track last set value of LED + +//***************************************************************************** +// Local Functions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +void on() +{ + stateLED = 1; // save state as 1 (on) + digitalWrite(PIN_LED, HIGH); // turn LED on + smartthing.send("on"); // send message to cloud +} + +//***************************************************************************** +void off() +{ + stateLED = 0; // set state to 0 (off) + digitalWrite(PIN_LED, LOW); // turn LED off + smartthing.send("off"); // send message to cloud +} + +//***************************************************************************** +// API Functions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +void setup() +{ + // setup default state of global variables + isDebugEnabled = true; + stateLED = 0; // matches state of hardware pin set below + + // setup hardware pins + pinMode(PIN_LED, OUTPUT); // define PIN_LED as an output + digitalWrite(PIN_LED, LOW); // set value to LOW (off) to match stateLED=0 + + //Run the SmartThings init() routine to make sure the ThingShield is connected to the ST Hub + smartthing.init(); + + if (isDebugEnabled) + { // setup debug serial port + Serial.begin(9600); // setup serial with a baud rate of 9600 + Serial.println("setup.."); // print out 'setup..' on start + } +} + +//***************************************************************************** +void loop() +{ + // run smartthing logic + smartthing.run(); +} + +//***************************************************************************** +void messageCallout(String message) +{ + // if debug is enabled print out the received message + if (isDebugEnabled) + { + Serial.print("Received message: '"); + Serial.print(message); + Serial.println("' "); + } + + // if message contents equals to 'on' then call on() function + // else if message contents equals to 'off' then call off() function + if (message.equals("on")) + { + on(); + } + else if (message.equals("off")) + { + off(); + } +} diff --git a/lib/SmartThings/examples/SmartThings_On_Off_LED_ThingShield/SmartThings_On_Off_LED_ThingShield.ino b/lib/SmartThings/examples/SmartThings_On_Off_LED_ThingShield/SmartThings_On_Off_LED_ThingShield.ino new file mode 100644 index 0000000..d41a8b1 --- /dev/null +++ b/lib/SmartThings/examples/SmartThings_On_Off_LED_ThingShield/SmartThings_On_Off_LED_ThingShield.ino @@ -0,0 +1,147 @@ +//***************************************************************************** +/// @file +/// @brief +/// Arduino SmartThings ThingShield On/Off with LED Example +/// +/// Revised by Dan Ogorchock on 2017-02-10 to work with new "SmartThings v2.0" Library +/// -Now supports automatic selectic of SoftwareSerial or HardwareSerial constructor +/// depending on the Arduino Model. +/// -If using an Arduino UNO R3, be sure to set the ThingShield switch to the D2/D3 position +/// -If using an Arduino Leonardo, be sure to set the ThingShield switch to the D0/D1 position +/// -If using an Arduino MEGA 2560, bbe sure to set the ThingShield switch to the D2/D3 position AND +/// connect jumper wires between pins 2 & 14 as well as between pins 3 & 15. +/// +/// DO NOT USE PINS 0,1,2,3,6 for I/O in your sketch as pins 0,1,2,3 are used by the ThingShield +/// and USB communications to your computer. Pin 6 is reserved by the ThingShield. +/// +/// @note UNO R3 Pins +/// ______________ +/// | | +/// | SW[] | +/// |[]RST | +/// | AREF |-- +/// | GND |-- +/// | 13 |--X Onboard LED +/// | 12 |-- +/// | 11 |-- +/// --| 3.3V 10 |-- +/// --| 5V 9 |-- +/// --| GND 8 |-- +/// --| GND | +/// --| Vin 7 |-- +/// | 6 |--Reserved +/// --| A0 5 |-- +/// --| A1 ( ) 4 |-- +/// --| A2 3 |--X THING_RX +/// --| A3 ____ 2 |--X THING_TX +/// --| A4 | | 1 |--X THING_RX +/// --| A5 | | 0 |--X THING_RX +/// |____| |____| +/// |____| +/// +//***************************************************************************** +#include + +//***************************************************************************** +// Pin Definitions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +#define PIN_LED 13 +#define PIN_THING_RX 3 +#define PIN_THING_TX 2 + +//***************************************************************************** +// Global Variables | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +SmartThingsCallout_t messageCallout; // call out function forward decalaration + + #if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_NANO) || defined(ARDUINO_AVR_MINI) //Arduino UNO, NANO, MINI + st::SmartThingsThingShield smartthing(PIN_THING_RX, PIN_THING_TX, messageCallout); //Use Software Serial constructor + #elif defined(ARDUINO_AVR_LEONARDO) //Arduino Leonardo + st::SmartThingsThingShield smartthing(&Serial1, messageCallout); //Use Hardware Serial constructor w/Serial1 + #elif defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560) //Arduino MEGA 1280 or 2560 + st::SmartThingsThingShield smartthing(&Serial3, messageCallout); //Use Hardware Serial constructor w/Serial3 + #else + //assume user is using an UNO for the unknown case + st::SmartThingsThingShield smartthing(PIN_THING_RX, PIN_THING_TX, messageCallout); //Use Software Serial constructor + #endif + +bool isDebugEnabled; // enable or disable debug in this example +int stateLED; // state to track last set value of LED + +//***************************************************************************** +// Local Functions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +void on() +{ + stateLED = 1; // save state as 1 (on) + digitalWrite(PIN_LED, HIGH); // turn LED on + smartthing.shieldSetLED(0, 0, 1); + smartthing.send("on"); // send message to cloud +} + +//***************************************************************************** +void off() +{ + stateLED = 0; // set state to 0 (off) + digitalWrite(PIN_LED, LOW); // turn LED off + smartthing.shieldSetLED(0, 0, 0); + smartthing.send("off"); // send message to cloud +} + +//***************************************************************************** +// API Functions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +void setup() +{ + // setup default state of global variables + isDebugEnabled = true; + stateLED = 0; // matches state of hardware pin set below + + // setup hardware pins + pinMode(PIN_LED, OUTPUT); // define PIN_LED as an output + digitalWrite(PIN_LED, LOW); // set value to LOW (off) to match stateLED=0 + + //Run the SmartThings init() routine to make sure the ThingShield is connected to the ST Hub + smartthing.init(); + + if (isDebugEnabled) + { // setup debug serial port + Serial.begin(9600); // setup serial with a baud rate of 9600 + Serial.println("setup.."); // print out 'setup..' on start + } +} + +//***************************************************************************** +void loop() +{ + // run smartthing logic + smartthing.run(); +} + +//***************************************************************************** +void messageCallout(String message) +{ + // if debug is enabled print out the received message + if (isDebugEnabled) + { + Serial.print("Received message: '"); + Serial.print(message); + Serial.println("' "); + } + + // if message contents equals to 'on' then call on() function + // else if message contents equals to 'off' then call off() function + if (message.equals("on")) + { + on(); + } + else if (message.equals("off")) + { + off(); + } +} + diff --git a/lib/SmartThings/examples/SmartThings_On_Off_LED_WiFiEsp/SmartThings_On_Off_LED_WiFiEsp.ino b/lib/SmartThings/examples/SmartThings_On_Off_LED_WiFiEsp/SmartThings_On_Off_LED_WiFiEsp.ino new file mode 100644 index 0000000..e31a04e --- /dev/null +++ b/lib/SmartThings/examples/SmartThings_On_Off_LED_WiFiEsp/SmartThings_On_Off_LED_WiFiEsp.ino @@ -0,0 +1,132 @@ +//***************************************************************************** +/// @file +/// @brief +/// Arduino SmartThings Ethernet WiFiEsp On/Off with LED Example +/// +/// Revised by Dan Ogorchock on 2017-02-20 to work with new "SmartThings v2.0" Library +/// +/// Notes: The Arduino MEGA 2560 communicates via Serial1 to the ESP-01 WiFi board +/// to your home network router, then to the ST Hub, and eventually to the +/// ST cloud servers. +/// +/// You must connect the ESP-01 to the Arduino MEGA 2560's "Serial1" +/// Hardware Serial port on pins 18 & 19. Google it! +/// +/// The ESP-01 must be running a version of firmware compatible with +/// the WiFiEsp library. Try the examples in the WiFiEsp library +/// to make sure everything is wried correctly before trying this sketch! +/// +//***************************************************************************** + +#include + +//***************************************************************************** +// Pin Definitions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +#define PIN_LED 13 + +//***************************************************************************** +// Global Variables | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +SmartThingsCallout_t messageCallout; // call out function forward decalaration + +//****************************************************************************************** +//ESP8266 WiFi Information CHANGE THIS INFORMATION ACCORDINGLY FOR YOUR NETWORK! +//****************************************************************************************** +String str_ssid = "yourSSIDhere"; // <---You must edit this line! +String str_password = "yourWiFiPasswordhere"; // <---You must edit this line! +IPAddress ip(192, 168, 1, 203); // Device IP Address // <---You must edit this line! +const unsigned int serverPort = 8090; // port to run the http server on + +// Smartthings Hub Information +IPAddress hubIp(192, 168, 1, 149); // smartthings hub ip // <---You must edit this line! +const unsigned int hubPort = 39500; // smartthings hub port + + +//Create a SmartThings Ethernet ESP8266WiFi object using the Arduino + ESP-01 constructor +st::SmartThingsWiFiEsp smartthing(&Serial1, str_ssid, str_password, ip, serverPort, hubIp, hubPort, messageCallout); + +bool isDebugEnabled; // enable or disable debug in this example +int stateLED; // state to track last set value of LED + +//***************************************************************************** +// Local Functions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +void on() +{ + stateLED = 1; // save state as 1 (on) + digitalWrite(PIN_LED, HIGH); // turn LED on + //smartthing.send("on"); // send message to cloud +} + +//***************************************************************************** +void off() +{ + stateLED = 0; // set state to 0 (off) + digitalWrite(PIN_LED, LOW); // turn LED off + //smartthing.send("off"); // send message to cloud +} + +//***************************************************************************** +// API Functions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +void setup() +{ + // setup default state of global variables + isDebugEnabled = true; + stateLED = 0; // matches state of hardware pin set below + + if (isDebugEnabled) + { // setup debug serial port + Serial.begin(9600); // setup serial with a baud rate of 9600 + Serial.println(""); + Serial.println("setup.."); // print out 'setup..' on start + } + + // setup hardware pins + pinMode(PIN_LED, OUTPUT); // define PIN_LED as an output + digitalWrite(PIN_LED, LOW); // set value to LOW (off) to match stateLED=0 + + // initialize Hardware Serial UART for ESP module + Serial1.begin(115200); //May need to adjust the baud rate for your ESP-01 (9600, 57600, 115200) + + //Run the SmartThings init() routine to make sure the ThingShield is connected to the ST Hub + smartthing.init(); + + +} + +//***************************************************************************** +void loop() +{ + // run smartthing logic + smartthing.run(); +} + +//***************************************************************************** +void messageCallout(String message) +{ + // if debug is enabled print out the received message + if (isDebugEnabled) + { + Serial.print("Received message: '"); + Serial.print(message); + Serial.println("' "); + } + + // if message contents equals to 'on' then call on() function + // else if message contents equals to 'off' then call off() function + if (message.equals("on")) + { + on(); + } + else if (message.equals("off")) + { + off(); + } +} + diff --git a/lib/SmartThings/examples/SmartThings_On_Off_LED_WiFiNINA/SmartThings_On_Off_LED_WiFiNINA.ino b/lib/SmartThings/examples/SmartThings_On_Off_LED_WiFiNINA/SmartThings_On_Off_LED_WiFiNINA.ino new file mode 100644 index 0000000..9a5aac3 --- /dev/null +++ b/lib/SmartThings/examples/SmartThings_On_Off_LED_WiFiNINA/SmartThings_On_Off_LED_WiFiNINA.ino @@ -0,0 +1,129 @@ +//***************************************************************************** +/// @file +/// @brief +/// Arduino SmartThings Ethernet WiFi NINA On/Off with LED Example +/// +/// Revised by Dan Ogorchock on 2020-01-19 to work with new "SmartThings v2.0" Library +/// +/// Notes: The Arduino with NINA communicates via WiFi to your home network router, +/// then to the ST Hub, and eventually to the ST cloud servers. +/// +/// +//***************************************************************************** + +#include + +//***************************************************************************** +// Pin Definitions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** + +//***************************************************************************** +// Global Variables | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +SmartThingsCallout_t messageCallout; // call out function forward decalaration + +//****************************************************************************************** +//WiFiNINA Information CHANGE THIS INFORMATION ACCORDINGLY FOR YOUR NETWORK! +//****************************************************************************************** +String str_ssid = "yourSSIDhere"; // <---You must edit this line! +String str_password = "yourWiFiPasswordhere"; // <---You must edit this line! +IPAddress ip(192, 168, 1, 202); // Device IP Address // <---You must edit this line if using static IP! +IPAddress gateway(192, 168, 1, 1); //router gateway // <---You must edit this line if using static IP! +IPAddress subnet(255, 255, 255, 0); //LAN subnet mask // <---You must edit this line if using static IP! +IPAddress dnsserver(192, 168, 1, 1); //DNS server // <---You must edit this line if using static IP! +const unsigned int serverPort = 8090; // port to run the http server on + +// Smartthings Hub Information +IPAddress hubIp(192, 168, 1, 149); // smartthings hub ip // <---You must edit this line! +const unsigned int hubPort = 39500; // smartthings hub port + +// Hubitat Hub Information +//IPAddress hubIp(192, 168, 1, 149); // Hubitat hub ip // <---You must edit this line! +//const unsigned int hubPort = 39501; // Hubitat hub port + + + +//Create a SmartThings Ethernet WiFiNINA object (comment/uncomment the lines below as desired - only ONE can be active) +// static IP +st::SmartThingsWiFiNINA smartthing(str_ssid, str_password, ip, gateway, subnet, dnsserver, serverPort, hubIp, hubPort, messageCallout); +// DHCP +//st::SmartThingsWiFiNINA smartthing(str_ssid, str_password, serverPort, hubIp, hubPort, messageCallout); + +bool isDebugEnabled; // enable or disable debug in this example + + +//***************************************************************************** +// Local Functions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +void on() +{ + digitalWrite(PIN_LED, LOW); // turn LED on + smartthing.send("on"); // send message to cloud +} + +//***************************************************************************** +void off() +{ + digitalWrite(PIN_LED, HIGH); // turn LED off + smartthing.send("off"); // send message to cloud +} + +//***************************************************************************** +// API Functions | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +// V V V V V V V V V V V V V V V V V V V V V V V V V V V V V V +//***************************************************************************** +void setup() +{ + // setup default state of global variables + isDebugEnabled = true; + + if (isDebugEnabled) + { // setup debug serial port + Serial.begin(9600); // setup serial with a baud rate of 9600 + Serial.println(""); + Serial.println("setup.."); // print out 'setup..' on start + } + + // setup hardware pins + pinMode(PIN_LED, OUTPUT); // define PIN_LED as an output + digitalWrite(PIN_LED, HIGH); // set value to HIGH (off) + + //Run the SmartThings init() routine to make sure the ThingShield is connected to the ST Hub + smartthing.init(); + + //synch up the ST cloud + smartthing.send("off"); // send message to cloud +} + +//***************************************************************************** +void loop() +{ + // run smartthing logic + smartthing.run(); +} + +//***************************************************************************** +void messageCallout(String message) +{ + // if debug is enabled print out the received message + if (isDebugEnabled) + { + Serial.print("Received message: '"); + Serial.print(message); + Serial.println("' "); + } + + // if message contents equals to 'on' then call on() function + // else if message contents equals to 'off' then call off() function + if (message.equals("on")) + { + on(); + } + else if (message.equals("off")) + { + off(); + } +} diff --git a/lib/SmartThings/extras/On_Off_LED_Ethernet.device.groovy b/lib/SmartThings/extras/On_Off_LED_Ethernet.device.groovy new file mode 100644 index 0000000..f1a6b69 --- /dev/null +++ b/lib/SmartThings/extras/On_Off_LED_Ethernet.device.groovy @@ -0,0 +1,111 @@ +/** + * Copyright 2015 SmartThings (original) + * + * 2017-02-11 Dan Ogorchock - Since SmartThings has abandoned the ThingShield, I have created a new + * Arduino "SmartThings" library with support for the ThingShield, + * W5100 Ethernet Shield, and the NodeMCU ESP8266 Board for connectivity to + * the SmartThings cloud. This file is to be used with the On/Off Ethernet W5100 + * and ESP8266 examples found in this new library which can be found at + * + * https://github.com/DanielOgorchock/ST_Anything/tree/master/Arduino/libraries/SmartThings + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License + * for the specific language governing permissions and limitations under the License. + * + */ +metadata { + definition (name: "On/Off Ethernet", namespace: "ogiewon", author: "Dan Ogorchock") { + capability "Actuator" + capability "Switch" + capability "Sensor" + } + + // Simulator metadata + simulator { + + } + + // Preferences + preferences { + input "ip", "text", title: "Arduino IP Address", description: "ip", required: true, displayDuringSetup: true + input "port", "text", title: "Arduino Port", description: "port", required: true, displayDuringSetup: true + input "mac", "text", title: "Arduino MAC Addr", description: "mac", required: true, displayDuringSetup: true + } + // UI tile definitions + tiles { + standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) { + state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" + state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" + } + standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat") { + state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure" + } + + main (["switch"]) + details (["switch","configure"]) + } +} + +// parse events into attributes +def parse(String description) { + //log.debug "Parsing '${description}'" + def msg = parseLanMessage(description) + def headerString = msg.header + + if (!headerString) { + //log.debug "headerstring was null for some reason :(" + } + + def bodyString = msg.body + + if (bodyString) { + //log.debug "BodyString: $bodyString" + def value = bodyString + def name = value in ["on","off"] ? "switch" : null + def result = createEvent(name: name, value: value) + log.debug "Parse returned ${result?.descriptionText}" + return result + } +} + +private getHostAddress() { + def ip = settings.ip + def port = settings.port + + log.debug "Using ip: ${ip} and port: ${port} for device: ${device.id}" + return ip + ":" + port +} + +def sendEthernet(message) { + log.debug "Executing 'sendEthernet' ${message}" + new physicalgraph.device.HubAction( + method: "POST", + path: "/${message}?", + headers: [ HOST: "${getHostAddress()}" ] + ) +} + +// Commands sent to the device +def on() { + log.debug "Sending 'on'" + sendEthernet("on") +} + +def off() { + log.debug "Sending 'off'" + sendEthernet("off") +} + +def configure() { + log.debug "Executing 'configure'" + if(device.deviceNetworkId!=settings.mac) { + log.debug "setting device network id" + device.deviceNetworkId = settings.mac + } +} \ No newline at end of file diff --git a/lib/SmartThings/extras/On_Off_LED_ThingShield.device.groovy b/lib/SmartThings/extras/On_Off_LED_ThingShield.device.groovy new file mode 100644 index 0000000..51f707a --- /dev/null +++ b/lib/SmartThings/extras/On_Off_LED_ThingShield.device.groovy @@ -0,0 +1,67 @@ +/** + * Copyright 2015 SmartThings (original) + * + * 2017-02-11 Dan Ogorchock - Since SmartThings has abandoned the ThingShield, I have created a new + * Arduino "SmartThings" library with support for the ThingShield, + * W5100 Ethernet Shield, and the NodeMCU ESP8266 Board for connectivity to + * the SmartThings cloud. This file is to be used with the On/Off ThingShield + * example found in this new library which can be found at + * + * https://github.com/DanielOgorchock/ST_Anything/tree/master/Arduino/libraries/SmartThings + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License + * for the specific language governing permissions and limitations under the License. + * + */ +metadata { + definition (name: "On/Off ThingShield", namespace: "ogiewon", author: "Dan Ogorchock") { + capability "Actuator" + capability "Switch" + capability "Sensor" + } + + // Simulator metadata + simulator { + status "on": "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6E" + status "off": "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6666" + + // reply messages + reply "raw 0x0 { 00 00 0a 0a 6f 6e }": "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6E" + reply "raw 0x0 { 00 00 0a 0a 6f 66 66 }": "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6666" + } + + // UI tile definitions + tiles { + standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true, canChangeBackground: true) { + state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#79b821" + state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff" + } + + main "switch" + details "switch" + } +} + +// Parse incoming device messages to generate events +def parse(String description) { + def value = zigbee.parse(description)?.text + def name = value in ["on","off"] ? "switch" : null + def result = createEvent(name: name, value: value) + log.debug "Parse returned ${result?.descriptionText}" + return result +} + +// Commands sent to the device +def on() { + zigbee.smartShield(text: "on").format() +} + +def off() { + zigbee.smartShield(text: "off").format() +} \ No newline at end of file diff --git a/lib/SmartThings/info.txt b/lib/SmartThings/info.txt new file mode 100644 index 0000000..33d855c --- /dev/null +++ b/lib/SmartThings/info.txt @@ -0,0 +1,46 @@ + -------------------------------------------------------------------------------------------------- +| Setup Instructions | + -------------------------------------------------------------------------------------------------- +1) Copy all of the SmartThings* directories into the 'libraries' directory in your sketchbook location. + Windows: 'My Documents\Arduino\libraries\SmartThings*' + OSX: '~/Documents/Arduino/libraries/SmartThings*' + + -------------------------------------------------------------------------------------------------- +| Notes | + -------------------------------------------------------------------------------------------------- + + + -------------------------------------------------------------------------------------------------- +| ChangeLog: | + -------------------------------------------------------------------------------------------------- +05/25/2017 (v2.3.0) do + Added support for W5500 shield, causing library to be broken into + multiple folders to avoid duplicate class definitions +04/26/2017 (v2.2.0) do + Added optional argument for max transmission rate which can be queried + by calling application. Not used internally. +02/20/2017 (v2.1.0) do + Added support for Arduino + ESP-01 hardware combination +02/10/2017 (v2.0.0) do ~ Totally rearchitected C++ Class structure to support ThingShield, W5100 Ethernet, and ESP8266 WiFi + + Added new init() function to allow object to connect to network at runtime in sketch setup() routine + + Revised On/Off Thingshield example to use the new library class, SmartThingsThingShield + + Added On/Off W5100 example to use the new SmartThingsEthernetW5100 class + + Added On/Off ESP8266WiFi example to use the new SmartThingsESP8266WiFi class +01/11/2015 (v0.0.6) do + Added Hardware Serial Constructor + + Added support for Leonardo and MEGA + ~ Performance improvements + ~ Significant SRAM memory optimizations (minimum ~175 bytes, up to 430 bytes) +02/11/2012 (v0.0.5) db + shieldGetLastNetworkStatus to public Class + + example/stLEDwithNetworkStatus + ~ renamed SmartThingsLED to stLED + + ascii diagram for each example documenting pins & usage +02/08/2012 (v0.0.4) db + Add docs/Doxygen + + Begin Framework for working on Leonardo (incomplete) + ~ Minor format cleanup +02/08/2012 (v0.0.3) db ! Fixed regression in last commit with rgb +02/07/2012 (v0.0.2) db ! Fixed typo in send functions + ! Changed write to print for maximal compatibility with serial code + dm ! Point Library to Absolute Path, Add documentation +02/06/2012 (v0.0.1) db ! Lowered Baud to 2400 due to softwareSerial rxBuffer size issue + + Add shield Commands(SetLED, Leave, Find, NetworkStatus) + + Updated Example to also SetLED with on/off control + + Add Doxygen comments & Version to Lib +02/04/2012 (unversioned) db + Initial Commit (currently depends on SoftwareSerial) + diff --git a/lib/SmartThings/keywords.txt b/lib/SmartThings/keywords.txt new file mode 100644 index 0000000..5777d6a --- /dev/null +++ b/lib/SmartThings/keywords.txt @@ -0,0 +1,29 @@ +####################################### +# Data Types +####################################### +SmartThings KEYWORD1 +SmartThingsThingShield KEYWORD1 +SmartThingsEthernet KEYWORD1 +SmartThingsEthernetW5100 KEYWORD1 +SmartThingsEthernetW5500 KEYWORD1 +SmartThingsESP8266WiFi KEYWORD1 +SmartThingsESP32WiFi KEYWORD1 +SmartThingsWiFiEsp KEYWORD1 +SmartThingsWiFi101 KEYWORD1 +SmartThingsWiFiNINA KEYWORD1 +SmartThingsCallout_t KEYWORD1 +SmartThingsNetworkState_t KEYWORD1 + +####################################### +# Public Methods / Functions +####################################### +run KEYWORD2 +send KEYWORD2 +init KEYWORD2 +getTransmitInterval KEYWORD2 +shieldSetLED KEYWORD2 +shieldFindNetwork KEYWORD2 +shieldLeaveNetwork KEYWORD2 +shieldGetLastNetworkState KEYWORD2 +shieldGetNetworkState KEYWORD2 + diff --git a/lib/SmartThings/library.properties b/lib/SmartThings/library.properties new file mode 100644 index 0000000..1323a83 --- /dev/null +++ b/lib/SmartThings/library.properties @@ -0,0 +1,10 @@ +name=SmartThings +version=2.5 +author=Dan G Ogorchock , Daniel J Ogorchock +maintainer=Dan G Ogorchock +sentence=A library that provides multiple methods to connect to SmartThings. +paragraph=This is a new and improved version of the SmartThings libray which now supports the original ThingShield, the W5100/W500 Ethernet shields, as well as the NodeMCU ESP8266 WiFi and ESP32 boards. +category=Communication +url=https://github.com/DanielOgorchock/ST_Anything/tree/master/Arduino/libraries/SmartThings +architectures=avr,esp8266,samd,esp32 +includes= diff --git a/lib/SmartThingsESP32WiFi/SmartThingsESP32WiFi.cpp b/lib/SmartThingsESP32WiFi/SmartThingsESP32WiFi.cpp new file mode 100644 index 0000000..e0b0227 --- /dev/null +++ b/lib/SmartThingsESP32WiFi/SmartThingsESP32WiFi.cpp @@ -0,0 +1,428 @@ +//******************************************************************************* +// SmartThings NodeMCU ESP32 Wifi Library +// +// License +// (C) Copyright 2017 Dan Ogorchock +// +// History +// 2017-08-15 Dan Ogorchock Created with the help of Joshua Spain +// 2017-09-05 Dan Ogorchock Added automatic WiFi reconnect logic as ESP32 +// doesn't do this automatically currently +// 2018-01-01 Dan Ogorchock Added WiFi.RSSI() data collection +// 2018-01-06 Dan Ogorchock Simplified the MAC address printout to prevent confusion +// 2018-02-03 Dan Ogorchock Support for Hubitat +// 2020-04-10 Dan Ogorchock Improved network performance by disabling WiFi Sleep +// 2020-06-20 Dan Ogorchock Add user selectable host name (repurposing the old shieldType variable) +// +//******************************************************************************* + +#include "SmartThingsESP32WiFi.h" + +namespace st +{ + int SmartThingsESP32WiFi::disconnectCounter = 0; + + //******************************************************************************* + // SmartThingsESP32WiFi Constructor - Static IP + //******************************************************************************* + SmartThingsESP32WiFi::SmartThingsESP32WiFi(String ssid, String password, IPAddress localIP, IPAddress localGateway, IPAddress localSubnetMask, IPAddress localDNSServer, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThingsEthernet(localIP, localGateway, localSubnetMask, localDNSServer, serverPort, hubIP, hubPort, callout, shieldType, enableDebug, transmitInterval, false), + st_server(serverPort) + { + ssid.toCharArray(st_ssid, sizeof(st_ssid)); + password.toCharArray(st_password, sizeof(st_password)); + } + + //******************************************************************************* + // SmartThingsESP32WiFI Constructor - DHCP + //******************************************************************************* + SmartThingsESP32WiFi::SmartThingsESP32WiFi(String ssid, String password, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThingsEthernet(serverPort, hubIP, hubPort, callout, shieldType, enableDebug, transmitInterval, true), + st_server(serverPort) + { + ssid.toCharArray(st_ssid, sizeof(st_ssid)); + password.toCharArray(st_password, sizeof(st_password)); + } + + //******************************************************************************* + // SmartThingsESP32WiFI Constructor - DHCP + //******************************************************************************* + SmartThingsESP32WiFi::SmartThingsESP32WiFi(uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThingsEthernet(serverPort, hubIP, hubPort, callout, shieldType, enableDebug, transmitInterval, true), + st_server(serverPort) + { + st_preExistingConnection = true; + } + + //***************************************************************************** + //SmartThingsESP32WiFI::~SmartThingsESP32WiFI() + //***************************************************************************** + SmartThingsESP32WiFi::~SmartThingsESP32WiFi() + { + + } + + //************************************************************************************** + /// Event Handler for ESP32 WiFi Events (needed to implement reconnect logic for now...) + //************************************************************************************** + void SmartThingsESP32WiFi::WiFiEvent(WiFiEvent_t event) + { + Serial.printf("[WiFi-event] event: %d\n", event); + + switch (event) { + case SYSTEM_EVENT_STA_GOT_IP: + Serial.println("WiFi connected"); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + Serial.println("WiFi lost connection. Attempting to reconnect..."); + WiFi.reconnect(); + disconnectCounter++; + if (disconnectCounter > 10) { + Serial.println("We have recieved the STA_DISCONNECTED event over 10 times now. Reboot..."); + ESP.restart(); + } + break; + case SYSTEM_EVENT_STA_START: + Serial.println("ESP32 station start"); + break; + case SYSTEM_EVENT_STA_CONNECTED: + Serial.println("ESP32 station connected to AP"); + disconnectCounter = 0; + break; + } + + } + + //******************************************************************************* + /// Initialize SmartThingsESP32WiFI Library + //******************************************************************************* + void SmartThingsESP32WiFi::init(void) + { + WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); + + // delete old config + WiFi.disconnect(true); + delay(1000); + WiFi.onEvent(SmartThingsESP32WiFi::WiFiEvent); + + + //Turn off Wirelss Access Point + Serial.println(F("Disabling ESP32 WiFi Access Point")); + Serial.println(F("")); + WiFi.mode(WIFI_STA); + //WiFi.setAutoReconnect(true); + //WiFi.setAutoConnect(true); + WiFi.setSleep(false); + + //get the MAC address + String strMAC(WiFi.macAddress()); + strMAC.replace(":", ""); + + //Set the hostname + if (_shieldType == "ESP32Wifi") { + String("ESP32-" + strMAC).toCharArray(st_devicename, sizeof(st_devicename)); + } + else { + _shieldType.toCharArray(st_devicename, sizeof(st_devicename)); + } + Serial.print(F("hostName = ")); + Serial.println(st_devicename); + + bool result = WiFi.setHostname(st_devicename); + Serial.print(F("setHostname returned ")); + Serial.println(result); + + if (st_DHCP == false) + { + WiFi.config(st_localIP, st_localGateway, st_localSubnetMask, st_localDNSServer); + } + + if (!st_preExistingConnection) { + Serial.println(F("")); + Serial.println(F("Initializing ESP32 WiFi network. Please be patient...")); + //wait for ESP32 to be ready on startup + delay(1000); //may not be necessary, but seems to help my test board start up cleanly + + // attempt to connect to WiFi network + WiFi.begin(st_ssid, st_password); + Serial.print(F("Attempting to connect to WPA SSID: ")); + Serial.println(st_ssid); + } + + int count =0; + while (WiFi.status() != WL_CONNECTED) { + count++; + Serial.print(F(".")); + delay(500); // wait for connection: + if (count > 10) { + Serial.println(F("what is taking so long?")); + count = 0; + } + } + + Serial.println(); + + st_server.begin(); + + Serial.println(F("")); + Serial.println(F("Enter the following three lines of data into ST App on your phone!")); + Serial.print(F("localIP = ")); + Serial.println(WiFi.localIP()); + Serial.print(F("serverPort = ")); + Serial.println(st_serverPort); + Serial.print(F("MAC Address = ")); + Serial.println(strMAC); + Serial.println(F("")); + Serial.print(F("SSID = ")); + Serial.println(st_ssid); + Serial.print(F("PASSWORD = ")); + Serial.println(st_password); + Serial.print(F("hubIP = ")); + Serial.println(st_hubIP); + Serial.print(F("hubPort = ")); + Serial.println(st_hubPort); + Serial.print(F("RSSI = ")); + Serial.println(WiFi.RSSI()); + Serial.println(F("")); + Serial.println(F("SmartThingsESP32WiFI: Intialized")); + Serial.println(F("")); + + RSSIsendInterval = 5000; + previousMillis = millis() - RSSIsendInterval; + + } + + //***************************************************************************** + // Run SmartThingsESP32WiFI Library + //***************************************************************************** + void SmartThingsESP32WiFi::run(void) + { + String readString; + String tempString; + String strRSSI; + + if (WiFi.isConnected() == false) + { + if (_isDebugEnabled) + { + Serial.println(F("**********************************************************")); + Serial.println(F("**** WiFi Disconnected. ESP32 should auto-reconnect. ***")); + Serial.println(F("**********************************************************")); + } + //WiFi.reconnect(); + //init(); + } + else + { + if (millis() - previousMillis > RSSIsendInterval) + { + + previousMillis = millis(); + + if (RSSIsendInterval < RSSI_TX_INTERVAL) + { + RSSIsendInterval = RSSIsendInterval + 1000; + } + + strRSSI = String("rssi ") + String(WiFi.RSSI()); + send(strRSSI); + + if (_isDebugEnabled) + { + Serial.println(strRSSI); + } + } + } + + WiFiClient client = st_server.available(); + if (client) { + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + //read char by char HTTP request + if (readString.length() < 200) { + //store characters to string + readString += c; + } + else + { + if (_isDebugEnabled) + { + Serial.println(F("")); + Serial.println(F("SmartThings.run() - Exceeded 200 character limit")); + Serial.println(F("")); + } + } + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + //now output HTML data header + tempString = readString.substring(readString.indexOf('/') + 1, readString.indexOf('?')); + + if (tempString.length() > 0) { + client.println(F("HTTP/1.1 200 OK")); //send new page + client.println(); + } + else { + client.println(F("HTTP/1.1 204 No Content")); + client.println(); + client.println(); + if (_isDebugEnabled) + { + Serial.println(F("No Valid Data Received")); + } + } + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } + else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + + delay(1); + //stopping client + client.stop(); + + //Handle the received data after cleaning up the network connection + if (tempString.length() > 0) { + if (_isDebugEnabled) + { + Serial.print(F("Handling request from ST. tempString = ")); + Serial.println(tempString); + } + //Pass the message to user's SmartThings callout function + tempString.replace("%20", " "); //Clean up for Hubitat + _calloutFunction(tempString); + } + + readString = ""; + tempString = ""; + } + } + + //******************************************************************************* + /// Send Message out over Ethernet to the Hub + //******************************************************************************* + void SmartThingsESP32WiFi::send(String message) + { + if (WiFi.isConnected() == false) + { + if (_isDebugEnabled) + { + Serial.println(F("**********************************************************")); + Serial.println(F("**** WiFi Disconnected. ESP32 should auto-reconnect. ***")); + Serial.println(F("**********************************************************")); + } + + //WiFi.reconnect(); + //init(); + } + + //WiFiClient st_client; + + //Make sure the client is stopped, to free up socket for new connection + st_client.stop(); + + if (st_client.connect(st_hubIP, st_hubPort)) + { + st_client.println(F("POST / HTTP/1.1")); + st_client.print(F("HOST: ")); + st_client.print(st_hubIP); + st_client.print(F(":")); + st_client.println(st_hubPort); + st_client.println(F("CONTENT-TYPE: text")); + st_client.println(F("CONNECTION: CLOSE")); + st_client.print(F("CONTENT-LENGTH: ")); + st_client.println(message.length()); + st_client.println(); + st_client.print(message); + } + else + { + //connection failed; + if (_isDebugEnabled) + { + Serial.println(F("***********************************************************")); + Serial.println(F("***** SmartThings.send() - Ethernet Connection Failed *****")); + Serial.println(F("***********************************************************")); + Serial.print(F("hubIP = ")); + Serial.print(st_hubIP); + Serial.print(F(" ")); + Serial.print(F("hubPort = ")); + Serial.println(st_hubPort); + + Serial.println(F("***********************************************************")); + Serial.println(F("**** WiFi Disconnected. ESP32 should auto-reconnect. ***")); + Serial.println(F("***********************************************************")); + } + + //WiFi.reconnect(); + //init(); //Re-Init connection to get things working again + + if (_isDebugEnabled) + { + Serial.println(F("***********************************************************")); + Serial.println(F("****** Attempting to resend missed data *******")); + Serial.println(F("***********************************************************")); + } + + + st_client.flush(); + st_client.stop(); + if (st_client.connect(st_hubIP, st_hubPort)) + { + st_client.println(F("POST / HTTP/1.1")); + st_client.print(F("HOST: ")); + st_client.print(st_hubIP); + st_client.print(F(":")); + st_client.println(st_hubPort); + st_client.println(F("CONTENT-TYPE: text")); + st_client.print(F("CONTENT-LENGTH: ")); + st_client.println(message.length()); + st_client.println(); + st_client.println(message); + } + + } + + // Wait for a response + unsigned long timeout = millis(); + while(!st_client.available()) + { + if(millis() - timeout > 1000) + { + Serial.println(F("Post request timed out\n")); + st_client.stop(); + return; + } + } + + + //if (_isDebugEnabled) { Serial.println(F("WiFi.send(): Reading for reply data "));} + // read any data returned from the POST + //while (st_client.connected()) { + while (st_client.available() && st_client.connected()) { + char c = st_client.read(); //gets byte from ethernet buffer + /*if((int) c == 255) + { + if(_isDebugEnabled) + Serial.println(F("Breaking due to invalid value")); + break; + }*/ + if (_isDebugEnabled) { Serial.print(c); } //prints byte to serial monitor + } + + delay(1); + st_client.stop(); + } +} diff --git a/lib/SmartThingsESP32WiFi/SmartThingsESP32WiFi.h b/lib/SmartThingsESP32WiFi/SmartThingsESP32WiFi.h new file mode 100644 index 0000000..e940849 --- /dev/null +++ b/lib/SmartThingsESP32WiFi/SmartThingsESP32WiFi.h @@ -0,0 +1,113 @@ +//******************************************************************************* +// SmartThings Arduino ESP32 Wifi Library +// +// License +// (C) Copyright 2017 Dan Ogorchock +// +// History +// 2017-08-15 Dan Ogorchock Created with the help of Joshua Spain +// 2017-09-05 Dan Ogorchock Added automatic WiFi reconnect logic as ESP32 +// doesn't do this automatically currently +// 2018-01-01 Dan Ogorchock Added WiFi.RSSI() data collection +// 2019-05-01 Dan Ogorchock Changed max transmit rate from every 100ms to every +// 500ms to prevent duplicate child devices +// 2020-06-20 Dan Ogorchock Add user selectable host name (repurposing the old shieldType variable) +// +//******************************************************************************* + +#ifndef __SMARTTHINGSESP32WIFI_H__ +#define __SMARTTHINGSESP32WIFI_H__ + +#include "SmartThingsEthernet.h" + +//******************************************************************************* +// Using ESP32 WiFi +//******************************************************************************* +#include + +namespace st +{ + class SmartThingsESP32WiFi: public SmartThingsEthernet + { + private: + //ESP32 WiFi Specific + char st_ssid[50]; + char st_password[50]; + static int disconnectCounter; + boolean st_preExistingConnection = false; + WiFiServer st_server; //server + WiFiClient st_client; //client + long previousMillis; + long RSSIsendInterval; + char st_devicename[50]; + + //************************************************************************************** + /// Event Handler for ESP32 WiFi Events (needed to implement reconnect logic for now...) + //************************************************************************************** + static void WiFiEvent(WiFiEvent_t event); + + public: + //******************************************************************************* + /// @brief SmartThings ESP32 WiFi Constructor - Static IP + /// @param[in] ssid - Wifi Network SSID + /// @param[in] password - Wifi Network Password + /// @param[in] localIP - TCP/IP Address of the Arduino + /// @param[in] localGateway - TCP/IP Gateway Address of local LAN (your Router's LAN Address) + /// @param[in] localSubnetMask - Subnet Mask of the Arduino + /// @param[in] localDNSServer - DNS Server + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsESP32WiFi(String ssid, String password, IPAddress localIP, IPAddress localGateway, IPAddress localSubnetMask, IPAddress localDNSServer, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "ESP32Wifi", bool enableDebug = false, int transmitInterval = 500); + + //******************************************************************************* + /// @brief SmartThings ESP32 WiFi Constructor - DHCP + /// @param[in] ssid - Wifi Network SSID + /// @param[in] password - Wifi Network Password + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsESP32WiFi(String ssid, String password, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "ESP32Wifi", bool enableDebug = false, int transmitInterval = 500); + + //******************************************************************************* + /// @brief SmartThings ESP32 WiFi Constructor - Pre-existing connection + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsESP32WiFi(uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "ESP32Wifi", bool enableDebug = false, int transmitInterval = 500); + + //******************************************************************************* + /// Destructor + //******************************************************************************* + ~SmartThingsESP32WiFi(); + + //******************************************************************************* + /// Initialize SmartThingsESP32WiFI Library + //******************************************************************************* + virtual void init(void); + + //******************************************************************************* + /// Run SmartThingsESP32WiFI Library + //******************************************************************************* + virtual void run(void); + + //******************************************************************************* + /// Send Message to the Hub + //******************************************************************************* + virtual void send(String message); + + }; +} +#endif diff --git a/lib/SmartThingsESP8266WiFi/SmartThingsESP8266WiFi.cpp b/lib/SmartThingsESP8266WiFi/SmartThingsESP8266WiFi.cpp new file mode 100644 index 0000000..a493570 --- /dev/null +++ b/lib/SmartThingsESP8266WiFi/SmartThingsESP8266WiFi.cpp @@ -0,0 +1,384 @@ +//******************************************************************************* +// SmartThings NodeMCU ESP8266 Wifi Library +// +// License +// (C) Copyright 2017 Dan Ogorchock +// +// History +// 2017-02-10 Dan Ogorchock Created +// 2017-12-29 Dan Ogorchock Added WiFi.RSSI() data collection +// 2018-01-06 Dan Ogorchock Simplified the MAC address printout to prevent confusion +// 2018-01-06 Dan Ogorchock Added OTA update capability +// 2018-02-03 Dan Ogorchock Support for Hubitat +// 2018-12-10 Dan Ogorchock Add user selectable host name (repurposing the old shieldType variable) +// 2019-06-03 Dan Ogorchock Changed to wait on st_client.available() instead of st_client.connected() +// 2019-06-25 Dan Ogorchock Fix default hostname to not use underscore character +//******************************************************************************* + +#include "SmartThingsESP8266WiFi.h" + +namespace st +{ + //******************************************************************************* + // SmartThingsESP8266WiFI Constructor - Static IP + //******************************************************************************* + SmartThingsESP8266WiFi::SmartThingsESP8266WiFi(String ssid, String password, IPAddress localIP, IPAddress localGateway, IPAddress localSubnetMask, IPAddress localDNSServer, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThingsEthernet(localIP, localGateway, localSubnetMask, localDNSServer, serverPort, hubIP, hubPort, callout, shieldType, enableDebug, transmitInterval, false), + st_server(serverPort) + { + ssid.toCharArray(st_ssid, sizeof(st_ssid)); + password.toCharArray(st_password, sizeof(st_password)); + } + + //******************************************************************************* + // SmartThingsESP8266WiFI Constructor - DHCP + //******************************************************************************* + SmartThingsESP8266WiFi::SmartThingsESP8266WiFi(String ssid, String password, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThingsEthernet(serverPort, hubIP, hubPort, callout, shieldType, enableDebug, transmitInterval, true), + st_server(serverPort) + { + ssid.toCharArray(st_ssid, sizeof(st_ssid)); + password.toCharArray(st_password, sizeof(st_password)); + } + + //******************************************************************************* + // SmartThingsESP8266WiFI Constructor - DHCP + //******************************************************************************* + SmartThingsESP8266WiFi::SmartThingsESP8266WiFi(uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThingsEthernet(serverPort, hubIP, hubPort, callout, shieldType, enableDebug, transmitInterval, true), + st_server(serverPort) + { + st_preExistingConnection = true; + } + + //***************************************************************************** + //SmartThingsESP8266WiFI::~SmartThingsESP8266WiFI() + //***************************************************************************** + SmartThingsESP8266WiFi::~SmartThingsESP8266WiFi() + { + + } + + //******************************************************************************* + /// Initialize SmartThingsESP8266WiFI Library + //******************************************************************************* + void SmartThingsESP8266WiFi::init(void) + { + if (!st_preExistingConnection) { + Serial.println(F("")); + Serial.println(F("Initializing ESP8266 WiFi network. Please be patient...")); + + if (st_DHCP == false) + { + WiFi.config(st_localIP, st_localGateway, st_localSubnetMask, st_localDNSServer); + } + // attempt to connect to WiFi network + WiFi.begin(st_ssid, st_password); + Serial.print(F("Attempting to connect to WPA SSID: ")); + Serial.println(st_ssid); + } + + while (WiFi.status() != WL_CONNECTED) { + Serial.print(F(".")); + delay(500); // wait for connection: + } + + Serial.println(); + + st_server.begin(); + + Serial.println(F("")); + Serial.println(F("Enter the following three lines of data into ST App on your phone!")); + Serial.print(F("localIP = ")); + Serial.println(WiFi.localIP()); + Serial.print(F("serverPort = ")); + Serial.println(st_serverPort); + Serial.print(F("MAC Address = ")); + String strMAC(WiFi.macAddress()); + strMAC.replace(":", ""); + Serial.println(strMAC); + Serial.println(F("")); + Serial.print(F("SSID = ")); + Serial.println(st_ssid); + Serial.print(F("PASSWORD = ")); + Serial.println(st_password); + Serial.print(F("hubIP = ")); + Serial.println(st_hubIP); + Serial.print(F("hubPort = ")); + Serial.println(st_hubPort); + Serial.print(F("RSSI = ")); + Serial.println(WiFi.RSSI()); + + if (_shieldType == "ESP8266Wifi") { + String("ESP8266-" + strMAC).toCharArray(st_devicename, sizeof(st_devicename)); + } + else { + _shieldType.toCharArray(st_devicename, sizeof(st_devicename)); + } + Serial.print(F("hostName = ")); + Serial.println(st_devicename); + + WiFi.hostname(st_devicename); + + Serial.println(F("")); + Serial.println(F("SmartThingsESP8266WiFI: Intialized")); + Serial.println(F("")); + + //Turn off Wirelss Access Point + Serial.println(F("Disabling ESP8266 WiFi Access Point")); + Serial.println(F("")); + WiFi.mode(WIFI_STA); + + RSSIsendInterval = 5000; + previousMillis = millis() - RSSIsendInterval; + + // Setup OTA Updates + + // Port defaults to 8266 + // ArduinoOTA.setPort(8266); + + // Hostname defaults to esp8266-[ChipID] + ArduinoOTA.setHostname(st_devicename); + + // No authentication by default + //ArduinoOTA.setPassword((const char*)"123"); + + ArduinoOTA.onStart([]() { + Serial.println("Start"); + }); + ArduinoOTA.onEnd([]() { + Serial.println("\nEnd"); + }); + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("Progress: %u%%\r", (progress / (total / 100))); + }); + ArduinoOTA.onError([](ota_error_t error) { + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); + else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); + else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); + else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); + else if (error == OTA_END_ERROR) Serial.println("End Failed"); + }); + ArduinoOTA.begin(); + Serial.println("ArduinoOTA Ready"); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + Serial.print("ArduionOTA Host Name: "); + Serial.println(ArduinoOTA.getHostname()); + Serial.println(); + } + + //***************************************************************************** + // Run SmartThingsESP8266WiFI Library + //***************************************************************************** + void SmartThingsESP8266WiFi::run(void) + { + + ArduinoOTA.handle(); + + String readString; + String tempString; + String strRSSI; + + if (WiFi.isConnected() == false) + { + if (_isDebugEnabled) + { + Serial.println(F("**********************************************************")); + Serial.println(F("**** WiFi Disconnected. ESP8266 should auto-reconnect ***")); + Serial.println(F("**********************************************************")); + } + + //init(); + } + else + { + if (millis() - previousMillis > RSSIsendInterval) + { + + previousMillis = millis(); + + if (RSSIsendInterval < RSSI_TX_INTERVAL) + { + RSSIsendInterval = RSSIsendInterval + 1000; + } + + strRSSI = String("rssi ") + String(WiFi.RSSI()); + send(strRSSI); + + if (_isDebugEnabled) + { + Serial.println(strRSSI); + } + } + } + + WiFiClient client = st_server.available(); + if (client) { + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + //read char by char HTTP request + if (readString.length() < 200) { + //store characters to string + readString += c; + } + else + { + if (_isDebugEnabled) + { + Serial.println(F("")); + Serial.println(F("SmartThings.run() - Exceeded 200 character limit")); + Serial.println(F("")); + } + } + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + //now output HTML data header + tempString = readString.substring(readString.indexOf('/') + 1, readString.indexOf('?')); + + if (tempString.length() > 0) { + client.println(F("HTTP/1.1 200 OK")); //send new page + client.println(); + } + else { + client.println(F("HTTP/1.1 204 No Content")); + client.println(); + client.println(); + if (_isDebugEnabled) + { + Serial.println(F("No Valid Data Received")); + } + } + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } + else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + + delay(1); + //stopping client + client.stop(); + + //Handle the received data after cleaning up the network connection + if (tempString.length() > 0) { + if (_isDebugEnabled) + { + Serial.print(F("Handling request from ST. tempString = ")); + Serial.println(tempString); + } + //Pass the message to user's SmartThings callout function + tempString.replace("%20", " "); //Clean up for Hubitat + _calloutFunction(tempString); + } + + readString = ""; + tempString = ""; + } + } + + //******************************************************************************* + /// Send Message out over Ethernet to the Hub + //******************************************************************************* + void SmartThingsESP8266WiFi::send(String message) + { + if (WiFi.isConnected() == false) + { + if (_isDebugEnabled) + { + Serial.println(F("**********************************************************")); + Serial.println(F("**** WiFi Disconnected. ESP8266 should auto-reconnect ***")); + Serial.println(F("**********************************************************")); + } + + //init(); + } + + //Make sure the client is stopped, to free up socket for new conenction + st_client.stop(); + + if (st_client.connect(st_hubIP, st_hubPort)) + { + st_client.println(F("POST / HTTP/1.1")); + st_client.print(F("HOST: ")); + st_client.print(st_hubIP); + st_client.print(F(":")); + st_client.println(st_hubPort); + st_client.println(F("CONTENT-TYPE: text")); + st_client.print(F("CONTENT-LENGTH: ")); + st_client.println(message.length()); + st_client.println(); + st_client.println(message); + } + else + { + //connection failed; + if (_isDebugEnabled) + { + Serial.println(F("***********************************************************")); + Serial.println(F("***** SmartThings.send() - Ethernet Connection Failed *****")); + Serial.println(F("***********************************************************")); + Serial.print(F("hubIP = ")); + Serial.print(st_hubIP); + Serial.print(F(" ")); + Serial.print(F("hubPort = ")); + Serial.println(st_hubPort); + + Serial.println(F("***********************************************************")); + Serial.println(F("**** WiFi Disconnected. ESP8266 should auto-reconnect ****")); + Serial.println(F("***********************************************************")); + } + + //init(); //Re-Init connection to get things working again + + if (_isDebugEnabled) + { + Serial.println(F("***********************************************************")); + Serial.println(F("****** Attempting to resend missed data *******")); + Serial.println(F("***********************************************************")); + } + + + st_client.flush(); + st_client.stop(); + if (st_client.connect(st_hubIP, st_hubPort)) + { + st_client.println(F("POST / HTTP/1.1")); + st_client.print(F("HOST: ")); + st_client.print(st_hubIP); + st_client.print(F(":")); + st_client.println(st_hubPort); + st_client.println(F("CONTENT-TYPE: text")); + st_client.print(F("CONTENT-LENGTH: ")); + st_client.println(message.length()); + st_client.println(); + st_client.println(message); + } + + } + + //if (_isDebugEnabled) { Serial.println(F("WiFi.send(): Reading for reply data "));} + // read any data returned from the POST + //while (st_client.connected()) { + while (st_client.available()) { + char c = st_client.read(); //gets byte from ethernet buffer + //if (_isDebugEnabled) { Serial.print(c); } //prints byte to serial monitor + } + //} + + delay(1); + st_client.stop(); + } + +} diff --git a/lib/SmartThingsESP8266WiFi/SmartThingsESP8266WiFi.h b/lib/SmartThingsESP8266WiFi/SmartThingsESP8266WiFi.h new file mode 100644 index 0000000..d08e4ad --- /dev/null +++ b/lib/SmartThingsESP8266WiFi/SmartThingsESP8266WiFi.h @@ -0,0 +1,107 @@ +//******************************************************************************* +// SmartThings Arduino ESP8266 Wifi Library +// +// License +// (C) Copyright 2017 Dan Ogorchock +// +// History +// 2017-02-05 Dan Ogorchock Created +// 2017-12-29 Dan Ogorchock Added WiFi.RSSI() data collection +// 2018-01-06 Dan Ogorchock Added OTA update capability +// 2018-12-10 Dan Ogorchock Add user selectable host name (repurposing the old shieldType variable) +// 2019-05-01 Dan Ogorchock Changed max transmit rate from every 100ms to every +// 500ms to prevent duplicate child devices +//******************************************************************************* + +#ifndef __SMARTTHINGSESP8266WIFI_H__ +#define __SMARTTHINGSESP8266WIFI_H__ + +#include "SmartThingsEthernet.h" + +//******************************************************************************* +// Using ESP8266 WiFi +//******************************************************************************* +#include +#include + +namespace st +{ + class SmartThingsESP8266WiFi: public SmartThingsEthernet + { + private: + //ESP8266 WiFi Specific + char st_ssid[50]; + char st_password[50]; + boolean st_preExistingConnection = false; + WiFiServer st_server; //server + WiFiClient st_client; //client + long previousMillis; + long RSSIsendInterval; + char st_devicename[50]; + + public: + + //******************************************************************************* + /// @brief SmartThings ESP8266 WiFi Constructor - Static IP + /// @param[in] ssid - Wifi Network SSID + /// @param[in] password - Wifi Network Password + /// @param[in] localIP - TCP/IP Address of the Arduino + /// @param[in] localGateway - TCP/IP Gateway Address of local LAN (your Router's LAN Address) + /// @param[in] localSubnetMask - Subnet Mask of the Arduino + /// @param[in] localDNSServer - DNS Server + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsESP8266WiFi(String ssid, String password, IPAddress localIP, IPAddress localGateway, IPAddress localSubnetMask, IPAddress localDNSServer, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "ESP8266Wifi", bool enableDebug = false, int transmitInterval = 500); + + //******************************************************************************* + /// @brief SmartThings ESP8266 WiFi Constructor - DHCP + /// @param[in] ssid - Wifi Network SSID + /// @param[in] password - Wifi Network Password + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsESP8266WiFi(String ssid, String password, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "ESP8266Wifi", bool enableDebug = false, int transmitInterval = 500); + + //******************************************************************************* + /// @brief SmartThings ESP8266 WiFi Constructor - Pre-existing connection + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsESP8266WiFi(uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "ESP8266Wifi", bool enableDebug = false, int transmitInterval = 500); + + //******************************************************************************* + /// Destructor + //******************************************************************************* + ~SmartThingsESP8266WiFi(); + + //******************************************************************************* + /// Initialize SmartThingsESP8266WiFI Library + //******************************************************************************* + virtual void init(void); + + //******************************************************************************* + /// Run SmartThingsESP8266WiFI Library + //******************************************************************************* + virtual void run(void); + + //******************************************************************************* + /// Send Message to the Hub + //******************************************************************************* + virtual void send(String message); + + }; +} +#endif diff --git a/lib/SmartThingsEthernetW5x00/SmartThingsEthernetW5x00.cpp b/lib/SmartThingsEthernetW5x00/SmartThingsEthernetW5x00.cpp new file mode 100644 index 0000000..6b2681c --- /dev/null +++ b/lib/SmartThingsEthernetW5x00/SmartThingsEthernetW5x00.cpp @@ -0,0 +1,269 @@ +//******************************************************************************* +// SmartThings Arduino Ethernet Library +// +// License +// (C) Copyright 2017 Dan Ogorchock +// +// History +// 2017-02-04 Dan Ogorchock Created +// 2018-01-06 Dan Ogorchock Simplified the MAC address printout to prevent confusion +// 2018-02-03 Dan Ogorchock Support for Hubitat +// 2020-04-05 Dan Ogorchock Tweaked to hopefully prevent lockup +// 2020-04-18 Dan Ogorchock Unified Arduino Ethernet Shield Class for 5100, 5200, 5500 +//******************************************************************************* + +#include "SmartThingsEthernetW5x00.h" + +namespace st +{ + //******************************************************************************* + // SmartThingsEthernet Constructor + //******************************************************************************* + SmartThingsEthernetW5x00::SmartThingsEthernetW5x00(byte mac[], IPAddress localIP, IPAddress localGateway, IPAddress localSubnetMask, IPAddress localDNSServer, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThingsEthernet(localIP, localGateway, localSubnetMask, localDNSServer, serverPort, hubIP, hubPort, callout, shieldType, enableDebug, transmitInterval), + st_server(serverPort) + { + //make a local copy of the MAC address + for (byte x = 0; x <= 5; x++) + { + st_mac[x] = mac[x]; + } + } + + //******************************************************************************* + // SmartThingsEthernet Constructor - DHCP + //******************************************************************************* + SmartThingsEthernetW5x00::SmartThingsEthernetW5x00(byte mac[], uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThingsEthernet(serverPort, hubIP, hubPort, callout, shieldType, enableDebug, transmitInterval, true), + st_server(serverPort) + { + //make a local copy of the MAC address + for (byte x = 0; x <= 5; x++) + { + st_mac[x] = mac[x]; + } + } + + //***************************************************************************** + //SmartThingsEthernet::~SmartThingsEthernet() + //***************************************************************************** + SmartThingsEthernetW5x00::~SmartThingsEthernetW5x00() + { + + } + + //******************************************************************************* + /// Initialize SmartThingsEthernet Library + //******************************************************************************* + void SmartThingsEthernetW5x00::init(void) + { + char buf[20]; + + // give the ethernet module time to boot up: + delay(1000); + + if (st_DHCP == false) + { + Ethernet.begin(st_mac, st_localIP, st_localDNSServer, st_localGateway, st_localSubnetMask); + } + else + { + Ethernet.begin(st_mac); + } + + st_server.begin(); + + + //if (_isDebugEnabled) + //{ + Serial.println(F("")); + Serial.println(F("Enter the following three lines of data into ST App on your phone!")); + Serial.print(F("localIP = ")); + Serial.println(Ethernet.localIP()); + Serial.print(F("serverPort = ")); + Serial.println(st_serverPort); + Serial.print(F("MAC Address = ")); + sprintf(buf, "%02X%02X%02X%02X%02X%02X", st_mac[0], st_mac[1], st_mac[2], st_mac[3], st_mac[4], st_mac[5]); + Serial.println(buf); + Serial.println(F("")); + + Serial.print(F("hubIP = ")); + Serial.println(st_hubIP); + Serial.print(F("hubPort = ")); + Serial.println(st_hubPort); + + Serial.println(F("")); + Serial.println(F("SmartThingsEthernet: Intialized")); + Serial.println(F("")); + //} + } + + //***************************************************************************** + // Run SmartThingsEthernet Library + //***************************************************************************** + void SmartThingsEthernetW5x00::run(void) + { + String readString; + String tempString; + + if (st_DHCP) { Ethernet.maintain(); } //Renew DHCP lease if necessary + + EthernetClient client = st_server.available(); + if (client) { + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + //read char by char HTTP request + if (readString.length() < 200) { + //store characters to string + readString += c; + } + else + { + if (_isDebugEnabled) + { + Serial.println(F("")); + Serial.println(F("SmartThings.run() - Exceeded 200 character limit")); + Serial.println(F("")); + } + } + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + //now output HTML data header + tempString = readString.substring(readString.indexOf('/') + 1, readString.indexOf('?')); + + if (tempString.length() > 0) { + client.println(F("HTTP/1.1 200 OK")); //send new page + client.println(); + } + else { + client.println(F("HTTP/1.1 204 No Content")); + client.println(); + client.println(); + if (_isDebugEnabled) + { + Serial.println(F("No Valid Data Received")); + } + } + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } + else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + + delay(1); + //stopping client + client.stop(); + + //Handle the received data after cleaning up the network connection + if (tempString.length() > 0) { + if (_isDebugEnabled) + { + Serial.print(F("Handling request from ST. tempString = ")); + Serial.println(tempString); + } + //Pass the message to user's SmartThings callout function + tempString.replace("%20", " "); //Clean up for Hubitat + _calloutFunction(tempString); + } + + readString = ""; + tempString = ""; + } + } + + //******************************************************************************* + /// Send Message out over Ethernet to the Hub + //******************************************************************************* + void SmartThingsEthernetW5x00::send(String message) + { + //Make sure the client is stopped, to free up socket for new conenction + st_client.stop(); + + if (st_client.connect(st_hubIP, st_hubPort)) + { + st_client.println(F("POST / HTTP/1.1")); + st_client.print(F("HOST: ")); + st_client.print(st_hubIP); + st_client.print(F(":")); + st_client.println(st_hubPort); + st_client.println(F("CONTENT-TYPE: text")); + st_client.print(F("CONTENT-LENGTH: ")); + st_client.println(message.length()); + st_client.println(); + st_client.println(message); + } + else + { + //connection failed; + if (_isDebugEnabled) + { + Serial.println(F("***********************************************************")); + Serial.println(F("***** SmartThings.send() - Ethernet Connection Failed *****")); + Serial.println(F("***********************************************************")); + Serial.print(F("hubIP = ")); + Serial.print(st_hubIP); + Serial.print(F(" ")); + Serial.print(F("hubPort = ")); + Serial.println(st_hubPort); + + Serial.println(F("***********************************************************")); + Serial.println(F("****** Attempting to restart network *******")); + Serial.println(F("***********************************************************")); + } + + + init(); //Re-Init connection to get things working again + + if (_isDebugEnabled) + { + Serial.println(F("***********************************************************")); + Serial.println(F("****** Attempting to resend missed data *******")); + Serial.println(F("***********************************************************")); + } + + + st_client.flush(); + st_client.stop(); + if (st_client.connect(st_hubIP, st_hubPort)) + { + st_client.println(F("POST / HTTP/1.1")); + st_client.print(F("HOST: ")); + st_client.print(st_hubIP); + st_client.print(F(":")); + st_client.println(st_hubPort); + st_client.println(F("CONTENT-TYPE: text")); + st_client.print(F("CONTENT-LENGTH: ")); + st_client.println(message.length()); + st_client.println(); + st_client.println(message); + } + + } + + //if (_isDebugEnabled) { Serial.println(F("Ethernet.send(): Reading for reply data "));} + // read any data returned from the POST + while (st_client.connected()) { + if (st_client.available()) { + char c = st_client.read(); //gets byte from ethernet buffer + //if (_isDebugEnabled) { Serial.print(c); } //prints byte to serial monitor + } else { + break; + } + } + + delay(1); + st_client.stop(); + } + +} diff --git a/lib/SmartThingsEthernetW5x00/SmartThingsEthernetW5x00.h b/lib/SmartThingsEthernetW5x00/SmartThingsEthernetW5x00.h new file mode 100644 index 0000000..940a54d --- /dev/null +++ b/lib/SmartThingsEthernetW5x00/SmartThingsEthernetW5x00.h @@ -0,0 +1,89 @@ +//******************************************************************************* +// SmartThings Arduino Ethernet Library +// +// License +// (C) Copyright 2017 Dan Ogorchock +// +// History +// 2017-02-04 Dan Ogorchock Created +// 2017-05-02 Dan Ogorchock Minor tweak to coexist peacefully with newer W5500 shield +// 2019-05-01 Dan Ogorchock Changed max transmit rate from every 100ms to every +// 500ms to prevent duplicate child devices +// 2020-04-18 Dan Ogorchock Unified Arduino Ethernet Shield Class for 5100, 5200, 5500 +//******************************************************************************* + +#ifndef __SMARTTHINGSETHERNETW5x00_H__ +#define __SMARTTHINGSETHERNETW5x00_H__ + + +#include "SmartThingsEthernet.h" +#include +#include + +//******************************************************************************* +// Using Ethernet Shield +//******************************************************************************* + +namespace st +{ + class SmartThingsEthernetW5x00: public SmartThingsEthernet + { + private: + //Ethernet W5x00 Specific + byte st_mac[6]; + EthernetServer st_server; //server + EthernetClient st_client; //client + + public: + + //******************************************************************************* + /// @brief SmartThings Ethernet Constructor + /// @param[in] mac[] - MAC Address of the Ethernet Shield, 6 bytes + /// @param[in] localIP - TCP/IP Address of the Arduino + /// @param[in] localGateway - TCP/IP Gateway Address of local LAN (your Router's LAN Address) + /// @param[in] localSubnetMask - Subnet Mask of the Arduino + /// @param[in] localDNSServer - DNS Server + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsEthernetW5x00(byte mac[], IPAddress localIP, IPAddress localGateway, IPAddress localSubnetMask, IPAddress localDNSServer, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "EthernetShield", bool enableDebug = false, int transmitInterval = 500); + + //******************************************************************************* + /// @brief SmartThings Ethernet Constructor - DHCP + /// @param[in] mac[] - MAC Address of the Ethernet Shield, 6 bytes + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsEthernetW5x00(byte mac[], uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "EthernetShield", bool enableDebug = false, int transmitInterval = 500); + + //******************************************************************************* + /// Destructor + //******************************************************************************* + ~SmartThingsEthernetW5x00(); + + //******************************************************************************* + /// Initialize SmartThingsEthernet Library + //******************************************************************************* + virtual void init(void); + + //******************************************************************************* + /// Run SmartThingsEthernet Library + //******************************************************************************* + virtual void run(void); + + //******************************************************************************* + /// Send Message to the Hub + //******************************************************************************* + virtual void send(String message); + + }; +} +#endif diff --git a/lib/SmartThingsWiFi101/SmartThingsWiFi101.cpp b/lib/SmartThingsWiFi101/SmartThingsWiFi101.cpp new file mode 100644 index 0000000..9b2be06 --- /dev/null +++ b/lib/SmartThingsWiFi101/SmartThingsWiFi101.cpp @@ -0,0 +1,329 @@ +//******************************************************************************* +// SmartThings Arduino Wifi101 Library - Use an Arduino with an Arduino WiFi 101 +// shield or Adafruit ATWINC1500 +// +// License +// (C) Copyright 2017 Dan Ogorchock +// +// History +// 2017-05-06 Dan Ogorchock Created +// 2017-05-29 Dan Ogorchock Implemented Low Power Mode to reduce power usage/chip heat +// 2018-01-01 Dan Ogorchock Added WiFi.RSSI() data collection +// 2018-01-06 Dan Ogorchock Simplified the MAC address printout to prevent confusion +// 2018-02-03 Dan Ogorchock Support for Hubitat +// 2020-04-05 Dan Ogorchock Tweaked to hopefully prevent lockup +//******************************************************************************* + +#include "SmartThingsWiFi101.h" + +namespace st +{ + //******************************************************************************* + // SmartThingsWiFi101 Constructor - Arduino + WiFi 101 - STATIC IP + //******************************************************************************* + SmartThingsWiFi101::SmartThingsWiFi101(String ssid, String password, IPAddress localIP, IPAddress localGateway, IPAddress localSubnetMask, IPAddress localDNSServer, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThingsEthernet(localIP, localGateway, localSubnetMask, localDNSServer, serverPort, hubIP, hubPort, callout, shieldType, enableDebug, transmitInterval, false), + st_server(serverPort) + { + ssid.toCharArray(st_ssid, sizeof(st_ssid)); + password.toCharArray(st_password, sizeof(st_password)); + } + + //***************************************************************************** + // SmartThingsWiFi101 Constructor - Arduino + WiFi 101 - DHCP + //***************************************************************************** + SmartThingsWiFi101::SmartThingsWiFi101(String ssid, String password, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThingsEthernet(serverPort, hubIP, hubPort, callout, shieldType, enableDebug, transmitInterval, true), + st_server(serverPort) + { + ssid.toCharArray(st_ssid, sizeof(st_ssid)); + password.toCharArray(st_password, sizeof(st_password)); + } + + + //***************************************************************************** + //SmartThingsWiFi101::~SmartThingsWiFi101() + //***************************************************************************** + SmartThingsWiFi101::~SmartThingsWiFi101() + { + + } + + //******************************************************************************* + /// Initialize SmartThingsWiFi101 Library + //******************************************************************************* + void SmartThingsWiFi101::init(void) + { + int status = WL_IDLE_STATUS; // the Wifi radio's status + + Serial.println(F("")); + Serial.println(F("Initializing WiFi 101 network. Please be patient...")); + + // check for the presence of the shield + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi 101 shield not present"); + // don't continue + while (true); + } + + // attempt to connect to WiFi network + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(st_ssid); + // Connect to WPA/WPA2 network + status = WiFi.begin(st_ssid, st_password); + // wait 5 seconds for connection: + delay(5000); + } + + if (st_DHCP == false) + { + // Set the local IP address + WiFi.config(st_localIP, st_localDNSServer, st_localGateway, st_localSubnetMask); + } + + WiFi.lowPowerMode(); //Reduce power usage when IDLE + + st_server.begin(); + + uint8_t mac[6]; + char buf[20]; + IPAddress ip = WiFi.localIP(); + Serial.println(); + Serial.println(F("Enter the following three lines of data into ST App on your phone!")); + Serial.print(F("localIP = ")); + Serial.println(ip); + Serial.print(F("serverPort = ")); + Serial.println(st_serverPort); + WiFi.macAddress(mac); + Serial.print(F("MAC Address = ")); + sprintf(buf, "%02X%02X%02X%02X%02X%02X", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]); + Serial.println(buf); + Serial.println(); + + Serial.print(F("SSID = ")); + Serial.println(st_ssid); + Serial.print(F("PASSWORD = ")); + Serial.println(st_password); + Serial.print(F("hubIP = ")); + Serial.println(st_hubIP); + Serial.print(F("hubPort = ")); + Serial.println(st_hubPort); + Serial.print(F("RSSI = ")); + Serial.println(WiFi.RSSI()); + Serial.println(); + Serial.println(F("SmartThingsWiFi101: Intialized")); + Serial.println(); + + RSSIsendInterval = 5000; + previousMillis = millis() - RSSIsendInterval; + } + + //***************************************************************************** + // Run SmartThingsWiFi101 Library + //***************************************************************************** + void SmartThingsWiFi101::run(void) + { + String readString; + String tempString; + String strRSSI; + + if (WiFi.status() != WL_CONNECTED) + { + if (_isDebugEnabled) + { + Serial.println(F("**********************************************************")); + Serial.println(F("**** WiFi Disconnected. Attempting restart! ******")); + Serial.println(F("**********************************************************")); + WiFi.end(); + init(); + } + } + else + { + if (millis() - previousMillis > RSSIsendInterval) + { + + previousMillis = millis(); + + if (RSSIsendInterval < RSSI_TX_INTERVAL) + { + RSSIsendInterval = RSSIsendInterval + 1000; + } + + strRSSI = String("rssi ") + String(WiFi.RSSI()); + send(strRSSI); + + if (_isDebugEnabled) + { + Serial.println(strRSSI); + } + } + } + + WiFiClient client = st_server.available(); + if (client) { + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + //read char by char HTTP request + if (readString.length() < 200) { + //store characters to string + readString += c; + } + else + { + if (_isDebugEnabled) + { + Serial.println(F("")); + Serial.println(F("SmartThings.run() - Exceeded 200 character limit")); + Serial.println(F("")); + } + } + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + //now output HTML data header + tempString = readString.substring(readString.indexOf('/') + 1, readString.indexOf('?')); + + if (tempString.length() > 0) { + client.println(F("HTTP/1.1 200 OK")); //send new page + client.println(); + } + else { + client.println(F("HTTP/1.1 204 No Content")); + client.println(); + client.println(); + if (_isDebugEnabled) + { + Serial.println(F("No Valid Data Received")); + } + } + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } + else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + + delay(1); + //stopping client + client.stop(); + + //Handle the received data after cleaning up the network connection + if (tempString.length() > 0) { + if (_isDebugEnabled) + { + Serial.print(F("Handling request from ST. tempString = ")); + Serial.println(tempString); + } + //Pass the message to user's SmartThings callout function + tempString.replace("%20", " "); //Clean up for Hubitat + _calloutFunction(tempString); + } + + readString = ""; + tempString = ""; + } + } + + //******************************************************************************* + /// Send Message out over Ethernet to the Hub + //******************************************************************************* + void SmartThingsWiFi101::send(String message) + { + if (WiFi.status() != WL_CONNECTED) + { + Serial.println(F("**********************************************************")); + Serial.println(F("**** WiFi Module Disconnected. Attempting restart! ******")); + Serial.println(F("**********************************************************")); + WiFi.end(); + init(); + } + + //Make sure the client is stopped, to free up socket for new conenction + st_client.stop(); + + if (st_client.connect(st_hubIP, st_hubPort)) + { + st_client.println(F("POST / HTTP/1.1")); + st_client.print(F("HOST: ")); + st_client.print(st_hubIP); + st_client.print(F(":")); + st_client.println(st_hubPort); + st_client.println(F("CONTENT-TYPE: text")); + st_client.print(F("CONTENT-LENGTH: ")); + st_client.println(message.length()); + st_client.println(); + st_client.println(message); + } + else + { + //connection failed; + if (_isDebugEnabled) + { + Serial.println(F("***********************************************************")); + Serial.println(F("***** SmartThings.send() - Ethernet Connection Failed *****")); + Serial.println(F("***********************************************************")); + Serial.print(F("hubIP = ")); + Serial.print(st_hubIP); + Serial.print(F(" ")); + Serial.print(F("hubPort = ")); + Serial.println(st_hubPort); + + Serial.println(F("***********************************************************")); + Serial.println(F("****** Attempting to restart network *******")); + Serial.println(F("***********************************************************")); + } + + WiFi.end(); //End current broken WiFi Connection + init(); //Re-Init connection to get things working again + + if (_isDebugEnabled) + { + Serial.println(F("***********************************************************")); + Serial.println(F("****** Attempting to resend missed data *******")); + Serial.println(F("***********************************************************")); + } + + + st_client.flush(); + st_client.stop(); + if (st_client.connect(st_hubIP, st_hubPort)) + { + st_client.println(F("POST / HTTP/1.1")); + st_client.print(F("HOST: ")); + st_client.print(st_hubIP); + st_client.print(F(":")); + st_client.println(st_hubPort); + st_client.println(F("CONTENT-TYPE: text")); + st_client.print(F("CONTENT-LENGTH: ")); + st_client.println(message.length()); + st_client.println(); + st_client.println(message); + } + + } + + //if (_isDebugEnabled) { Serial.println(F("WiFi.send(): Reading for reply data "));} + // read any data returned from the POST + //while (st_client.connected()) { + while (st_client.available()) { + char c = st_client.read(); //gets byte from ethernet buffer + //if (_isDebugEnabled) { Serial.print(c); } //prints byte to serial monitor + //} + } + + delay(1); + st_client.stop(); + } + +} diff --git a/lib/SmartThingsWiFi101/SmartThingsWiFi101.h b/lib/SmartThingsWiFi101/SmartThingsWiFi101.h new file mode 100644 index 0000000..9e0f5d8 --- /dev/null +++ b/lib/SmartThingsWiFi101/SmartThingsWiFi101.h @@ -0,0 +1,95 @@ +//******************************************************************************* +// SmartThings Arduino Wifi101 Library - Use an Arduino with an Arduino WiFi 101 +// shield or Adafruit ATWINC1500 +// +// License +// (C) Copyright 2017 Dan Ogorchock +// +// History +// 2017-05-06 Dan Ogorchock Created +// 2018-01-01 Dan Ogorchock Added WiFi.RSSI() data collection +// 2019-05-01 Dan Ogorchock Changed max transmit rate from every 100ms to every +// 500ms to prevent duplicate child devices +//******************************************************************************* + +#ifndef __SMARTTHINGSWIFI101_H__ +#define __SMARTTHINGSWIFI101_H__ + + +#include "SmartThingsEthernet.h" + +//******************************************************************************* +// Using WiFi101 library for the Arduino WiFi 101 shield or Adafruit ATWINC1500 +//******************************************************************************* +#include +#include + + +namespace st +{ + class SmartThingsWiFi101: public SmartThingsEthernet + { + private: + //WiFi Specific + char st_ssid[50]; + char st_password[50]; + WiFiServer st_server; //server + WiFiClient st_client; //client + long previousMillis; + long RSSIsendInterval; + + public: + + //******************************************************************************* + /// @brief SmartThings Arduino + WiFi 101 Constructor - STATIC IP + /// @param[in] ssid - Wifi Network SSID + /// @param[in] password - Wifi Network Password + /// @param[in] localIP - TCP/IP Address of the Arduino + /// @param[in] localGateway - TCP/IP Gateway Address of local LAN (your Router's LAN Address) + /// @param[in] localSubnetMask - Subnet Mask of the Arduino + /// @param[in] localDNSServer - DNS Server + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsWiFi101(String ssid, String password, IPAddress localIP, IPAddress localGateway, IPAddress localSubnetMask, IPAddress localDNSServer, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "Wifi101", bool enableDebug = true, int transmitInterval = 500); + + //******************************************************************************* + /// @brief SmartThings Arduino + WiFi Constructor 101 - DHCP + /// @param[in] ssid - Wifi Network SSID + /// @param[in] password - Wifi Network Password + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsWiFi101(String ssid, String password, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "WiFi101", bool enableDebug = false, int transmitInterval = 500); + + //******************************************************************************* + /// Destructor + //******************************************************************************* + ~SmartThingsWiFi101(); + + //******************************************************************************* + /// Initialize SmartThingsWiFi101 Library + //******************************************************************************* + virtual void init(void); + + //******************************************************************************* + /// Run SmartThingsWiFi101 Library + //******************************************************************************* + virtual void run(void); + + //******************************************************************************* + /// Send Message to the Hub + //******************************************************************************* + virtual void send(String message); + + }; +} +#endif diff --git a/lib/SmartThingsWiFiEsp/SmartThingsWiFiEsp.cpp b/lib/SmartThingsWiFiEsp/SmartThingsWiFiEsp.cpp new file mode 100644 index 0000000..357e782 --- /dev/null +++ b/lib/SmartThingsWiFiEsp/SmartThingsWiFiEsp.cpp @@ -0,0 +1,328 @@ +//******************************************************************************* +// SmartThings Arduino WifiEsp Library - Use an Arduino with an ESP-01 for WiFi +// +// License +// (C) Copyright 2017 Dan Ogorchock +// +// History +// 2017-02-20 Dan Ogorchock Created +// 2018-01-06 Dan Ogorchock Added WiFi.RSSI() data collection +// 2018-01-06 Dan Ogorchock Simplified the MAC address printout to prevent confusion +// 2018-02-03 Dan Ogorchock Support for Hubitat +// 2020-04-05 Dan Ogorchock Tweaked to hopefully prevent lockup +//******************************************************************************* + +#include "SmartThingsWiFiEsp.h" + +namespace st +{ + //******************************************************************************* + // SmartThingsWiFiEsp Constructor - Arduino + ESP-01 board - STATIC IP + //******************************************************************************* + SmartThingsWiFiEsp::SmartThingsWiFiEsp(Stream *espSerial, String ssid, String password, IPAddress localIP, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThingsEthernet(localIP, serverPort, hubIP, hubPort, callout, shieldType, enableDebug, transmitInterval, false), + st_server(serverPort), + st_espSerial(espSerial) + { + ssid.toCharArray(st_ssid, sizeof(st_ssid)); + password.toCharArray(st_password, sizeof(st_password)); + } + + //******************************************************************************* + // SmartThingsWiFiEsp Constructor - Arduino + ESP-01 board - DHCP + //******************************************************************************* + SmartThingsWiFiEsp::SmartThingsWiFiEsp(Stream *espSerial, String ssid, String password, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThingsEthernet(serverPort, hubIP, hubPort, callout, shieldType, enableDebug, transmitInterval, true), + st_server(serverPort), + st_espSerial(espSerial) + { + ssid.toCharArray(st_ssid, sizeof(st_ssid)); + password.toCharArray(st_password, sizeof(st_password)); + } + + + //***************************************************************************** + //SmartThingsWiFiEsp::~SmartThingsESP8266WiFI() + //***************************************************************************** + SmartThingsWiFiEsp::~SmartThingsWiFiEsp() + { + + } + + //******************************************************************************* + /// Initialize SmartThingsWiFiEsp Library + //******************************************************************************* + void SmartThingsWiFiEsp::init(void) + { + int status = WL_IDLE_STATUS; // the Wifi radio's status + + Serial.println(F("")); + Serial.println(F("Initializing WiFiEsp network. Please be patient...")); + + // Initialize the WiFiEsp library + WiFi.init(st_espSerial); + + // check for the presence of the shield + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("ESP WiFi shield not present"); + // don't continue + while (true); + } + + // attempt to connect to WiFi network + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(st_ssid); + // Connect to WPA/WPA2 network + status = WiFi.begin(st_ssid, st_password); + delay(1000); + } + + if (st_DHCP == false) + { + // Set the local IP address + WiFi.config(st_localIP); + } + + st_server.begin(); + + uint8_t mac[6]; + char buf[20]; + + Serial.println(F("")); + Serial.println(F("Enter the following three lines of data into ST App on your phone!")); + Serial.print(F("localIP = ")); + Serial.println(WiFi.localIP()); + Serial.print(F("serverPort = ")); + Serial.println(st_serverPort); + WiFi.macAddress(mac); + Serial.print(F("MAC Address = ")); + sprintf(buf, "%02X%02X%02X%02X%02X%02X", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]); + Serial.println(buf); + Serial.println(F("")); + + Serial.print(F("SSID = ")); + Serial.println(st_ssid); + Serial.print(F("PASSWORD = ")); + Serial.println(st_password); + Serial.print(F("hubIP = ")); + Serial.println(st_hubIP); + Serial.print(F("hubPort = ")); + Serial.println(st_hubPort); + Serial.print(F("RSSI = ")); + Serial.println(WiFi.RSSI()); + Serial.println(F("")); + Serial.println(F("SmartThingsWiFiEsp: Intialized")); + Serial.println(F("")); + + RSSIsendInterval = 5000; + previousMillis = millis() - RSSIsendInterval; + } + + //***************************************************************************** + // Run SmartThingsWiFiEsp Library + //***************************************************************************** + void SmartThingsWiFiEsp::run(void) + { + String readString; + String tempString; + String strRSSI; + + //if (WiFi.status() != WL_CONNECTED) + //{ + // Serial.println(F("**********************************************************")); + // Serial.println(F("**** WiFi Module Disconnected. Attempting restart! ******")); + // Serial.println(F("**********************************************************")); + // WiFi.reset(); + // init(); + //} + //else + //{ + if (millis() - previousMillis > RSSIsendInterval) + { + + previousMillis = millis(); + + if (RSSIsendInterval < RSSI_TX_INTERVAL) + { + RSSIsendInterval = RSSIsendInterval + 1000; + } + + strRSSI = String("rssi ") + String(WiFi.RSSI()); + send(strRSSI); + + if (_isDebugEnabled) + { + Serial.println(strRSSI); + } + } + //} + + WiFiEspClient client = st_server.available(); + if (client) { + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + //read char by char HTTP request + if (readString.length() < 200) { + //store characters to string + readString += c; + } + else + { + if (_isDebugEnabled) + { + Serial.println(F("")); + Serial.println(F("SmartThings.run() - Exceeded 200 character limit")); + Serial.println(F("")); + } + } + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + //now output HTML data header + tempString = readString.substring(readString.indexOf('/') + 1, readString.indexOf('?')); + + if (tempString.length() > 0) { + client.println(F("HTTP/1.1 200 OK")); //send new page + client.println(); + } + else { + client.println(F("HTTP/1.1 204 No Content")); + client.println(); + client.println(); + if (_isDebugEnabled) + { + Serial.println(F("No Valid Data Received")); + } + } + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } + else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + + delay(1); + //stopping client + client.stop(); + + //Handle the received data after cleaning up the network connection + if (tempString.length() > 0) { + if (_isDebugEnabled) + { + Serial.print(F("Handling request from ST. tempString = ")); + Serial.println(tempString); + } + //Pass the message to user's SmartThings callout function + tempString.replace("%20", " "); //Clean up for Hubitat + _calloutFunction(tempString); + } + + readString = ""; + tempString = ""; + } + } + + //******************************************************************************* + /// Send Message out over Ethernet to the Hub + //******************************************************************************* + void SmartThingsWiFiEsp::send(String message) + { + st_client.stop(); + + //if (WiFi.status() != WL_CONNECTED) + //{ + // Serial.println(F("**********************************************************")); + // Serial.println(F("**** WiFi Module Disconnected. Attempting restart! ******")); + // Serial.println(F("**********************************************************")); + // WiFi.reset(); + // init(); + //} + + //Make sure the client is stopped, to free up socket for new conenction + st_client.stop(); + + if (st_client.connect(st_hubIP, st_hubPort)) + { + st_client.println(F("POST / HTTP/1.1")); + st_client.print(F("HOST: ")); + st_client.print(st_hubIP); + st_client.print(F(":")); + st_client.println(st_hubPort); + st_client.println(F("CONTENT-TYPE: text")); + st_client.print(F("CONTENT-LENGTH: ")); + st_client.println(message.length()); + st_client.println(); + st_client.println(message); + } + else + { + //connection failed; + if (_isDebugEnabled) + { + Serial.println(F("***********************************************************")); + Serial.println(F("***** SmartThings.send() - Ethernet Connection Failed *****")); + Serial.println(F("***********************************************************")); + Serial.print(F("hubIP = ")); + Serial.print(st_hubIP); + Serial.print(F(" ")); + Serial.print(F("hubPort = ")); + Serial.println(st_hubPort); + + Serial.println(F("***********************************************************")); + Serial.println(F("**** WiFi Disconnected. ESP8266 should auto-reconnect ****")); + Serial.println(F("***********************************************************")); + } + + //WiFi.reset();//End current broken WiFi Connection + //init(); //Re-Init connection to get things working again + + if (_isDebugEnabled) + { + Serial.println(F("***********************************************************")); + Serial.println(F("****** Attempting to resend missed data *******")); + Serial.println(F("***********************************************************")); + } + + + st_client.flush(); + st_client.stop(); + if (st_client.connect(st_hubIP, st_hubPort)) + { + st_client.println(F("POST / HTTP/1.1")); + st_client.print(F("HOST: ")); + st_client.print(st_hubIP); + st_client.print(F(":")); + st_client.println(st_hubPort); + st_client.println(F("CONTENT-TYPE: text")); + st_client.print(F("CONTENT-LENGTH: ")); + st_client.println(message.length()); + st_client.println(); + st_client.println(message); + } + + } + + //if (_isDebugEnabled) { Serial.println(F("WiFi.send(): Reading for reply data "));} + // read any data returned from the POST + //while (st_client.connected()) { + while (st_client.available()) { + char c = st_client.read(); //gets byte from ethernet buffer + //if (_isDebugEnabled) { Serial.print(c); } //prints byte to serial monitor + //} + } + + delay(1); + st_client.stop(); + } + +} diff --git a/lib/SmartThingsWiFiEsp/SmartThingsWiFiEsp.h b/lib/SmartThingsWiFiEsp/SmartThingsWiFiEsp.h new file mode 100644 index 0000000..9f4367e --- /dev/null +++ b/lib/SmartThingsWiFiEsp/SmartThingsWiFiEsp.h @@ -0,0 +1,94 @@ +//******************************************************************************* +// SmartThings Arduino WifiEsp Library - Use an Arduino with an ESP-01 for WiFi +// +// License +// (C) Copyright 2017 Dan Ogorchock +// +// History +// 2017-02-20 Dan Ogorchock Created +// 2018-01-06 Dan Ogorchock Added WiFi.RSSI() data collection +// 2019-05-01 Dan Ogorchock Changed max transmit rate from every 100ms to every +// 500ms to prevent duplicate child devices +//******************************************************************************* + +#ifndef __SMARTTHINGSWIFIESP_H__ +#define __SMARTTHINGSWIFIESP_H__ + + +#include "SmartThingsEthernet.h" + +//******************************************************************************* +// Using WiFiEsp library for the ESP-01 board +//******************************************************************************* +#include + + +namespace st +{ + class SmartThingsWiFiEsp: public SmartThingsEthernet + { + private: + //WiFi Specific + char st_ssid[50]; + char st_password[50]; + WiFiEspServer st_server; //server + WiFiEspClient st_client; //client + Stream* st_espSerial; //Serial UART used to commincate with the ESP-01 board + long previousMillis; + long RSSIsendInterval; + + public: + + //******************************************************************************* + /// @brief SmartThings Arduino + ESP-01 WiFi Constructor - STATIC IP + /// @param[in] espSerial - Pointer to an initialized Hardware Serial device (e.g. Serial1, Serial2, or Serial3) + /// @param[in] ssid - Wifi Network SSID + /// @param[in] password - Wifi Network Password + /// @param[in] localIP - TCP/IP Address of the Arduino + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsWiFiEsp(Stream *espSerial, String ssid, String password, IPAddress localIP, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "WiFiESP", bool enableDebug = true, int transmitInterval = 500); + + //******************************************************************************* + /// @brief SmartThings Arduino + ESP-01 WiFi Constructor - DHCP + /// @param[in] espSerial - Pointer to an initialized Hardware Serial device (e.g. Serial1, Serial2, or Serial3) + /// @param[in] ssid - Wifi Network SSID + /// @param[in] password - Wifi Network Password + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsWiFiEsp(Stream *espSerial, String ssid, String password, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "WiFiESP", bool enableDebug = false, int transmitInterval = 500); + + //******************************************************************************* + /// Destructor + //******************************************************************************* + ~SmartThingsWiFiEsp(); + + //******************************************************************************* + /// Initialize SmartThingsWiFiEsp Library + //******************************************************************************* + virtual void init(void); + + //******************************************************************************* + /// Run SmartThingsWiFiEsp Library + //******************************************************************************* + virtual void run(void); + + //******************************************************************************* + /// Send Message to the Hub + //******************************************************************************* + virtual void send(String message); + + }; +} +#endif + diff --git a/lib/SmartThingsWiFiNINA/SmartThingsWiFiNINA.cpp b/lib/SmartThingsWiFiNINA/SmartThingsWiFiNINA.cpp new file mode 100644 index 0000000..8172f6d --- /dev/null +++ b/lib/SmartThingsWiFiNINA/SmartThingsWiFiNINA.cpp @@ -0,0 +1,334 @@ +//******************************************************************************* +// SmartThings Arduino WiFiNINA Library - Use an Arduino MKR 1010, NANO33IoT +// or similar boards +// +// +// License +// (C) Copyright 2019 Dan Ogorchock +// +// History +// 2019-06-23 Dan Ogorchock Created +// 2019-08-17 Dan Ogorchock NANO33IoT +// 2020-04-05 Dan Ogorchock Tweaked to hopefully prevent lockup +// +//******************************************************************************* + + +#include "SmartThingsWiFiNINA.h" + +namespace st +{ + //******************************************************************************* + // SmartThingsWiFiNINA Constructor - Arduino + WiFi - STATIC IP + //******************************************************************************* + SmartThingsWiFiNINA::SmartThingsWiFiNINA(String ssid, String password, IPAddress localIP, IPAddress localGateway, IPAddress localSubnetMask, IPAddress localDNSServer, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThingsEthernet(localIP, localGateway, localSubnetMask, localDNSServer, serverPort, hubIP, hubPort, callout, shieldType, enableDebug, transmitInterval, false), + st_server(serverPort) + { + ssid.toCharArray(st_ssid, sizeof(st_ssid)); + password.toCharArray(st_password, sizeof(st_password)); + } + + //***************************************************************************** + // SmartThingsWiFiNINA Constructor - Arduino + WiFi - DHCP + //***************************************************************************** + SmartThingsWiFiNINA::SmartThingsWiFiNINA(String ssid, String password, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType, bool enableDebug, int transmitInterval) : + SmartThingsEthernet(serverPort, hubIP, hubPort, callout, shieldType, enableDebug, transmitInterval, true), + st_server(serverPort) + { + ssid.toCharArray(st_ssid, sizeof(st_ssid)); + password.toCharArray(st_password, sizeof(st_password)); + } + + + //***************************************************************************** + //SmartThingsWiFiNINA::~SmartThingsWiFiNINA() + //***************************************************************************** + SmartThingsWiFiNINA::~SmartThingsWiFiNINA() + { + + } + + //******************************************************************************* + /// Initialize SmartThingsWiFiNINA Library + //******************************************************************************* + void SmartThingsWiFiNINA::init(void) + { + int status = WL_IDLE_STATUS; // the Wifi radio's status + + Serial.println(F("")); + Serial.println(F("Initializing WiFi NINA network. Please be patient...")); + + // check for the presence of the shield + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < "1.0.0") { + Serial.println("Please upgrade the WiFi module's firmware"); + } + + // attempt to connect to WiFi network + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(st_ssid); + // Connect to WPA/WPA2 network + status = WiFi.begin(st_ssid, st_password); + // wait 5 seconds for connection: + delay(5000); + } + + if (st_DHCP == false) + { + // Set the local IP address + WiFi.config(st_localIP, st_localDNSServer, st_localGateway, st_localSubnetMask); + } + + //WiFi.lowPowerMode(); //Reduce power usage when IDLE + + st_server.begin(); + + uint8_t mac[6]; + char buf[20]; + IPAddress ip = WiFi.localIP(); + Serial.println(); + Serial.println(F("Enter the following three lines of data into ST App on your phone!")); + Serial.print(F("localIP = ")); + Serial.println(ip); + Serial.print(F("serverPort = ")); + Serial.println(st_serverPort); + WiFi.macAddress(mac); + Serial.print(F("MAC Address = ")); + sprintf(buf, "%02X%02X%02X%02X%02X%02X", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]); + Serial.println(buf); + Serial.println(); + + Serial.print(F("SSID = ")); + Serial.println(st_ssid); + Serial.print(F("PASSWORD = ")); + Serial.println(st_password); + Serial.print(F("hubIP = ")); + Serial.println(st_hubIP); + Serial.print(F("hubPort = ")); + Serial.println(st_hubPort); + Serial.print(F("RSSI = ")); + Serial.println(WiFi.RSSI()); + Serial.println(); + Serial.println(F("SmartThingsWiFiNINA: Intialized")); + Serial.println(); + + RSSIsendInterval = 5000; + previousMillis = millis() - RSSIsendInterval; + } + + //***************************************************************************** + // Run SmartThingsWiFiNINA Library + //***************************************************************************** + void SmartThingsWiFiNINA::run(void) + { + String readString; + String tempString; + String strRSSI; + + if (WiFi.status() != WL_CONNECTED) + { + if (_isDebugEnabled) + { + Serial.println(F("**********************************************************")); + Serial.println(F("**** WiFi Disconnected. Attempting restart! ******")); + Serial.println(F("**********************************************************")); + WiFi.end(); + init(); + } + } + else + { + if (millis() - previousMillis > RSSIsendInterval) + { + + previousMillis = millis(); + + if (RSSIsendInterval < RSSI_TX_INTERVAL) + { + RSSIsendInterval = RSSIsendInterval + 1000; + } + + strRSSI = String("rssi ") + String(WiFi.RSSI()); + send(strRSSI); + + if (_isDebugEnabled) + { + Serial.println(strRSSI); + } + } + } + + WiFiClient client = st_server.available(); + if (client) { + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + //read char by char HTTP request + if (readString.length() < 200) { + //store characters to string + readString += c; + } + else + { + if (_isDebugEnabled) + { + Serial.println(F("")); + Serial.println(F("SmartThings.run() - Exceeded 200 character limit")); + Serial.println(F("")); + } + } + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + //now output HTML data header + tempString = readString.substring(readString.indexOf('/') + 1, readString.indexOf('?')); + + if (tempString.length() > 0) { + client.println(F("HTTP/1.1 200 OK")); //send new page + client.println(); + } + else { + client.println(F("HTTP/1.1 204 No Content")); + client.println(); + client.println(); + if (_isDebugEnabled) + { + Serial.println(F("No Valid Data Received")); + } + } + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } + else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + + delay(1); + //stopping client + client.stop(); + + //Handle the received data after cleaning up the network connection + if (tempString.length() > 0) { + if (_isDebugEnabled) + { + Serial.print(F("Handling request from ST. tempString = ")); + Serial.println(tempString); + } + //Pass the message to user's SmartThings callout function + tempString.replace("%20", " "); //Clean up for Hubitat + _calloutFunction(tempString); + } + + readString = ""; + tempString = ""; + } + } + + //******************************************************************************* + /// Send Message out over Ethernet to the Hub + //******************************************************************************* + void SmartThingsWiFiNINA::send(String message) + { + if (WiFi.status() != WL_CONNECTED) + { + Serial.println(F("**********************************************************")); + Serial.println(F("**** WiFi Module Disconnected. Attempting restart! ******")); + Serial.println(F("**********************************************************")); + WiFi.end(); + init(); + } + + //Make sure the client is stopped, to free up socket for new conenction + st_client.stop(); + + if (st_client.connect(st_hubIP, st_hubPort)) + { + st_client.println(F("POST / HTTP/1.1")); + st_client.print(F("HOST: ")); + st_client.print(st_hubIP); + st_client.print(F(":")); + st_client.println(st_hubPort); + st_client.println(F("CONTENT-TYPE: text")); + st_client.print(F("CONTENT-LENGTH: ")); + st_client.println(message.length()); + st_client.println(); + st_client.println(message); + } + else + { + //connection failed; + if (_isDebugEnabled) + { + Serial.println(F("***********************************************************")); + Serial.println(F("***** SmartThings.send() - Ethernet Connection Failed *****")); + Serial.println(F("***********************************************************")); + Serial.print(F("hubIP = ")); + Serial.print(st_hubIP); + Serial.print(F(" ")); + Serial.print(F("hubPort = ")); + Serial.println(st_hubPort); + + Serial.println(F("***********************************************************")); + Serial.println(F("****** Attempting to restart network *******")); + Serial.println(F("***********************************************************")); + } + + WiFi.end(); //End current broken WiFi Connection + init(); //Re-Init connection to get things working again + + if (_isDebugEnabled) + { + Serial.println(F("***********************************************************")); + Serial.println(F("****** Attempting to resend missed data *******")); + Serial.println(F("***********************************************************")); + } + + + st_client.flush(); + st_client.stop(); + if (st_client.connect(st_hubIP, st_hubPort)) + { + st_client.println(F("POST / HTTP/1.1")); + st_client.print(F("HOST: ")); + st_client.print(st_hubIP); + st_client.print(F(":")); + st_client.println(st_hubPort); + st_client.println(F("CONTENT-TYPE: text")); + st_client.print(F("CONTENT-LENGTH: ")); + st_client.println(message.length()); + st_client.println(); + st_client.println(message); + } + + } + + //if (_isDebugEnabled) { Serial.println(F("WiFi.send(): Reading for reply data "));} + // read any data returned from the POST + //while (st_client.connected()) { + while (st_client.available()) { + char c = st_client.read(); //gets byte from ethernet buffer + //if (_isDebugEnabled) { Serial.print(c); } //prints byte to serial monitor + } + //} + + delay(1); + st_client.stop(); + } + +} diff --git a/lib/SmartThingsWiFiNINA/SmartThingsWiFiNINA.h b/lib/SmartThingsWiFiNINA/SmartThingsWiFiNINA.h new file mode 100644 index 0000000..e789a73 --- /dev/null +++ b/lib/SmartThingsWiFiNINA/SmartThingsWiFiNINA.h @@ -0,0 +1,95 @@ +//******************************************************************************* +// SmartThings Arduino WiFiNINA Library - Use an Arduino MKR 1010, NANO33IoT +// or similar boards +// +// +// License +// (C) Copyright 2019 Dan Ogorchock +// +// History +// 2019-06-23 Dan Ogorchock Created +// 2019-08-17 Dan Ogorchock NANO33IoT +// +//******************************************************************************* + +#ifndef __SMARTTHINGSWIFININA_H__ +#define __SMARTTHINGSWIFININA_H__ + + +#include "SmartThingsEthernet.h" + +//******************************************************************************* +// Using WiFiNINA library for the Arduino MKR 1010 or similar +//******************************************************************************* +#include +#include + + +namespace st +{ + class SmartThingsWiFiNINA: public SmartThingsEthernet + { + private: + //WiFi Specific + char st_ssid[50]; + char st_password[50]; + WiFiServer st_server; //server + WiFiClient st_client; //client + long previousMillis; + long RSSIsendInterval; + + public: + + //******************************************************************************* + /// @brief SmartThings Arduino + WiFi Constructor - STATIC IP + /// @param[in] ssid - Wifi Network SSID + /// @param[in] password - Wifi Network Password + /// @param[in] localIP - TCP/IP Address of the Arduino + /// @param[in] localGateway - TCP/IP Gateway Address of local LAN (your Router's LAN Address) + /// @param[in] localSubnetMask - Subnet Mask of the Arduino + /// @param[in] localDNSServer - DNS Server + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsWiFiNINA(String ssid, String password, IPAddress localIP, IPAddress localGateway, IPAddress localSubnetMask, IPAddress localDNSServer, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "WiFiNINA", bool enableDebug = true, int transmitInterval = 500); + + //******************************************************************************* + /// @brief SmartThings Arduino + WiFi Constructor - DHCP + /// @param[in] ssid - Wifi Network SSID + /// @param[in] password - Wifi Network Password + /// @param[in] serverPort - TCP/IP Port of the Arduino + /// @param[in] hubIP - TCP/IP Address of the ST Hub + /// @param[in] hubPort - TCP/IP Port of the ST Hub + /// @param[in] callout - Set the Callout Function that is called on Msg Reception + /// @param[in] shieldType (optional) - Set the Reported SheildType to the Server + /// @param[in] enableDebug (optional) - Enable internal Library debug + //******************************************************************************* + SmartThingsWiFiNINA(String ssid, String password, uint16_t serverPort, IPAddress hubIP, uint16_t hubPort, SmartThingsCallout_t *callout, String shieldType = "WiFiNINA", bool enableDebug = false, int transmitInterval = 500); + + //******************************************************************************* + /// Destructor + //******************************************************************************* + ~SmartThingsWiFiNINA(); + + //******************************************************************************* + /// Initialize SmartThingsWiFiNINA Library + //******************************************************************************* + virtual void init(void); + + //******************************************************************************* + /// Run SmartThingsWiFiNINA Library + //******************************************************************************* + virtual void run(void); + + //******************************************************************************* + /// Send Message to the Hub + //******************************************************************************* + virtual void send(String message); + + }; +} +#endif diff --git a/lib/WiFi101/CHANGELOG b/lib/WiFi101/CHANGELOG new file mode 100644 index 0000000..ce164c8 --- /dev/null +++ b/lib/WiFi101/CHANGELOG @@ -0,0 +1,155 @@ +WiFi101 ?.?.? - ????.??.?? + +WiFi101 0.16.0 - 2018.04.04 + +* Added WiFi.setTimeout(timeout) API to set timeout of WiFi.begin(...) +* Changed check firmware version comparision from == to >= +* Updated latest firmware version for model B to 19.6.1 + +WiFi101 0.15.3 - 2018.11.21 + +* Fixed unreachable destination issue in UDP packet transmission +* Changed where required, in library's examples, the server's URL arduino.cc\80 in example.org\80, because http://arduino.cc will be no longer available +* Changed the MAC address print in the library's example now are showed corectly all the MAC address chars +* Fixed WiFiUDP::endPacket() return value in accord with sendig returns. Thanks to @mjlitke @jrowberg +* Changed WiFiSocketClass::create(...) return condition. Thanks to @jrowberg +* Changed server and URL to avoid 301 response from Server +* Fixed initialization Server issue by adding socket initialization in WiFiServer::WiFiServer constructor + +WiFi101 0.15.2 - 2018.02.20 + +* Fixed issue with WiFiServer::begin() stopping first listening server + +WiFi101 0.15.1 - 2018.02.14 + +* Fixed compatibility with Arduino Due +* Fixed return code of WiFiUdp::endPacket(). Thanks @mlitke +* Fixed WiFiServer::available() hanging after WiFi.end() is called + +WiFi101 0.15.0 - 2018.01.02 + +* Fixed WiFi.status() hanging if no shield was present +* Reworked socket buffer layer to prevent (SAMD) and reduce lockups (AVR) +* Make reset pin optional. Thanks @awatterott +* Added ability to retrieve remote IP and port of WiFiClient + +WiFi101 0.14.3 - 2017.06.01 + +* Fixed issues with WiFiMDNSResponder and large request packets +* Fixed issues with WiFiClient and sending data after the socket is closed + +WiFi101 0.14.2 - 2017.05.08 + +* Fixed issues with WiFiServer::write not working + +WiFi101 0.14.1 - 2017.04.20 + +* Fixed issues with WiFiMDNSResponder and Windows using Bonjour +* Correct cast of buffer size when processing received data + +WiFi101 0.14.0 - 2017.03.22 + +* Added support for firmware 19.5.2 +* Add ability to create Access Point with WPA security (f/w 19.5.2 or higher) +* Add WiFi.hostname(name) method to set custom host name for DHCP (f/w 19.5.2 or higher) +* Enables support for AES-256 Ciphers (f/w 19.5.2 or higher) +* Make provisioning mode backwards compatible with f/w 19.4.4 and older + +WiFi101 0.13.0 - 2017.03.01 + +* Added WiFi.channel() and WiFi.BSSID() + +WiFi101 0.12.1 - 2017.01.19 + +* Fixed tomorrow day issue in WiFi.getTime() + +WiFi101 0.12.0 - 2017.01.05 + +* Made provisioning mode easier and added example sketch +* Fixed WiFi.getTime() not returning 0, if time has not been synced via NTP +* Fixed crashing when connecting after scanning +* Fixed WiFiServer::available() returning valid client on outbound client connection +* Added WiFiUdp::beginMulticast(port) function for compatiblity with EthernetUdp, as beginMulti was inconsistent + +WiFi101 0.11.2 - 2016.12.15 + +* Fixed value of WiFi.getTime() being off by one day +* Fixed calling WiFi.RSSI() causing lockups + +WiFi101 0.11.1 - 2016.11.29 + +* Fixed regression for non-AVR boards that resulted in corrupt with data over than 1400 bytes was received + +WiFi101 0.11.0 - 2016.11.14 + +* Changed WiFi.ping(...) to return round trip time on success, negative value on error. Thanks @PKGeorgiev +* WiFi.end() now powers down the WiFi module +* WiFi.config(ip) can now be used to set a static IP for WiFi.begin(...) +* Fixed WiFi.BSSID(bssid) returning reversed MAC address +* Added WiFi.APClientMacAddress() API to get MAC address of AP client in AP mode +* Added WiFi.getTime() API to get epoch from NTP + +WiFi101 0.10.0 - 2016.09.08 + +* Added WiFi.end() to disconnect from the AP or end AP mode +* Added new WiFi.ping(...) functionality. Thanks @PKGeorgiev +* Added WiFi.setPins(...) to customize the CS, INTN, RESET and CHIPEN pins +* Add new WL_AP_LISTENING, WL_AP_CONNECTED, and WL_AP_FAILED status types for AP mode +* Fixed return value of WiFiUDP::beginPacket(host, port) when host is successfully resolved +* Added power management methods: WiFi.lowPowerMode(), WiFi.maxLowPowerMode(), WiFi.noLowPowerMode() +* Close TCP sockets when physical link is disconnected +* Fixed WiFi.RSSI() returning 0 when there was pending socket data + +WiFi101 0.9.1 - 2016.04.19 + +* Increased compatibility with 3rd party boards and architectures. +* Rename WiFiMdnsResponder.h/cpp to WiFiMDNSResponder.h/cpp +* Fixed buffering of UDP packet + +WiFi101 0.9.0 - 2016.03.21 + +* Fixed WiFi.status() hanging when shield is not present +* Fixed MAC address returning 00:00:00:00:00:00 with firmware version 19.3.0 +* Fixed SSL write functionality with firmware version 19.3.0 +* Fixed previous version of the library not working on the Uno and other boards that used PCINT's +* Added beginAP(...) API's to create access point with WEP passwords +* Fixed beginAP(...) channel off by one error +* Fixed WiFi.status() always returning WL_CONNECTED once connected, even if access point is disconnected later +* Added beginMulti API for Multicast UDP support +* Added WiFiMDNSResponder class and MDNS Web server example + +WiFi101 0.8.0 - 2016.02.15 + +* Added example for Access Point web server (thanks @ladyada) +* Fixed MAC Address printed in reverse order +* Allow another library to override PCINT ISR (fix issues when using the WiFi101 + library with other libraries like SoftwareSerial) + +WiFi101 0.7.0 - 2015.01.11 + +* Added support for WiFi Firmware 19.4.4 +* WiFi.hostByName(...) will not try resolve the domain name if it's already a numeric IP +* Fixed manual IP configuration (no DHCP) +* Fixed WiFiServer.available(), now follows API specification +* Fixed WEP key connection +* Fixed WiFiClient copy constructor and assignment operator. This improves stability when + Client objects are assigned or returned from functions. +* Control pins are now configurable through defines from variant. + +WiFi101 0.6.0 - 2015.11.27 + +* Fixed bug with AVR boards when Web Server is used +* Fixed UDP read bug on AVR Boards +* Added missing inlcude for SSL Client +* Fixed peek() function +* Fixed some examples + +WiFi101 0.5.1 - 2015.10.06 + +* Improved support for AVR Boards (Uno, Mega, Leonardo, etc.) and + ARM based boards (Due and Zero). + +WiFi101 0.5.0 - 2015.10.01 + +* Initial release + diff --git a/lib/WiFi101/README.adoc b/lib/WiFi101/README.adoc new file mode 100644 index 0000000..8eb6924 --- /dev/null +++ b/lib/WiFi101/README.adoc @@ -0,0 +1,27 @@ += WiFi library for the Arduino WiFi Shield 101 and MKR1000 board = + +image:https://travis-ci.org/arduino-libraries/WiFi101.svg?branch=master["Build Status", link="https://travis-ci.org/arduino-libraries/WiFi101"] + +This library implements a network driver for devices based +on the ATMEL WINC1500 WiFi module. + +For more information about this library please visit us at +https://www.arduino.cc/en/Reference/WiFi101 + +== License == + +Copyright (c) Arduino LLC. All right reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/lib/WiFi101/examples/AP_SimpleWebServer/AP_SimpleWebServer.ino b/lib/WiFi101/examples/AP_SimpleWebServer/AP_SimpleWebServer.ino new file mode 100644 index 0000000..f77c518 --- /dev/null +++ b/lib/WiFi101/examples/AP_SimpleWebServer/AP_SimpleWebServer.ino @@ -0,0 +1,179 @@ +/* + WiFi Web Server LED Blink + + A simple web server that lets you blink an LED via the web. + This sketch will create a new access point (with no password). + It will then launch a new server and print out the IP address + to the Serial monitor. From there, you can open that address in a web browser + to turn on and off the LED on pin 13. + + If the IP address of your shield is yourAddress: + http://yourAddress/H turns the LED on + http://yourAddress/L turns it off + + created 25 Nov 2012 + by Tom Igoe + adapted to WiFi AP by Adafruit + */ + +#include +#include +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key Index number (needed only for WEP) + +int led = LED_BUILTIN; +int status = WL_IDLE_STATUS; +WiFiServer server(80); + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + Serial.println("Access Point Web Server"); + + pinMode(led, OUTPUT); // set the LED pin mode + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue + while (true); + } + + // by default the local IP address of will be 192.168.1.1 + // you can override it with the following: + // WiFi.config(IPAddress(10, 0, 0, 1)); + + // print the network name (SSID); + Serial.print("Creating access point named: "); + Serial.println(ssid); + + // Create open network. Change this line if you want to create an WEP network: + status = WiFi.beginAP(ssid); + if (status != WL_AP_LISTENING) { + Serial.println("Creating access point failed"); + // don't continue + while (true); + } + + // wait 10 seconds for connection: + delay(10000); + + // start the web server on port 80 + server.begin(); + + // you're connected now, so print out the status + printWiFiStatus(); +} + + +void loop() { + // compare the previous status to the current status + if (status != WiFi.status()) { + // it has changed update the variable + status = WiFi.status(); + + if (status == WL_AP_CONNECTED) { + byte remoteMac[6]; + + // a device has connected to the AP + Serial.print("Device connected to AP, MAC address: "); + WiFi.APClientMacAddress(remoteMac); + printMacAddress(remoteMac); + } else { + // a device has disconnected from the AP, and we are back in listening mode + Serial.println("Device disconnected from AP"); + } + } + + WiFiClient client = server.available(); // listen for incoming clients + + if (client) { // if you get a client, + Serial.println("new client"); // print a message out the serial port + String currentLine = ""; // make a String to hold incoming data from the client + while (client.connected()) { // loop while the client's connected + if (client.available()) { // if there's bytes to read from the client, + char c = client.read(); // read a byte, then + Serial.write(c); // print it out the serial monitor + if (c == '\n') { // if the byte is a newline character + + // if the current line is blank, you got two newline characters in a row. + // that's the end of the client HTTP request, so send a response: + if (currentLine.length() == 0) { + // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) + // and a content-type so the client knows what's coming, then a blank line: + client.println("HTTP/1.1 200 OK"); + client.println("Content-type:text/html"); + client.println(); + + // the content of the HTTP response follows the header: + client.print("Click here turn the LED on
"); + client.print("Click here turn the LED off
"); + + // The HTTP response ends with another blank line: + client.println(); + // break out of the while loop: + break; + } + else { // if you got a newline, then clear currentLine: + currentLine = ""; + } + } + else if (c != '\r') { // if you got anything else but a carriage return character, + currentLine += c; // add it to the end of the currentLine + } + + // Check to see if the client request was "GET /H" or "GET /L": + if (currentLine.endsWith("GET /H")) { + digitalWrite(led, HIGH); // GET /H turns the LED on + } + if (currentLine.endsWith("GET /L")) { + digitalWrite(led, LOW); // GET /L turns the LED off + } + } + } + // close the connection: + client.stop(); + Serial.println("client disconnected"); + } +} + +void printWiFiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); + // print where to go in a browser: + Serial.print("To see this page in action, open a browser to http://"); + Serial.println(ip); + +} + +void printMacAddress(byte mac[]) { + for (int i = 5; i >= 0; i--) { + if (mac[i] < 16) { + Serial.print("0"); + } + Serial.print(mac[i], HEX); + if (i > 0) { + Serial.print(":"); + } + } + Serial.println(); +} diff --git a/lib/WiFi101/examples/AP_SimpleWebServer/arduino_secrets.h b/lib/WiFi101/examples/AP_SimpleWebServer/arduino_secrets.h new file mode 100644 index 0000000..a8ff904 --- /dev/null +++ b/lib/WiFi101/examples/AP_SimpleWebServer/arduino_secrets.h @@ -0,0 +1,3 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" + diff --git a/lib/WiFi101/examples/CheckWifi101FirmwareVersion/CheckWifi101FirmwareVersion.ino b/lib/WiFi101/examples/CheckWifi101FirmwareVersion/CheckWifi101FirmwareVersion.ino new file mode 100644 index 0000000..6f69bc7 --- /dev/null +++ b/lib/WiFi101/examples/CheckWifi101FirmwareVersion/CheckWifi101FirmwareVersion.ino @@ -0,0 +1,67 @@ +/* + * This example check if the firmware loaded on the WiFi101 + * shield is updated. + * + * Circuit: + * - WiFi101 Shield attached + * + * Created 29 July 2015 by Cristian Maglie + * This code is in the public domain. + */ +#include +#include +#include + +void setup() { + // Initialize serial + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // Print a welcome message + Serial.println("WiFi101 firmware check."); + Serial.println(); + + // Check for the presence of the shield + Serial.print("WiFi101 shield: "); + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("NOT PRESENT"); + return; // don't continue + } + Serial.println("DETECTED"); + + // Print firmware version on the shield + String fv = WiFi.firmwareVersion(); + String latestFv; + Serial.print("Firmware version installed: "); + Serial.println(fv); + + if (REV(GET_CHIPID()) >= REV_3A0) { + // model B + latestFv = WIFI_FIRMWARE_LATEST_MODEL_B; + } else { + // model A + latestFv = WIFI_FIRMWARE_LATEST_MODEL_A; + } + + // Print required firmware version + Serial.print("Latest firmware version available : "); + Serial.println(latestFv); + + // Check if the latest version is installed + Serial.println(); + if (fv >= latestFv) { + Serial.println("Check result: PASSED"); + } else { + Serial.println("Check result: NOT PASSED"); + Serial.println(" - The firmware version on the shield do not match the"); + Serial.println(" version required by the library, you may experience"); + Serial.println(" issues or failures."); + } +} + +void loop() { + // do nothing +} + diff --git a/lib/WiFi101/examples/ConnectNoEncryption/ConnectNoEncryption.ino b/lib/WiFi101/examples/ConnectNoEncryption/ConnectNoEncryption.ino new file mode 100644 index 0000000..357b80d --- /dev/null +++ b/lib/WiFi101/examples/ConnectNoEncryption/ConnectNoEncryption.ino @@ -0,0 +1,115 @@ +/* + + This example connects to an unencrypted WiFi network. + Then it prints the MAC address of the WiFi shield, + the IP address obtained, and other network details. + + Circuit: + * WiFi shield attached + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ +#include +#include +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +int status = WL_IDLE_STATUS; // the WiFi radio's status + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // attempt to connect to WiFi network: + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to open SSID: "); + Serial.println(ssid); + status = WiFi.begin(ssid); + + // wait 10 seconds for connection: + delay(10000); + } + + // you're connected now, so print out the data: + Serial.print("You're connected to the network"); + printCurrentNet(); + printWiFiData(); +} + +void loop() { + // check the network connection once every 10 seconds: + delay(10000); + printCurrentNet(); +} + +void printWiFiData() { + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + Serial.println(ip); + + // print your MAC address: + byte mac[6]; + WiFi.macAddress(mac); + Serial.print("MAC address: "); + printMacAddress(mac); + + // print your subnet mask: + IPAddress subnet = WiFi.subnetMask(); + Serial.print("NetMask: "); + Serial.println(subnet); + + // print your gateway address: + IPAddress gateway = WiFi.gatewayIP(); + Serial.print("Gateway: "); + Serial.println(gateway); +} + +void printCurrentNet() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print the MAC address of the router you're attached to: + byte bssid[6]; + WiFi.BSSID(bssid); + Serial.print("BSSID: "); + printMacAddress(bssid); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.println(rssi); + + // print the encryption type: + byte encryption = WiFi.encryptionType(); + Serial.print("Encryption Type:"); + Serial.println(encryption, HEX); +} + +void printMacAddress(byte mac[]) { + for (int i = 5; i >= 0; i--) { + if (mac[i] < 16) { + Serial.print("0"); + } + Serial.print(mac[i], HEX); + if (i > 0) { + Serial.print(":"); + } + } + Serial.println(); +} diff --git a/lib/WiFi101/examples/ConnectNoEncryption/arduino_secrets.h b/lib/WiFi101/examples/ConnectNoEncryption/arduino_secrets.h new file mode 100644 index 0000000..07c1148 --- /dev/null +++ b/lib/WiFi101/examples/ConnectNoEncryption/arduino_secrets.h @@ -0,0 +1 @@ +#define SECRET_SSID "" diff --git a/lib/WiFi101/examples/ConnectWithWEP/ConnectWithWEP.ino b/lib/WiFi101/examples/ConnectWithWEP/ConnectWithWEP.ino new file mode 100644 index 0000000..7cbee26 --- /dev/null +++ b/lib/WiFi101/examples/ConnectWithWEP/ConnectWithWEP.ino @@ -0,0 +1,119 @@ +/* + + This example connects to a WEP-encrypted WiFi network. + Then it prints the MAC address of the WiFi shield, + the IP address obtained, and other network details. + + If you use 40-bit WEP, you need a key that is 10 characters long, + and the characters must be hexadecimal (0-9 or A-F). + e.g. for 40-bit, ABBADEAF01 will work, but ABBADEAF won't work + (too short) and ABBAISDEAF won't work (I and S are not + hexadecimal characters). + + For 128-bit, you need a string that is 26 characters long. + D0D0DEADF00DABBADEAFBEADED will work because it's 26 characters, + all in the 0-9, A-F range. + + Circuit: + * WiFi shield attached + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char key[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key Index number +int status = WL_IDLE_STATUS; // the WiFi radio's status + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // attempt to connect to WiFi network: + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to WEP network, SSID: "); + Serial.println(ssid); + status = WiFi.begin(ssid, keyIndex, key); + + // wait 10 seconds for connection: + delay(10000); + } + + // once you are connected : + Serial.print("You're connected to the network"); + printCurrentNet(); + printWiFiData(); +} + +void loop() { + // check the network connection once every 10 seconds: + delay(10000); + printCurrentNet(); +} + +void printWiFiData() { + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + Serial.println(ip); + + // print your MAC address: + byte mac[6]; + WiFi.macAddress(mac); + Serial.print("MAC address: "); + printMacAddress(mac); +} + +void printCurrentNet() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print the MAC address of the router you're attached to: + byte bssid[6]; + WiFi.BSSID(bssid); + Serial.print("BSSID: "); + printMacAddress(bssid); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.println(rssi); + + // print the encryption type: + byte encryption = WiFi.encryptionType(); + Serial.print("Encryption Type:"); + Serial.println(encryption, HEX); + Serial.println(); +} + +void printMacAddress(byte mac[]) { + for (int i = 5; i >= 0; i--) { + if (mac[i] < 16) { + Serial.print("0"); + } + Serial.print(mac[i], HEX); + if (i > 0) { + Serial.print(":"); + } + } + Serial.println(); +} diff --git a/lib/WiFi101/examples/ConnectWithWEP/arduino_secrets.h b/lib/WiFi101/examples/ConnectWithWEP/arduino_secrets.h new file mode 100644 index 0000000..a8ff904 --- /dev/null +++ b/lib/WiFi101/examples/ConnectWithWEP/arduino_secrets.h @@ -0,0 +1,3 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" + diff --git a/lib/WiFi101/examples/ConnectWithWPA/ConnectWithWPA.ino b/lib/WiFi101/examples/ConnectWithWPA/ConnectWithWPA.ino new file mode 100644 index 0000000..edf4cae --- /dev/null +++ b/lib/WiFi101/examples/ConnectWithWPA/ConnectWithWPA.ino @@ -0,0 +1,111 @@ +/* + + This example connects to an unencrypted WiFi network. + Then it prints the MAC address of the WiFi shield, + the IP address obtained, and other network details. + + Circuit: + * WiFi shield attached + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int status = WL_IDLE_STATUS; // the WiFi radio's status + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // attempt to connect to WiFi network: + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + + // you're connected now, so print out the data: + Serial.print("You're connected to the network"); + printCurrentNet(); + printWiFiData(); + +} + +void loop() { + // check the network connection once every 10 seconds: + delay(10000); + printCurrentNet(); +} + +void printWiFiData() { + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + Serial.println(ip); + + // print your MAC address: + byte mac[6]; + WiFi.macAddress(mac); + Serial.print("MAC address: "); + printMacAddress(mac); + +} + +void printCurrentNet() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print the MAC address of the router you're attached to: + byte bssid[6]; + WiFi.BSSID(bssid); + Serial.print("BSSID: "); + printMacAddress(bssid); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.println(rssi); + + // print the encryption type: + byte encryption = WiFi.encryptionType(); + Serial.print("Encryption Type:"); + Serial.println(encryption, HEX); + Serial.println(); +} + +void printMacAddress(byte mac[]) { + for (int i = 5; i >= 0; i--) { + if (mac[i] < 16) { + Serial.print("0"); + } + Serial.print(mac[i], HEX); + if (i > 0) { + Serial.print(":"); + } + } + Serial.println(); +} diff --git a/lib/WiFi101/examples/ConnectWithWPA/arduino_secrets.h b/lib/WiFi101/examples/ConnectWithWPA/arduino_secrets.h new file mode 100644 index 0000000..a8ff904 --- /dev/null +++ b/lib/WiFi101/examples/ConnectWithWPA/arduino_secrets.h @@ -0,0 +1,3 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" + diff --git a/lib/WiFi101/examples/FirmwareUpdater/Endianess.ino b/lib/WiFi101/examples/FirmwareUpdater/Endianess.ino new file mode 100644 index 0000000..897c770 --- /dev/null +++ b/lib/WiFi101/examples/FirmwareUpdater/Endianess.ino @@ -0,0 +1,62 @@ +/* + Endianess.ino - Network byte order conversion functions. + Copyright (c) 2015 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + +bool isBigEndian() { + uint32_t test = 0x11223344; + uint8_t *pTest = reinterpret_cast(&test); + return pTest[0] == 0x11; +} + +uint32_t fromNetwork32(uint32_t from) { + static const bool be = isBigEndian(); + if (be) { + return from; + } else { + uint8_t *pFrom = reinterpret_cast(&from); + uint32_t to; + to = pFrom[0]; to <<= 8; + to |= pFrom[1]; to <<= 8; + to |= pFrom[2]; to <<= 8; + to |= pFrom[3]; + return to; + } +} + +uint16_t fromNetwork16(uint16_t from) { + static bool be = isBigEndian(); + if (be) { + return from; + } else { + uint8_t *pFrom = reinterpret_cast(&from); + uint16_t to; + to = pFrom[0]; to <<= 8; + to |= pFrom[1]; + return to; + } +} + +uint32_t toNetwork32(uint32_t to) { + return fromNetwork32(to); +} + +uint16_t toNetwork16(uint16_t to) { + return fromNetwork16(to); +} + diff --git a/lib/WiFi101/examples/FirmwareUpdater/FirmwareUpdater.ino b/lib/WiFi101/examples/FirmwareUpdater/FirmwareUpdater.ino new file mode 100644 index 0000000..1bbd6b9 --- /dev/null +++ b/lib/WiFi101/examples/FirmwareUpdater/FirmwareUpdater.ino @@ -0,0 +1,129 @@ +/* + FirmwareUpdate.h - Firmware Updater for WiFi101 / WINC1500. + Copyright (c) 2015 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +typedef struct __attribute__((__packed__)) { + uint8_t command; + uint32_t address; + uint32_t arg1; + uint16_t payloadLength; + + // payloadLenght bytes of data follows... +} UartPacket; + +static const int MAX_PAYLOAD_SIZE = 1024; + +#define CMD_READ_FLASH 0x01 +#define CMD_WRITE_FLASH 0x02 +#define CMD_ERASE_FLASH 0x03 +#define CMD_MAX_PAYLOAD_SIZE 0x50 +#define CMD_HELLO 0x99 + +void setup() { + Serial.begin(115200); + + nm_bsp_init(); + if (m2m_wifi_download_mode() != M2M_SUCCESS) { + Serial.println(F("Failed to put the WiFi module in download mode")); + while (true) + ; + } +} + +void receivePacket(UartPacket *pkt, uint8_t *payload) { + // Read command + uint8_t *p = reinterpret_cast(pkt); + uint16_t l = sizeof(UartPacket); + while (l > 0) { + int c = Serial.read(); + if (c == -1) + continue; + *p++ = c; + l--; + } + + // Convert parameters from network byte order to cpu byte order + pkt->address = fromNetwork32(pkt->address); + pkt->arg1 = fromNetwork32(pkt->arg1); + pkt->payloadLength = fromNetwork16(pkt->payloadLength); + + // Read payload + l = pkt->payloadLength; + while (l > 0) { + int c = Serial.read(); + if (c == -1) + continue; + *payload++ = c; + l--; + } +} + +// Allocated statically so the compiler can tell us +// about the amount of used RAM +static UartPacket pkt; +static uint8_t payload[MAX_PAYLOAD_SIZE]; + +void loop() { + receivePacket(&pkt, payload); + + if (pkt.command == CMD_HELLO) { + if (pkt.address == 0x11223344 && pkt.arg1 == 0x55667788) + Serial.print("v10000"); + } + + if (pkt.command == CMD_MAX_PAYLOAD_SIZE) { + uint16_t res = toNetwork16(MAX_PAYLOAD_SIZE); + Serial.write(reinterpret_cast(&res), sizeof(res)); + } + + if (pkt.command == CMD_READ_FLASH) { + uint32_t address = pkt.address; + uint32_t len = pkt.arg1; + if (spi_flash_read(payload, address, len) != M2M_SUCCESS) { + Serial.println("ER"); + } else { + Serial.write(payload, len); + Serial.print("OK"); + } + } + + if (pkt.command == CMD_WRITE_FLASH) { + uint32_t address = pkt.address; + uint32_t len = pkt.payloadLength; + if (spi_flash_write(payload, address, len) != M2M_SUCCESS) { + Serial.print("ER"); + } else { + Serial.print("OK"); + } + } + + if (pkt.command == CMD_ERASE_FLASH) { + uint32_t address = pkt.address; + uint32_t len = pkt.arg1; + if (spi_flash_erase(address, len) != M2M_SUCCESS) { + Serial.print("ER"); + } else { + Serial.print("OK"); + } + } +} + + diff --git a/lib/WiFi101/examples/MDNS_WiFiWebServer/MDNS_WiFiWebServer.ino b/lib/WiFi101/examples/MDNS_WiFiWebServer/MDNS_WiFiWebServer.ino new file mode 100644 index 0000000..f62ac62 --- /dev/null +++ b/lib/WiFi101/examples/MDNS_WiFiWebServer/MDNS_WiFiWebServer.ino @@ -0,0 +1,170 @@ +/* + MDNS WiFi Web Server + + A simple web server that shows the value of the analog input pins, + and exposes itself on the MDNS name 'wifi101.local'. + + On Linux (like Ubuntu 15.04) or OSX you can access the web page + on the device in a browser at 'http://wifi101.local/'. + + On Windows you'll first need to install the Bonjour Printer Services + from: + https://support.apple.com/kb/dl999?locale=en_US + Then you can access the device in a browser at 'http://wifi101.local/'. + + This example is written for a network using WPA encryption. For + WEP or WPA, change the WiFi.begin() call accordingly. + + Circuit: + * WiFi shield attached + * Analog inputs attached to pins A0 through A5 (optional) + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + modified 27 January 2016 + by Tony DiCola + +*/ + +#include +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key Index number (needed only for WEP) + +char mdnsName[] = "wifi101"; // the MDNS name that the board will respond to +// Note that the actual MDNS name will have '.local' after +// the name above, so "wifi101" will be accessible on +// the MDNS name "wifi101.local". + +int status = WL_IDLE_STATUS; + +// Create a MDNS responder to listen and respond to MDNS name requests. +WiFiMDNSResponder mdnsResponder; + +WiFiServer server(80); + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // attempt to connect to WiFi network: + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + // you're connected now, so print out the status: + printWiFiStatus(); + + server.begin(); + + // Setup the MDNS responder to listen to the configured name. + // NOTE: You _must_ call this _after_ connecting to the WiFi network and + // being assigned an IP address. + if (!mdnsResponder.begin(mdnsName)) { + Serial.println("Failed to start MDNS responder!"); + while(1); + } + + Serial.print("Server listening at http://"); + Serial.print(mdnsName); + Serial.println(".local/"); +} + + +void loop() { + // Call the update() function on the MDNS responder every loop iteration to + // make sure it can detect and respond to name requests. + mdnsResponder.poll(); + + // listen for incoming clients + WiFiClient client = server.available(); + if (client) { + Serial.println("new client"); + // an http request ends with a blank line + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + Serial.write(c); + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + // send a standard http response header + client.println("HTTP/1.1 200 OK"); + client.println("Content-Type: text/html"); + client.println("Connection: close"); // the connection will be closed after completion of the response + client.println("Refresh: 5"); // refresh the page automatically every 5 sec + client.println(); + client.println(""); + client.println(""); + // output the value of each analog input pin + for (int analogChannel = 0; analogChannel < 6; analogChannel++) { + int sensorReading = analogRead(analogChannel); + client.print("analog input "); + client.print(analogChannel); + client.print(" is "); + client.print(sensorReading); + client.println("
"); + } + client.println(""); + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } + else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + // give the web browser time to receive the data + delay(1); + + // close the connection: + client.stop(); + Serial.println("client disconnected"); + } +} + + +void printWiFiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFi101/examples/MDNS_WiFiWebServer/arduino_secrets.h b/lib/WiFi101/examples/MDNS_WiFiWebServer/arduino_secrets.h new file mode 100644 index 0000000..a8ff904 --- /dev/null +++ b/lib/WiFi101/examples/MDNS_WiFiWebServer/arduino_secrets.h @@ -0,0 +1,3 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" + diff --git a/lib/WiFi101/examples/Provisioning_WiFiWebServer/Provisioning_WiFiWebServer.ino b/lib/WiFi101/examples/Provisioning_WiFiWebServer/Provisioning_WiFiWebServer.ino new file mode 100644 index 0000000..0297707 --- /dev/null +++ b/lib/WiFi101/examples/Provisioning_WiFiWebServer/Provisioning_WiFiWebServer.ino @@ -0,0 +1,167 @@ +/* + WiFi Web Server + + A simple web server that shows the value of the analog input pins. + using a WiFi shield. + + This example is written to configure the WiFi settings using provisioning mode. + It also sets up an mDNS server so the IP address of the board doesn't have to + be obtained via the serial monitor. + + Circuit: + WiFi shield attached + Analog inputs attached to pins A0 through A5 (optional) + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + +*/ + +#include +#include +#include + +const int ledPin = 6; // LED pin for connectivity status indicator + +char mdnsName[] = "wifi101"; // the MDNS name that the board will respond to + // after WiFi settings have been provisioned +// Note that the actual MDNS name will have '.local' after +// the name above, so "wifi101" will be accessible on +// the MDNS name "wifi101.local". + +WiFiServer server(80); + +// Create a MDNS responder to listen and respond to MDNS name requests. +WiFiMDNSResponder mdnsResponder; + +void setup() { + //Initialize serial: + Serial.begin(9600); + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // configure the LED pin for output mode + pinMode(ledPin, OUTPUT); + + // Start in provisioning mode: + // 1) This will try to connect to a previously associated access point. + // 2) If this fails, an access point named "wifi101-XXXX" will be created, where XXXX + // is the last 4 digits of the boards MAC address. Once you are connected to the access point, + // you can configure an SSID and password by visiting http://wifi101/ + WiFi.beginProvision(); + + while (WiFi.status() != WL_CONNECTED) { + // wait while not connected + + // blink the led to show an unconnected status + digitalWrite(ledPin, HIGH); + delay(500); + digitalWrite(ledPin, LOW); + delay(500); + } + + // connected, make the LED stay on + digitalWrite(ledPin, HIGH); + + server.begin(); + + // Setup the MDNS responder to listen to the configured name. + // NOTE: You _must_ call this _after_ connecting to the WiFi network and + // being assigned an IP address. + if (!mdnsResponder.begin(mdnsName)) { + Serial.println("Failed to start MDNS responder!"); + while(1); + } + + Serial.print("Server listening at http://"); + Serial.print(mdnsName); + Serial.println(".local/"); + + // you're connected now, so print out the status: + printWiFiStatus(); +} + + +void loop() { + // Call the update() function on the MDNS responder every loop iteration to + // make sure it can detect and respond to name requests. + mdnsResponder.poll(); + + // listen for incoming clients + WiFiClient client = server.available(); + if (client) { + Serial.println("new client"); + // an http request ends with a blank line + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + Serial.write(c); + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + // send a standard http response header + client.println("HTTP/1.1 200 OK"); + client.println("Content-Type: text/html"); + client.println("Connection: close"); // the connection will be closed after completion of the response + client.println("Refresh: 5"); // refresh the page automatically every 5 sec + client.println(); + client.println(""); + client.println(""); + // output the value of each analog input pin + for (int analogChannel = 0; analogChannel < 6; analogChannel++) { + int sensorReading = analogRead(analogChannel); + client.print("analog input "); + client.print(analogChannel); + client.print(" is "); + client.print(sensorReading); + client.println("
"); + } + client.println(""); + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } + else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + // give the web browser time to receive the data + delay(1); + + // close the connection: + client.stop(); + Serial.println("client disonnected"); + } +} + + +void printWiFiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} + diff --git a/lib/WiFi101/examples/ScanNetworks/ScanNetworks.ino b/lib/WiFi101/examples/ScanNetworks/ScanNetworks.ino new file mode 100644 index 0000000..11ba6e0 --- /dev/null +++ b/lib/WiFi101/examples/ScanNetworks/ScanNetworks.ino @@ -0,0 +1,120 @@ +/* + + This example prints the WiFi shield's MAC address, and + scans for available WiFi networks using the WiFi shield. + Every ten seconds, it scans again. It doesn't actually + connect to any network, so no encryption scheme is specified. + + Circuit: + * WiFi shield attached + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 21 Junn 2012 + by Tom Igoe and Jaymes Dec + */ + + +#include +#include + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // Print WiFi MAC address: + printMacAddress(); + + // scan for existing networks: + Serial.println("Scanning available networks..."); + listNetworks(); +} + +void loop() { + delay(10000); + // scan for existing networks: + Serial.println("Scanning available networks..."); + listNetworks(); +} + +void printMacAddress() { + // the MAC address of your WiFi shield + byte mac[6]; + + // print your MAC address: + WiFi.macAddress(mac); + Serial.print("MAC: "); + printMacAddress(mac); +} + +void listNetworks() { + // scan for nearby networks: + Serial.println("** Scan Networks **"); + int numSsid = WiFi.scanNetworks(); + if (numSsid == -1) + { + Serial.println("Couldn't get a wifi connection"); + while (true); + } + + // print the list of networks seen: + Serial.print("number of available networks:"); + Serial.println(numSsid); + + // print the network number and name for each network found: + for (int thisNet = 0; thisNet < numSsid; thisNet++) { + Serial.print(thisNet); + Serial.print(") "); + Serial.print(WiFi.SSID(thisNet)); + Serial.print("\tSignal: "); + Serial.print(WiFi.RSSI(thisNet)); + Serial.print(" dBm"); + Serial.print("\tEncryption: "); + printEncryptionType(WiFi.encryptionType(thisNet)); + Serial.flush(); + } +} + +void printEncryptionType(int thisType) { + // read the encryption type and print out the name: + switch (thisType) { + case ENC_TYPE_WEP: + Serial.println("WEP"); + break; + case ENC_TYPE_TKIP: + Serial.println("WPA"); + break; + case ENC_TYPE_CCMP: + Serial.println("WPA2"); + break; + case ENC_TYPE_NONE: + Serial.println("None"); + break; + case ENC_TYPE_AUTO: + Serial.println("Auto"); + break; + } +} + +void printMacAddress(byte mac[]) { + for (int i = 5; i >= 0; i--) { + if (mac[i] < 16) { + Serial.print("0"); + } + Serial.print(mac[i], HEX); + if (i > 0) { + Serial.print(":"); + } + } + Serial.println(); +} diff --git a/lib/WiFi101/examples/ScanNetworksAdvanced/ScanNetworksAdvanced.ino b/lib/WiFi101/examples/ScanNetworksAdvanced/ScanNetworksAdvanced.ino new file mode 100644 index 0000000..e628a5e --- /dev/null +++ b/lib/WiFi101/examples/ScanNetworksAdvanced/ScanNetworksAdvanced.ino @@ -0,0 +1,129 @@ +/* + + This example prints the WiFi 101 shield or MKR1000 MAC address, and + scans for available WiFi networks using the WiFi 101 shield or MKR1000 board. + Every ten seconds, it scans again. It doesn't actually + connect to any network, so no encryption scheme is specified. + BSSID and WiFi channel are printed + + Circuit: + WiFi 101 shield attached or MKR1000 board + + This example is based on ScanNetworks + + created 1 Mar 2017 + by Arturo Guadalupi +*/ + + +#include +#include + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // print your MAC address: + byte mac[6]; + WiFi.macAddress(mac); + Serial.print("MAC: "); + printMacAddress(mac); + + // scan for existing networks: + Serial.println(); + Serial.println("Scanning available networks..."); + listNetworks(); +} + +void loop() { + delay(10000); + // scan for existing networks: + Serial.println("Scanning available networks..."); + listNetworks(); +} + +void listNetworks() { + // scan for nearby networks: + Serial.println("** Scan Networks **"); + int numSsid = WiFi.scanNetworks(); + if (numSsid == -1) + { + Serial.println("Couldn't get a WiFi connection"); + while (true); + } + + // print the list of networks seen: + Serial.print("number of available networks: "); + Serial.println(numSsid); + + // print the network number and name for each network found: + for (int thisNet = 0; thisNet < numSsid; thisNet++) { + Serial.print(thisNet + 1); + Serial.print(") "); + Serial.print("Signal: "); + Serial.print(WiFi.RSSI(thisNet)); + Serial.print(" dBm"); + Serial.print("\tChannel: "); + Serial.print(WiFi.channel(thisNet)); + byte bssid[6]; + Serial.print("\t\tBSSID: "); + printMacAddress(WiFi.BSSID(thisNet, bssid)); + Serial.print("\tEncryption: "); + printEncryptionType(WiFi.encryptionType(thisNet)); + Serial.print("\t\tSSID: "); + Serial.println(WiFi.SSID(thisNet)); + Serial.flush(); + } + Serial.println(); +} + +void printEncryptionType(int thisType) { + // read the encryption type and print out the name: + switch (thisType) { + case ENC_TYPE_WEP: + Serial.print("WEP"); + break; + case ENC_TYPE_TKIP: + Serial.print("WPA"); + break; + case ENC_TYPE_CCMP: + Serial.print("WPA2"); + break; + case ENC_TYPE_NONE: + Serial.print("None"); + break; + case ENC_TYPE_AUTO: + Serial.print("Auto"); + break; + } +} + +void print2Digits(byte thisByte) { + if (thisByte < 0xF) { + Serial.print("0"); + } + Serial.print(thisByte, HEX); +} + +void printMacAddress(byte mac[]) { + for (int i = 5; i >= 0; i--) { + if (mac[i] < 16) { + Serial.print("0"); + } + Serial.print(mac[i], HEX); + if (i > 0) { + Serial.print(":"); + } + } + Serial.println(); +} diff --git a/lib/WiFi101/examples/SimpleWebServerWiFi/SimpleWebServerWiFi.ino b/lib/WiFi101/examples/SimpleWebServerWiFi/SimpleWebServerWiFi.ino new file mode 100644 index 0000000..aeaf0c6 --- /dev/null +++ b/lib/WiFi101/examples/SimpleWebServerWiFi/SimpleWebServerWiFi.ino @@ -0,0 +1,131 @@ +/* + WiFi Web Server LED Blink + + A simple web server that lets you blink an LED via the web. + This sketch will print the IP address of your WiFi Shield (once connected) + to the Serial monitor. From there, you can open that address in a web browser + to turn on and off the LED on pin 9. + + If the IP address of your shield is yourAddress: + http://yourAddress/H turns the LED on + http://yourAddress/L turns it off + + This example is written for a network using WPA encryption. For + WEP or WPA, change the WiFi.begin() call accordingly. + + Circuit: + * WiFi shield attached + * LED attached to pin 9 + + created 25 Nov 2012 + by Tom Igoe + */ +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key Index number (needed only for WEP) + +int status = WL_IDLE_STATUS; +WiFiServer server(80); + +void setup() { + Serial.begin(9600); // initialize serial communication + pinMode(9, OUTPUT); // set the LED pin mode + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + while (true); // don't continue + } + + // attempt to connect to WiFi network: + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to Network named: "); + Serial.println(ssid); // print the network name (SSID); + + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + // wait 10 seconds for connection: + delay(10000); + } + server.begin(); // start the web server on port 80 + printWiFiStatus(); // you're connected now, so print out the status +} + + +void loop() { + WiFiClient client = server.available(); // listen for incoming clients + + if (client) { // if you get a client, + Serial.println("new client"); // print a message out the serial port + String currentLine = ""; // make a String to hold incoming data from the client + while (client.connected()) { // loop while the client's connected + if (client.available()) { // if there's bytes to read from the client, + char c = client.read(); // read a byte, then + Serial.write(c); // print it out the serial monitor + if (c == '\n') { // if the byte is a newline character + + // if the current line is blank, you got two newline characters in a row. + // that's the end of the client HTTP request, so send a response: + if (currentLine.length() == 0) { + // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) + // and a content-type so the client knows what's coming, then a blank line: + client.println("HTTP/1.1 200 OK"); + client.println("Content-type:text/html"); + client.println(); + + // the content of the HTTP response follows the header: + client.print("Click here turn the LED on pin 9 on
"); + client.print("Click here turn the LED on pin 9 off
"); + + // The HTTP response ends with another blank line: + client.println(); + // break out of the while loop: + break; + } + else { // if you got a newline, then clear currentLine: + currentLine = ""; + } + } + else if (c != '\r') { // if you got anything else but a carriage return character, + currentLine += c; // add it to the end of the currentLine + } + + // Check to see if the client request was "GET /H" or "GET /L": + if (currentLine.endsWith("GET /H")) { + digitalWrite(9, HIGH); // GET /H turns the LED on + } + if (currentLine.endsWith("GET /L")) { + digitalWrite(9, LOW); // GET /L turns the LED off + } + } + } + // close the connection: + client.stop(); + Serial.println("client disonnected"); + } +} + +void printWiFiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); + // print where to go in a browser: + Serial.print("To see this page in action, open a browser to http://"); + Serial.println(ip); +} diff --git a/lib/WiFi101/examples/SimpleWebServerWiFi/arduino_secrets.h b/lib/WiFi101/examples/SimpleWebServerWiFi/arduino_secrets.h new file mode 100644 index 0000000..a8ff904 --- /dev/null +++ b/lib/WiFi101/examples/SimpleWebServerWiFi/arduino_secrets.h @@ -0,0 +1,3 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" + diff --git a/lib/WiFi101/examples/WiFiChatServer/WiFiChatServer.ino b/lib/WiFi101/examples/WiFiChatServer/WiFiChatServer.ino new file mode 100644 index 0000000..ac7bd76 --- /dev/null +++ b/lib/WiFi101/examples/WiFiChatServer/WiFiChatServer.ino @@ -0,0 +1,114 @@ +/* + Chat Server + + A simple server that distributes any incoming messages to all + connected clients. To use telnet to your device's IP address and type. + You can see the client's input in the serial monitor as well. + + This example is written for a network using WPA encryption. For + WEP or WPA, change the WiFi.begin() call accordingly. + + + Circuit: + * WiFi shield attached + + created 18 Dec 2009 + by David A. Mellis + modified 31 May 2012 + by Tom Igoe + + */ + +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) + +int keyIndex = 0; // your network key Index number (needed only for WEP) + +int status = WL_IDLE_STATUS; + +WiFiServer server(23); + +boolean alreadyConnected = false; // whether or not the client was connected previously + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // attempt to connect to WiFi network: + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + + // start the server: + server.begin(); + // you're connected now, so print out the status: + printWiFiStatus(); +} + + +void loop() { + // wait for a new client: + WiFiClient client = server.available(); + + + // when the client sends the first byte, say hello: + if (client) { + if (!alreadyConnected) { + // clead out the input buffer: + client.flush(); + Serial.println("We have a new client"); + client.println("Hello, client!"); + alreadyConnected = true; + } + + if (client.available() > 0) { + // read the bytes incoming from the client: + char thisChar = client.read(); + // echo the bytes back to the client: + server.write(thisChar); + // echo the bytes to the server as well: + Serial.write(thisChar); + } + } +} + + +void printWiFiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} + + diff --git a/lib/WiFi101/examples/WiFiChatServer/arduino_secrets.h b/lib/WiFi101/examples/WiFiChatServer/arduino_secrets.h new file mode 100644 index 0000000..a8ff904 --- /dev/null +++ b/lib/WiFi101/examples/WiFiChatServer/arduino_secrets.h @@ -0,0 +1,3 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" + diff --git a/lib/WiFi101/examples/WiFiPing/WiFiPing.ino b/lib/WiFi101/examples/WiFiPing/WiFiPing.ino new file mode 100644 index 0000000..0b86b95 --- /dev/null +++ b/lib/WiFi101/examples/WiFiPing/WiFiPing.ino @@ -0,0 +1,132 @@ +/* + + This example connects to a encrypted WiFi network (WPA/WPA2). + Then it prints the MAC address of the WiFi shield, + the IP address obtained, and other network details. + Then it continuously pings given host specified by IP Address or name. + + Circuit: + WiFi shield attached / MKR1000 + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 09 June 2016 + by Petar Georgiev +*/ +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int status = WL_IDLE_STATUS; // the WiFi radio's status + +// Specify IP address or hostname +String hostName = "www.google.com"; +int pingResult; + +void setup() { + // Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // attempt to connect to WiFi network: + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network: + status = WiFi.begin(ssid, pass); + + // wait 5 seconds for connection: + delay(5000); + } + + // you're connected now, so print out the data: + Serial.println("You're connected to the network"); + printCurrentNet(); + printWiFiData(); +} + +void loop() { + Serial.print("Pinging "); + Serial.print(hostName); + Serial.print(": "); + + pingResult = WiFi.ping(hostName); + + if (pingResult >= 0) { + Serial.print("SUCCESS! RTT = "); + Serial.print(pingResult); + Serial.println(" ms"); + } else { + Serial.print("FAILED! Error code: "); + Serial.println(pingResult); + } + + delay(5000); +} + +void printWiFiData() { + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP address : "); + Serial.println(ip); + + Serial.print("Subnet mask: "); + Serial.println((IPAddress)WiFi.subnetMask()); + + Serial.print("Gateway IP : "); + Serial.println((IPAddress)WiFi.gatewayIP()); + + // print your MAC address: + byte mac[6]; + WiFi.macAddress(mac); + Serial.print("MAC address: "); + printMacAddress(mac); +} + +void printCurrentNet() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print the MAC address of the router you're attached to: + byte bssid[6]; + WiFi.BSSID(bssid); + Serial.print("BSSID: "); + printMacAddress(bssid); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI): "); + Serial.println(rssi); + + // print the encryption type: + byte encryption = WiFi.encryptionType(); + Serial.print("Encryption Type: "); + Serial.println(encryption, HEX); + Serial.println(); +} + +void printMacAddress(byte mac[]) { + for (int i = 5; i >= 0; i--) { + if (mac[i] < 16) { + Serial.print("0"); + } + Serial.print(mac[i], HEX); + if (i > 0) { + Serial.print(":"); + } + } + Serial.println(); +} diff --git a/lib/WiFi101/examples/WiFiPing/arduino_secrets.h b/lib/WiFi101/examples/WiFiPing/arduino_secrets.h new file mode 100644 index 0000000..a8ff904 --- /dev/null +++ b/lib/WiFi101/examples/WiFiPing/arduino_secrets.h @@ -0,0 +1,3 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" + diff --git a/lib/WiFi101/examples/WiFiSSLClient/WiFiSSLClient.ino b/lib/WiFi101/examples/WiFiSSLClient/WiFiSSLClient.ino new file mode 100644 index 0000000..a436902 --- /dev/null +++ b/lib/WiFi101/examples/WiFiSSLClient/WiFiSSLClient.ino @@ -0,0 +1,107 @@ +/* +This example creates a client object that connects and transfers +data using always SSL. + +It is compatible with the methods normally related to plain +connections, like client.connect(host, port). + +Written by Arturo Guadalupi +last revision November 2015 + +*/ + +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key Index number (needed only for WEP) + +int status = WL_IDLE_STATUS; +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +//IPAddress server(74,125,232,128); // numeric IP for Google (no DNS) +char server[] = "www.google.com"; // name address for Google (using DNS) + +// Initialize the Ethernet client library +// with the IP address and port of the server +// that you want to connect to (port 80 is default for HTTP): +WiFiSSLClient client; + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + Serial.println("Connected to wifi"); + printWiFiStatus(); + + Serial.println("\nStarting connection to server..."); + // if you get a connection, report back via serial: + if (client.connect(server, 443)) { + Serial.println("connected to server"); + // Make a HTTP request: + client.println("GET /search?q=arduino HTTP/1.1"); + client.println("Host: www.google.com"); + client.println("Connection: close"); + client.println(); + } +} + +void loop() { + // if there are incoming bytes available + // from the server, read them and print them: + while (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + Serial.println(); + Serial.println("disconnecting from server."); + client.stop(); + + // do nothing forevermore: + while (true); + } +} + + +void printWiFiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFi101/examples/WiFiSSLClient/arduino_secrets.h b/lib/WiFi101/examples/WiFiSSLClient/arduino_secrets.h new file mode 100644 index 0000000..a8ff904 --- /dev/null +++ b/lib/WiFi101/examples/WiFiSSLClient/arduino_secrets.h @@ -0,0 +1,3 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" + diff --git a/lib/WiFi101/examples/WiFiUdpNtpClient/WiFiUdpNtpClient.ino b/lib/WiFi101/examples/WiFiUdpNtpClient/WiFiUdpNtpClient.ino new file mode 100644 index 0000000..e82fbaa --- /dev/null +++ b/lib/WiFi101/examples/WiFiUdpNtpClient/WiFiUdpNtpClient.ino @@ -0,0 +1,182 @@ +/* + + Udp NTP Client + + Get the time from a Network Time Protocol (NTP) time server + Demonstrates use of UDP sendPacket and ReceivePacket + For more on NTP time servers and the messages needed to communicate with them, + see http://en.wikipedia.org/wiki/Network_Time_Protocol + + created 4 Sep 2010 + by Michael Margolis + modified 9 Apr 2012 + by Tom Igoe + + This code is in the public domain. + + */ + +#include +#include +#include + +int status = WL_IDLE_STATUS; +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key Index number (needed only for WEP) + +unsigned int localPort = 2390; // local port to listen for UDP packets + +IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server + +const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message + +byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets + +// A UDP instance to let us send and receive packets over UDP +WiFiUDP Udp; + +void setup() +{ + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // attempt to connect to WiFi network: + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + + Serial.println("Connected to wifi"); + printWiFiStatus(); + + Serial.println("\nStarting connection to server..."); + Udp.begin(localPort); +} + +void loop() +{ + sendNTPpacket(timeServer); // send an NTP packet to a time server + // wait to see if a reply is available + delay(1000); + if ( Udp.parsePacket() ) { + Serial.println("packet received"); + // We've received a packet, read the data from it + Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer + + //the timestamp starts at byte 40 of the received packet and is four bytes, + // or two words, long. First, esxtract the two words: + + unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); + unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); + // combine the four bytes (two words) into a long integer + // this is NTP time (seconds since Jan 1 1900): + unsigned long secsSince1900 = highWord << 16 | lowWord; + Serial.print("Seconds since Jan 1 1900 = " ); + Serial.println(secsSince1900); + + // now convert NTP time into everyday time: + Serial.print("Unix time = "); + // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: + const unsigned long seventyYears = 2208988800UL; + // subtract seventy years: + unsigned long epoch = secsSince1900 - seventyYears; + // print Unix time: + Serial.println(epoch); + + + // print the hour, minute and second: + Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT) + Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) + Serial.print(':'); + if ( ((epoch % 3600) / 60) < 10 ) { + // In the first 10 minutes of each hour, we'll want a leading '0' + Serial.print('0'); + } + Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute) + Serial.print(':'); + if ( (epoch % 60) < 10 ) { + // In the first 10 seconds of each minute, we'll want a leading '0' + Serial.print('0'); + } + Serial.println(epoch % 60); // print the second + } + // wait ten seconds before asking for the time again + delay(10000); +} + +// send an NTP request to the time server at the given address +unsigned long sendNTPpacket(IPAddress& address) +{ + //Serial.println("1"); + // set all bytes in the buffer to 0 + memset(packetBuffer, 0, NTP_PACKET_SIZE); + // Initialize values needed to form NTP request + // (see URL above for details on the packets) + //Serial.println("2"); + packetBuffer[0] = 0b11100011; // LI, Version, Mode + packetBuffer[1] = 0; // Stratum, or type of clock + packetBuffer[2] = 6; // Polling Interval + packetBuffer[3] = 0xEC; // Peer Clock Precision + // 8 bytes of zero for Root Delay & Root Dispersion + packetBuffer[12] = 49; + packetBuffer[13] = 0x4E; + packetBuffer[14] = 49; + packetBuffer[15] = 52; + + //Serial.println("3"); + + // all NTP fields have been given values, now + // you can send a packet requesting a timestamp: + Udp.beginPacket(address, 123); //NTP requests are to port 123 + //Serial.println("4"); + Udp.write(packetBuffer, NTP_PACKET_SIZE); + //Serial.println("5"); + Udp.endPacket(); + //Serial.println("6"); +} + + +void printWiFiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} + + + + + + + + + + diff --git a/lib/WiFi101/examples/WiFiUdpNtpClient/arduino_secrets.h b/lib/WiFi101/examples/WiFiUdpNtpClient/arduino_secrets.h new file mode 100644 index 0000000..a8ff904 --- /dev/null +++ b/lib/WiFi101/examples/WiFiUdpNtpClient/arduino_secrets.h @@ -0,0 +1,3 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" + diff --git a/lib/WiFi101/examples/WiFiUdpSendReceiveString/WiFiUdpSendReceiveString.ino b/lib/WiFi101/examples/WiFiUdpSendReceiveString/WiFiUdpSendReceiveString.ino new file mode 100644 index 0000000..cbc9f7f --- /dev/null +++ b/lib/WiFi101/examples/WiFiUdpSendReceiveString/WiFiUdpSendReceiveString.ino @@ -0,0 +1,113 @@ +/* + WiFi UDP Send and Receive String + + This sketch wait an UDP packet on localPort using a WiFi shield. + When a packet is received an Acknowledge packet is sent to the client on port remotePort + + Circuit: + * WiFi shield attached + + created 30 December 2012 + by dlf (Metodo2 srl) + + */ + + +#include +#include +#include + +int status = WL_IDLE_STATUS; +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key Index number (needed only for WEP) + +unsigned int localPort = 2390; // local port to listen on + +char packetBuffer[255]; //buffer to hold incoming packet +char ReplyBuffer[] = "acknowledged"; // a string to send back + +WiFiUDP Udp; + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // attempt to connect to WiFi network: + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + Serial.println("Connected to wifi"); + printWiFiStatus(); + + Serial.println("\nStarting connection to server..."); + // if you get a connection, report back via serial: + Udp.begin(localPort); +} + +void loop() { + + // if there's data available, read a packet + int packetSize = Udp.parsePacket(); + if (packetSize) + { + Serial.print("Received packet of size "); + Serial.println(packetSize); + Serial.print("From "); + IPAddress remoteIp = Udp.remoteIP(); + Serial.print(remoteIp); + Serial.print(", port "); + Serial.println(Udp.remotePort()); + + // read the packet into packetBufffer + int len = Udp.read(packetBuffer, 255); + if (len > 0) packetBuffer[len] = 0; + Serial.println("Contents:"); + Serial.println(packetBuffer); + + // send a reply, to the IP address and port that sent us the packet we received + Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); + Udp.write(ReplyBuffer); + Udp.endPacket(); + } +} + + +void printWiFiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} + + + + diff --git a/lib/WiFi101/examples/WiFiUdpSendReceiveString/arduino_secrets.h b/lib/WiFi101/examples/WiFiUdpSendReceiveString/arduino_secrets.h new file mode 100644 index 0000000..a8ff904 --- /dev/null +++ b/lib/WiFi101/examples/WiFiUdpSendReceiveString/arduino_secrets.h @@ -0,0 +1,3 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" + diff --git a/lib/WiFi101/examples/WiFiWebClient/WiFiWebClient.ino b/lib/WiFi101/examples/WiFiWebClient/WiFiWebClient.ino new file mode 100644 index 0000000..5faa779 --- /dev/null +++ b/lib/WiFi101/examples/WiFiWebClient/WiFiWebClient.ino @@ -0,0 +1,121 @@ +/* + Web client + + This sketch connects to a website (http://www.google.com) + using a WiFi shield. + + This example is written for a network using WPA encryption. For + WEP or WPA, change the WiFi.begin() call accordingly. + + This example is written for a network using WPA encryption. For + WEP or WPA, change the WiFi.begin() call accordingly. + + Circuit: + * WiFi shield attached + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ + + +#include +#include +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key Index number (needed only for WEP) + +int status = WL_IDLE_STATUS; +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +//IPAddress server(74,125,232,128); // numeric IP for Google (no DNS) +char server[] = "www.google.com"; // name address for Google (using DNS) + +// Initialize the Ethernet client library +// with the IP address and port of the server +// that you want to connect to (port 80 is default for HTTP): +WiFiClient client; + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + Serial.println("Connected to wifi"); + printWiFiStatus(); + + Serial.println("\nStarting connection to server..."); + // if you get a connection, report back via serial: + if (client.connect(server, 80)) { + Serial.println("connected to server"); + // Make a HTTP request: + client.println("GET /search?q=arduino HTTP/1.1"); + client.println("Host: www.google.com"); + client.println("Connection: close"); + client.println(); + } +} + +void loop() { + // if there are incoming bytes available + // from the server, read them and print them: + while (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + Serial.println(); + Serial.println("disconnecting from server."); + client.stop(); + + // do nothing forevermore: + while (true); + } +} + + +void printWiFiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} + + + + + diff --git a/lib/WiFi101/examples/WiFiWebClient/arduino_secrets.h b/lib/WiFi101/examples/WiFiWebClient/arduino_secrets.h new file mode 100644 index 0000000..a8ff904 --- /dev/null +++ b/lib/WiFi101/examples/WiFiWebClient/arduino_secrets.h @@ -0,0 +1,3 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" + diff --git a/lib/WiFi101/examples/WiFiWebClientRepeating/WiFiWebClientRepeating.ino b/lib/WiFi101/examples/WiFiWebClientRepeating/WiFiWebClientRepeating.ino new file mode 100644 index 0000000..cc40dc9 --- /dev/null +++ b/lib/WiFi101/examples/WiFiWebClientRepeating/WiFiWebClientRepeating.ino @@ -0,0 +1,127 @@ +/* + Repeating WiFi Web Client + + This sketch connects to a a web server and makes a request + using an Arduino WiFi shield. + + Circuit: + * WiFi shield attached to pins SPI pins and pin 7 + + created 23 April 2012 + modified 31 May 2012 + by Tom Igoe + modified 13 Jan 2014 + by Federico Vanzati + + http://arduino.cc/en/Tutorial/WiFiWebClientRepeating + This code is in the public domain. + */ + +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key Index number (needed only for WEP) + +int status = WL_IDLE_STATUS; + +// Initialize the WiFi client library +WiFiClient client; + +// server address: +char server[] = "example.org"; +//IPAddress server(64,131,82,241); + +unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds +const unsigned long postingInterval = 10L * 1000L; // delay between updates, in milliseconds + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // attempt to connect to WiFi network: + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + // you're connected now, so print out the status: + printWiFiStatus(); +} + +void loop() { + // if there's incoming data from the net connection. + // send it out the serial port. This is for debugging + // purposes only: + while (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if ten seconds have passed since your last connection, + // then connect again and send data: + if (millis() - lastConnectionTime > postingInterval) { + httpRequest(); + } + +} + +// this method makes a HTTP connection to the server: +void httpRequest() { + // close any connection before send a new request. + // This will free the socket on the WiFi shield + client.stop(); + + // if there's a successful connection: + if (client.connect(server, 80)) { + Serial.println("connecting..."); + // send the HTTP PUT request: + client.println("GET / HTTP/1.1"); + client.println("Host: example.org"); + client.println("User-Agent: ArduinoWiFi/1.1"); + client.println("Connection: close"); + client.println(); + + // note the time that the connection was made: + lastConnectionTime = millis(); + } + else { + // if you couldn't make a connection: + Serial.println("connection failed"); + } +} + + +void printWiFiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFi101/examples/WiFiWebClientRepeating/arduino_secrets.h b/lib/WiFi101/examples/WiFiWebClientRepeating/arduino_secrets.h new file mode 100644 index 0000000..a8ff904 --- /dev/null +++ b/lib/WiFi101/examples/WiFiWebClientRepeating/arduino_secrets.h @@ -0,0 +1,3 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" + diff --git a/lib/WiFi101/examples/WiFiWebServer/WiFiWebServer.ino b/lib/WiFi101/examples/WiFiWebServer/WiFiWebServer.ino new file mode 100644 index 0000000..24d0083 --- /dev/null +++ b/lib/WiFi101/examples/WiFiWebServer/WiFiWebServer.ino @@ -0,0 +1,135 @@ +/* + WiFi Web Server + + A simple web server that shows the value of the analog input pins. + using a WiFi shield. + + This example is written for a network using WPA encryption. For + WEP or WPA, change the WiFi.begin() call accordingly. + + Circuit: + * WiFi shield attached + * Analog inputs attached to pins A0 through A5 (optional) + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + + */ + +#include +#include + + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key Index number (needed only for WEP) + +int status = WL_IDLE_STATUS; + +WiFiServer server(80); + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + server.begin(); + // you're connected now, so print out the status: + printWiFiStatus(); +} + + +void loop() { + // listen for incoming clients + WiFiClient client = server.available(); + if (client) { + Serial.println("new client"); + // an http request ends with a blank line + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + Serial.write(c); + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + // send a standard http response header + client.println("HTTP/1.1 200 OK"); + client.println("Content-Type: text/html"); + client.println("Connection: close"); // the connection will be closed after completion of the response + client.println("Refresh: 5"); // refresh the page automatically every 5 sec + client.println(); + client.println(""); + client.println(""); + // output the value of each analog input pin + for (int analogChannel = 0; analogChannel < 6; analogChannel++) { + int sensorReading = analogRead(analogChannel); + client.print("analog input "); + client.print(analogChannel); + client.print(" is "); + client.print(sensorReading); + client.println("
"); + } + client.println(""); + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } + else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + // give the web browser time to receive the data + delay(1); + + // close the connection: + client.stop(); + Serial.println("client disconnected"); + } +} + + +void printWiFiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFi101/examples/WiFiWebServer/arduino_secrets.h b/lib/WiFi101/examples/WiFiWebServer/arduino_secrets.h new file mode 100644 index 0000000..a8ff904 --- /dev/null +++ b/lib/WiFi101/examples/WiFiWebServer/arduino_secrets.h @@ -0,0 +1,3 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" + diff --git a/lib/WiFi101/keywords.txt b/lib/WiFi101/keywords.txt new file mode 100644 index 0000000..aa3e709 --- /dev/null +++ b/lib/WiFi101/keywords.txt @@ -0,0 +1,62 @@ +####################################### +# Syntax Coloring Map For WiFi +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +WiFi KEYWORD1 +WiFi101 KEYWORD1 +Client KEYWORD1 +Server KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +setPins KEYWORD2 +status KEYWORD2 +connect KEYWORD2 +connectSSL KEYWORD2 +write KEYWORD2 +available KEYWORD2 +read KEYWORD2 +flush KEYWORD2 +stop KEYWORD2 +connected KEYWORD2 +begin KEYWORD2 +beginProvision KEYWORD2 +beginOrProvision KEYWORD2 +beginMulticast KEYWORD2 +disconnect KEYWORD2 +macAddress KEYWORD2 +localIP KEYWORD2 +subnetMask KEYWORD2 +gatewayIP KEYWORD2 +SSID KEYWORD2 +BSSID KEYWORD2 +APClientMacAddress KEYWORD2 +RSSI KEYWORD2 +encryptionType KEYWORD2 +channel KEYWORD2 +provisioned KEYWORD2 +getResult KEYWORD2 +getSocket KEYWORD2 +poll KEYWORD2 +getTime KEYWORD2 +hostname KEYWORD2 +WiFiClient KEYWORD2 +WiFiServer KEYWORD2 +WiFiSSLClient KEYWORD2 +WiFiMDNSResponder KEYWORD2 + +lowPowerMode KEYWORD2 +maxLowPowerMode KEYWORD2 +noLowPowerMode KEYWORD2 +setTimeout KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/lib/WiFi101/library.properties b/lib/WiFi101/library.properties new file mode 100644 index 0000000..1887e7f --- /dev/null +++ b/lib/WiFi101/library.properties @@ -0,0 +1,10 @@ +name=WiFi101 +version=0.16.0 +author=Arduino +maintainer=Arduino +sentence=Network driver for ATMEL WINC1500 module (used on Arduino/Genuino Wifi Shield 101 and MKR1000 boards) +paragraph=This library implements a network driver for devices based on the ATMEL WINC1500 wifi module +category=Communication +url=http://www.arduino.cc/en/Reference/WiFi101 +architectures=* +includes=WiFi101.h diff --git a/lib/WiFi101/src/WiFi.cpp b/lib/WiFi101/src/WiFi.cpp new file mode 100644 index 0000000..82c6a0b --- /dev/null +++ b/lib/WiFi101/src/WiFi.cpp @@ -0,0 +1,1177 @@ +/* + WiFi.cpp - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifdef ARDUINO_ARCH_AVR +#include +#if (__AVR_LIBC_MAJOR__ < 2) +#define WIFI_101_NO_TIME_H +#endif +#endif + +#ifndef WIFI_101_NO_TIME_H +#include +#endif + +#if !defined(_TIME_H_) && !defined(TIME_H) +// another library overrided the time.h header +#define WIFI_101_NO_TIME_H +#endif + +#include "utility/WiFiSocket.h" + +#include "WiFi101.h" + +extern "C" { + #include "bsp/include/nm_bsp.h" + #include "bsp/include/nm_bsp_arduino.h" + #include "driver/include/m2m_periph.h" + #include "driver/include/m2m_ssl.h" + #include "driver/include/m2m_wifi.h" +} + +static void wifi_cb(uint8_t u8MsgType, void *pvMsg) +{ + WiFi.handleEvent(u8MsgType, pvMsg); +} + +void WiFiClass::handleEvent(uint8_t u8MsgType, void *pvMsg) +{ + switch (u8MsgType) { + case M2M_WIFI_RESP_DEFAULT_CONNECT: + { + tstrM2MDefaultConnResp *pstrDefaultConnResp = (tstrM2MDefaultConnResp *)pvMsg; + if (pstrDefaultConnResp->s8ErrorCode) { + _status = WL_DISCONNECTED; + } + } + break; + + case M2M_WIFI_RESP_CON_STATE_CHANGED: + { + tstrM2mWifiStateChanged *pstrWifiState = (tstrM2mWifiStateChanged *)pvMsg; + if (pstrWifiState->u8CurrState == M2M_WIFI_CONNECTED) { + //SERIAL_PORT_MONITOR.println("wifi_cb: M2M_WIFI_RESP_CON_STATE_CHANGED: CONNECTED"); + if (_mode == WL_STA_MODE && !_dhcp) { + _status = WL_CONNECTED; + +#ifdef CONF_PERIPH + // WiFi led ON. + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO15, 0); +#endif + } else if (_mode == WL_AP_MODE) { + _status = WL_AP_CONNECTED; + } + } else if (pstrWifiState->u8CurrState == M2M_WIFI_DISCONNECTED) { + //SERIAL_PORT_MONITOR.println("wifi_cb: M2M_WIFI_RESP_CON_STATE_CHANGED: DISCONNECTED"); + if (_mode == WL_STA_MODE) { + _status = WL_DISCONNECTED; + if (_dhcp) { + _localip = 0; + _submask = 0; + _gateway = 0; + } + // Close sockets to clean state + // Clients will need to reconnect once the physical link will be re-established + for (int i = 0; i < MAX_SOCKET; i++) { + WiFiSocket.close(i); + } + } else if (_mode == WL_AP_MODE) { + _status = WL_AP_LISTENING; + } +#ifdef CONF_PERIPH + // WiFi led OFF (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO15, 1); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO4, 1); +#endif + } + } + break; + + case M2M_WIFI_REQ_DHCP_CONF: + { + if (_mode == WL_STA_MODE) { + tstrM2MIPConfig *pstrIPCfg = (tstrM2MIPConfig *)pvMsg; + _localip = pstrIPCfg->u32StaticIP; + _submask = pstrIPCfg->u32SubnetMask; + _gateway = pstrIPCfg->u32Gateway; + + _status = WL_CONNECTED; + +#ifdef CONF_PERIPH + // WiFi led ON (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO15, 0); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO4, 0); +#endif + } + /*uint8_t *pu8IPAddress = (uint8_t *)pvMsg; + SERIAL_PORT_MONITOR.print("wifi_cb: M2M_WIFI_REQ_DHCP_CONF: IP is "); + SERIAL_PORT_MONITOR.print(pu8IPAddress[0], 10); + SERIAL_PORT_MONITOR.print("."); + SERIAL_PORT_MONITOR.print(pu8IPAddress[1], 10); + SERIAL_PORT_MONITOR.print("."); + SERIAL_PORT_MONITOR.print(pu8IPAddress[2], 10); + SERIAL_PORT_MONITOR.print("."); + SERIAL_PORT_MONITOR.print(pu8IPAddress[3], 10); + SERIAL_PORT_MONITOR.println("");*/ + } + break; + + case M2M_WIFI_RESP_CURRENT_RSSI: + { + _resolve = *((int8_t *)pvMsg); + } + break; + + case M2M_WIFI_RESP_PROVISION_INFO: + { + tstrM2MProvisionInfo *pstrProvInfo = (tstrM2MProvisionInfo *)pvMsg; + //SERIAL_PORT_MONITOR.println("wifi_cb: M2M_WIFI_RESP_PROVISION_INFO"); + + if (pstrProvInfo->u8Status == M2M_SUCCESS) { + memset(_ssid, 0, M2M_MAX_SSID_LEN); + memcpy(_ssid, (char *)pstrProvInfo->au8SSID, strlen((char *)pstrProvInfo->au8SSID)); + _mode = WL_STA_MODE; + _localip = 0; + _submask = 0; + _gateway = 0; + m2m_wifi_connect((char *)pstrProvInfo->au8SSID, strlen((char *)pstrProvInfo->au8SSID), + pstrProvInfo->u8SecType, pstrProvInfo->au8Password, M2M_WIFI_CH_ALL); + } else { + _status = WL_PROVISIONING_FAILED; + //SERIAL_PORT_MONITOR.println("wifi_cb: Provision failed.\r\n"); + beginProvision(); + } + } + break; + + case M2M_WIFI_RESP_SCAN_DONE: + { + tstrM2mScanDone *pstrInfo = (tstrM2mScanDone *)pvMsg; + if (pstrInfo->u8NumofCh >= 1) { + _status = WL_SCAN_COMPLETED; + } + } + break; + + case M2M_WIFI_RESP_SCAN_RESULT: + { + tstrM2mWifiscanResult *pstrScanResult = (tstrM2mWifiscanResult *)pvMsg; + uint16_t scan_ssid_len = strlen((const char *)pstrScanResult->au8SSID); + memset(_scan_ssid, 0, M2M_MAX_SSID_LEN); + if (scan_ssid_len) { + memcpy(_scan_ssid, (const char *)pstrScanResult->au8SSID, scan_ssid_len); + } + if (_remoteMacAddress) { + // reverse copy the remote MAC + for(int i = 0; i < 6; i++) { + _remoteMacAddress[i] = pstrScanResult->au8BSSID[5-i]; + } + } + _resolve = pstrScanResult->s8rssi; + _scan_auth = pstrScanResult->u8AuthType; + _scan_channel = pstrScanResult->u8ch; + _status = WL_SCAN_COMPLETED; + } + break; + + case M2M_WIFI_RESP_CONN_INFO: + { + tstrM2MConnInfo *pstrConnInfo = (tstrM2MConnInfo*)pvMsg; + + if (_remoteMacAddress) { + // reverse copy the remote MAC + for(int i = 0; i < 6; i++) { + _remoteMacAddress[i] = pstrConnInfo->au8MACAddress[5-i]; + } + _remoteMacAddress = 0; + } + + strcpy((char *)_ssid, pstrConnInfo->acSSID); + } + break; + + case M2M_WIFI_RESP_GET_SYS_TIME: + { + if (_resolve != 0) { + memcpy((tstrSystemTime *)_resolve, pvMsg, sizeof(tstrSystemTime)); + + _resolve = 0; + } + } + break; + + default: + break; + } +} + +static void resolve_cb(uint8_t * hostName, uint32_t hostIp) +{ + WiFi.handleResolve(hostName, hostIp); +} + +void WiFiClass::handleResolve(uint8_t * /*hostName*/, uint32_t hostIp) +{ + _resolve = hostIp; +} + +static void socket_cb(SOCKET sock, uint8 u8Msg, void *pvMsg) +{ + WiFiSocket.eventCallback(sock, u8Msg, pvMsg); +} + +void ping_cb(uint32 u32IPAddr, uint32 u32RTT, uint8 u8ErrorCode) +{ + WiFi.handlePingResponse(u32IPAddr, u32RTT, u8ErrorCode); +} + +void WiFiClass::handlePingResponse(uint32 u32IPAddr, uint32 u32RTT, uint8 u8ErrorCode) +{ + if (PING_ERR_SUCCESS == u8ErrorCode) { + // Ensure this ICMP reply comes from requested IP address + if (_resolve == u32IPAddr) { + _resolve = (uint32_t)u32RTT; + } else { + // Another network device replied to the our ICMP request + _resolve = (uint32_t)WL_PING_DEST_UNREACHABLE; + } + } else if (PING_ERR_DEST_UNREACH == u8ErrorCode) { + _resolve = (uint32_t)WL_PING_DEST_UNREACHABLE; + } else if (PING_ERR_TIMEOUT == u8ErrorCode) { + _resolve = (uint32_t)WL_PING_TIMEOUT; + } else { + _resolve = (uint32_t)WL_PING_ERROR; + } +} + +WiFiClass::WiFiClass() : + _init(0), + _mode(WL_RESET_MODE), + _status(WL_NO_SHIELD), + _timeout(60000) +{ +} + +void WiFiClass::setPins(int8_t cs, int8_t irq, int8_t rst, int8_t en) +{ + gi8Winc1501CsPin = cs; + gi8Winc1501IntnPin = irq; + gi8Winc1501ResetPin = rst; + gi8Winc1501ChipEnPin = en; +} + +int WiFiClass::init() +{ + tstrWifiInitParam param; + int8_t ret; + + // Initialize the WiFi BSP: + nm_bsp_init(); + + // Initialize WiFi module and register status callback: + param.pfAppWifiCb = wifi_cb; + ret = m2m_wifi_init(¶m); + if (M2M_SUCCESS != ret && M2M_ERR_FW_VER_MISMATCH != ret) { +#ifdef CONF_PERIPH + if (ret != M2M_ERR_INVALID) { + // Error led ON (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO18, 0); + m2m_periph_gpio_set_dir(M2M_PERIPH_GPIO6, 1); + } +#endif + return ret; + } + + // Initialize socket API and register socket callback: + socketInit(); + registerSocketCallback(socket_cb, resolve_cb); + _init = 1; + _status = WL_IDLE_STATUS; + _localip = 0; + _submask = 0; + _gateway = 0; + _dhcp = 1; + _resolve = 0; + _remoteMacAddress = 0; + + extern uint32 nmdrv_firm_ver; + + if (nmdrv_firm_ver >= M2M_MAKE_VERSION(19, 5, 0)) { + // enable AES-128 and AES-256 Ciphers, if firmware is 19.5.0 or higher + m2m_ssl_set_active_ciphersuites(SSL_NON_ECC_CIPHERS_AES_128 | SSL_NON_ECC_CIPHERS_AES_256); + } + +#ifdef CONF_PERIPH + // Initialize IO expander LED control (rev A then rev B).. + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO15, 1); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO16, 1); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO18, 1); + m2m_periph_gpio_set_dir(M2M_PERIPH_GPIO15, 1); + m2m_periph_gpio_set_dir(M2M_PERIPH_GPIO16, 1); + m2m_periph_gpio_set_dir(M2M_PERIPH_GPIO18, 1); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO4, 1); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO5, 1); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO6, 1); + m2m_periph_gpio_set_dir(M2M_PERIPH_GPIO4, 1); + m2m_periph_gpio_set_dir(M2M_PERIPH_GPIO5, 1); + m2m_periph_gpio_set_dir(M2M_PERIPH_GPIO6, 1); +#endif + + return ret; +} + +extern "C" { + sint8 nm_get_firmware_info(tstrM2mRev* M2mRev); +} + +char* WiFiClass::firmwareVersion() +{ + tstrM2mRev rev; + + if (!_init) { + init(); + } + nm_get_firmware_info(&rev); + memset(_version, 0, 9); + if (rev.u8FirmwareMajor != rev.u8DriverMajor && rev.u8FirmwareMinor != rev.u8DriverMinor) { + sprintf(_version, "-Err-"); + } + else { + sprintf(_version, "%d.%d.%d", rev.u8FirmwareMajor, rev.u8FirmwareMinor, rev.u8FirmwarePatch); + } + return _version; +} + +uint8_t WiFiClass::begin() +{ + if (!_init) { + init(); + } + + // Connect to router: + if (_dhcp) { + _localip = 0; + _submask = 0; + _gateway = 0; + } + if (m2m_wifi_default_connect() < 0) { + _status = WL_CONNECT_FAILED; + return _status; + } + _status = WL_IDLE_STATUS; + _mode = WL_STA_MODE; + + // Wait for connection or timeout: + for (unsigned long start = millis(); millis() - start < _timeout;) + { + m2m_wifi_handle_events(NULL); + if ((_status & WL_CONNECTED) || (_status & WL_DISCONNECTED)) { + break; + } + } + + memset(_ssid, 0, M2M_MAX_SSID_LEN); + + if (!(_status & WL_CONNECTED)) { + _mode = WL_RESET_MODE; + } else { + m2m_wifi_get_connection_info(); + + m2m_wifi_handle_events(NULL); + } + + return _status; +} + +uint8_t WiFiClass::begin(const char *ssid) +{ + return startConnect(ssid, M2M_WIFI_SEC_OPEN, (void *)0); +} + +uint8_t WiFiClass::begin(const char *ssid, uint8_t key_idx, const char* key) +{ + tstrM2mWifiWepParams wep_params; + + memset(&wep_params, 0, sizeof(tstrM2mWifiWepParams)); + wep_params.u8KeyIndx = key_idx; + wep_params.u8KeySz = strlen(key); + strcpy((char *)&wep_params.au8WepKey[0], key); + return startConnect(ssid, M2M_WIFI_SEC_WEP, &wep_params); +} + +uint8_t WiFiClass::begin(const char *ssid, const char *key) +{ + return startConnect(ssid, M2M_WIFI_SEC_WPA_PSK, key); +} + +uint8_t WiFiClass::startConnect(const char *ssid, uint8_t u8SecType, const void *pvAuthInfo) +{ + if (!_init) { + init(); + } + + // Connect to router: + if (_dhcp) { + _localip = 0; + _submask = 0; + _gateway = 0; + } + if (m2m_wifi_connect((char*)ssid, strlen(ssid), u8SecType, (void*)pvAuthInfo, M2M_WIFI_CH_ALL) < 0) { + _status = WL_CONNECT_FAILED; + return _status; + } + _status = WL_IDLE_STATUS; + _mode = WL_STA_MODE; + + // Wait for connection or timeout: + for (unsigned long start = millis(); millis() - start < _timeout;) + { + m2m_wifi_handle_events(NULL); + if ((_status & WL_CONNECTED) || (_status & WL_DISCONNECTED)) { + break; + } + } + if (!(_status & WL_CONNECTED)) { + _mode = WL_RESET_MODE; + } + + memset(_ssid, 0, M2M_MAX_SSID_LEN); + memcpy(_ssid, ssid, strlen(ssid)); + return _status; +} + +uint8_t WiFiClass::beginAP(const char *ssid) +{ + return beginAP(ssid, 1); +} + +uint8_t WiFiClass::beginAP(const char *ssid, uint8_t channel) +{ + return startAP(ssid, M2M_WIFI_SEC_OPEN, NULL, channel); +} + +uint8_t WiFiClass::beginAP(const char *ssid, uint8_t key_idx, const char* key) +{ + return beginAP(ssid, key_idx, key, 1); +} + +uint8_t WiFiClass::beginAP(const char *ssid, uint8_t key_idx, const char* key, uint8_t channel) +{ + tstrM2mWifiWepParams wep_params; + + if (key_idx == 0) { + key_idx = 1; // 1 is the minimum key index + } + + memset(&wep_params, 0, sizeof(tstrM2mWifiWepParams)); + wep_params.u8KeyIndx = key_idx; + wep_params.u8KeySz = strlen(key); + strcpy((char *)&wep_params.au8WepKey[0], key); + + return startAP(ssid, M2M_WIFI_SEC_WEP, &wep_params, channel); +} + +uint8_t WiFiClass::beginAP(const char *ssid, const char* key) +{ + return beginAP(ssid, key, 1); +} + +uint8_t WiFiClass::beginAP(const char *ssid, const char* key, uint8_t channel) +{ + return startAP(ssid, M2M_WIFI_SEC_WPA_PSK, key, channel); +} + +uint8_t WiFiClass::startAP(const char *ssid, uint8_t u8SecType, const void *pvAuthInfo, uint8_t channel) +{ + tstrM2MAPConfig strM2MAPConfig; + + if (!_init) { + init(); + } + + if (channel == 0) { + channel = 1; // channel 1 is the minium channel + } + + // Enter Access Point mode: + memset(&strM2MAPConfig, 0x00, sizeof(tstrM2MAPConfig)); + strcpy((char *)&strM2MAPConfig.au8SSID, ssid); + strM2MAPConfig.u8ListenChannel = channel; + strM2MAPConfig.u8SecType = u8SecType; + if (_localip == 0) { + strM2MAPConfig.au8DHCPServerIP[0] = 192; + strM2MAPConfig.au8DHCPServerIP[1] = 168; + strM2MAPConfig.au8DHCPServerIP[2] = 1; + strM2MAPConfig.au8DHCPServerIP[3] = 1; + } else { + memcpy(strM2MAPConfig.au8DHCPServerIP, &_localip, sizeof(_localip)); + if (strM2MAPConfig.au8DHCPServerIP[3] == 100) { + // limitation of WINC1500 firmware, IP address of client is always x.x.x.100 + _status = WL_AP_FAILED; + return _status; + } + } + + if (u8SecType == M2M_WIFI_SEC_WEP) { + tstrM2mWifiWepParams* wep_params = (tstrM2mWifiWepParams*)pvAuthInfo; + + strM2MAPConfig.u8KeyIndx = wep_params->u8KeyIndx; + strM2MAPConfig.u8KeySz = wep_params->u8KeySz; + strcpy((char*)strM2MAPConfig.au8WepKey, (char *)wep_params->au8WepKey); + } + + if (u8SecType == M2M_WIFI_SEC_WPA_PSK) { + strM2MAPConfig.u8KeySz = strlen((char*)pvAuthInfo); + strcpy((char*)strM2MAPConfig.au8Key, (char *)pvAuthInfo); + } + + if (m2m_wifi_enable_ap(&strM2MAPConfig) < 0) { + _status = WL_AP_FAILED; + return _status; + } + _status = WL_AP_LISTENING; + _mode = WL_AP_MODE; + + memset(_ssid, 0, M2M_MAX_SSID_LEN); + memcpy(_ssid, ssid, strlen(ssid)); + m2m_memcpy((uint8 *)&_localip, (uint8 *)&strM2MAPConfig.au8DHCPServerIP[0], 4); + _submask = 0x00FFFFFF; + _gateway = _localip; + +#ifdef CONF_PERIPH + // WiFi led ON (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO15, 0); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO4, 0); +#endif + + return _status; +} + +uint8_t WiFiClass::beginProvision() +{ + return beginProvision(1); +} + +uint8_t WiFiClass::beginProvision(uint8_t channel) +{ + // try to connect using begin + if (begin() != WL_CONNECTED) { + // failed, enter provisioning mode + + uint8_t mac[6]; + char provSsid[13]; + + // get MAC address for provisioning SSID + macAddress(mac); + sprintf(provSsid, "wifi101-%.2X%.2X", mac[1], mac[0]); + + // start provisioning mode + startProvision(provSsid, "wifi101", channel); + } + + return status(); +} + +uint8_t WiFiClass::startProvision(const char *ssid, const char *url, uint8_t channel) +{ + tstrM2MAPConfig strM2MAPConfig; + + if (!_init) { + init(); + } + + // Enter Provision mode: + memset(&strM2MAPConfig, 0x00, sizeof(tstrM2MAPConfig)); + strcpy((char *)&strM2MAPConfig.au8SSID, ssid); + strM2MAPConfig.u8ListenChannel = channel; + strM2MAPConfig.u8SecType = M2M_WIFI_SEC_OPEN; + strM2MAPConfig.u8SsidHide = SSID_MODE_VISIBLE; + strM2MAPConfig.au8DHCPServerIP[0] = 192; + strM2MAPConfig.au8DHCPServerIP[1] = 168; + strM2MAPConfig.au8DHCPServerIP[2] = 1; + strM2MAPConfig.au8DHCPServerIP[3] = 1; + + if (m2m_wifi_start_provision_mode((tstrM2MAPConfig *)&strM2MAPConfig, (char*)url, 1) < 0) { + _status = WL_PROVISIONING_FAILED; + return _status; + } + _status = WL_PROVISIONING; + _mode = WL_PROV_MODE; + + memset(_ssid, 0, M2M_MAX_SSID_LEN); + memcpy(_ssid, ssid, strlen(ssid)); + m2m_memcpy((uint8 *)&_localip, (uint8 *)&strM2MAPConfig.au8DHCPServerIP[0], 4); + _submask = 0x00FFFFFF; + _gateway = _localip; + +#ifdef CONF_PERIPH + // WiFi led ON (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO15, 0); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO4, 0); +#endif + + return _status; +} + +uint32_t WiFiClass::provisioned() +{ + m2m_wifi_handle_events(NULL); + + if (_mode == WL_STA_MODE) { + return 1; + } + else { + return 0; + } +} + +void WiFiClass::config(IPAddress local_ip) +{ + config(local_ip, (uint32_t)0); +} + +void WiFiClass::config(IPAddress local_ip, IPAddress dns_server) +{ + config(local_ip, dns_server, (uint32_t)0); +} + +void WiFiClass::config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway) +{ + config(local_ip, dns_server, gateway, (uint32_t)0); +} + +void WiFiClass::config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) +{ + tstrM2MIPConfig conf; + + if (!_init) { + init(); + } + + conf.u32DNS = (uint32_t)dns_server; + conf.u32Gateway = (uint32_t)gateway; + conf.u32StaticIP = (uint32_t)local_ip; + conf.u32SubnetMask = (uint32_t)subnet; + _dhcp = 0; + m2m_wifi_enable_dhcp(0); // disable DHCP + m2m_wifi_set_static_ip(&conf); + _localip = conf.u32StaticIP; + _submask = conf.u32SubnetMask; + _gateway = conf.u32Gateway; +} + +void WiFiClass::hostname(const char* name) +{ + if (!_init) { + init(); + } + + m2m_wifi_set_device_name((uint8 *)name, strlen(name)); +} + +void WiFiClass::disconnect() +{ + // Close sockets to clean state + for (int i = 0; i < MAX_SOCKET; i++) { + WiFiSocket.close(i); + } + + m2m_wifi_disconnect(); + +#ifdef CONF_PERIPH + // WiFi led OFF (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO15, 1); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO4, 1); +#endif +} + +void WiFiClass::end() +{ + // Close sockets to clean state + for (int i = 0; i < MAX_SOCKET; i++) { + WiFiSocket.close(i); + } + + if (_mode == WL_AP_MODE) { + m2m_wifi_disable_ap(); + } else { + if (_mode == WL_PROV_MODE) { + m2m_wifi_stop_provision_mode(); + } + + m2m_wifi_disconnect(); + } + +#ifdef CONF_PERIPH + // WiFi led OFF (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO15, 1); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO4, 1); +#endif + + socketDeinit(); + + m2m_wifi_deinit(NULL); + + nm_bsp_deinit(); + + _mode = WL_RESET_MODE; + _status = WL_NO_SHIELD; + _init = 0; +} + +uint8_t *WiFiClass::macAddress(uint8_t *mac) +{ + m2m_wifi_get_mac_address(mac); + byte tmpMac[6], i; + + m2m_wifi_get_mac_address(tmpMac); + + for(i = 0; i < 6; i++) + mac[i] = tmpMac[5-i]; + + return mac; +} + +uint32_t WiFiClass::localIP() +{ + return _localip; +} + +uint32_t WiFiClass::subnetMask() +{ + return _submask; +} + +uint32_t WiFiClass::gatewayIP() +{ + return _gateway; +} + +char* WiFiClass::SSID() +{ + if (_status == WL_CONNECTED || _status == WL_AP_LISTENING || _status == WL_AP_CONNECTED) { + return _ssid; + } + else { + return 0; + } +} + +uint8_t* WiFiClass::BSSID(uint8_t* bssid) +{ + if (_mode == WL_AP_MODE) { + return macAddress(bssid); + } else { + return remoteMacAddress(bssid); + } +} + +uint8_t* WiFiClass::APClientMacAddress(uint8_t* mac) +{ + if (_mode == WL_AP_MODE) { + return remoteMacAddress(mac); + } else { + memset(mac, 0, 6); + return mac; + } +} + +uint8_t* WiFiClass::remoteMacAddress(uint8_t* remoteMacAddress) +{ + _remoteMacAddress = remoteMacAddress; + memset(remoteMacAddress, 0, 6); + + m2m_wifi_get_connection_info(); + + // Wait for connection or timeout: + unsigned long start = millis(); + while (_remoteMacAddress != 0 && millis() - start < 1000) { + m2m_wifi_handle_events(NULL); + } + + _remoteMacAddress = 0; + return remoteMacAddress; +} + +int32_t WiFiClass::RSSI() +{ + if (_mode == WL_RESET_MODE) { + return -100; + } + + // Clear pending events: + m2m_wifi_handle_events(NULL); + + // Send RSSI request: + _resolve = 0; + if (m2m_wifi_req_curr_rssi() < 0) { + return 0; + } + + // Wait for connection or timeout: + unsigned long start = millis(); + while (_resolve == 0 && millis() - start < 1000) { + m2m_wifi_handle_events(NULL); + } + + int32_t rssi = _resolve; + + _resolve = 0; + + return rssi; +} + +int8_t WiFiClass::scanNetworks() +{ + wl_status_t tmp = _status; + + if (!_init) { + init(); + } + + // Start scan: + if (m2m_wifi_request_scan(M2M_WIFI_CH_ALL) < 0) { + return 0; + } + + // Wait for scan result or timeout: + _status = WL_IDLE_STATUS; + unsigned long start = millis(); + while (!(_status & WL_SCAN_COMPLETED) && millis() - start < 5000) { + m2m_wifi_handle_events(NULL); + } + _status = tmp; + return m2m_wifi_get_num_ap_found(); +} + +char* WiFiClass::SSID(uint8_t pos) +{ + wl_status_t tmp = _status; + + // Get scan SSID result: + memset(_scan_ssid, 0, M2M_MAX_SSID_LEN); + if (m2m_wifi_req_scan_result(pos) < 0) { + return 0; + } + + // Wait for connection or timeout: + _status = WL_IDLE_STATUS; + unsigned long start = millis(); + while (!(_status & WL_SCAN_COMPLETED) && millis() - start < 2000) { + m2m_wifi_handle_events(NULL); + } + + _status = tmp; + _resolve = 0; + + return _scan_ssid; +} + +int32_t WiFiClass::RSSI(uint8_t pos) +{ + wl_status_t tmp = _status; + + // Get scan RSSI result: + if (m2m_wifi_req_scan_result(pos) < 0) { + return 0; + } + + // Wait for connection or timeout: + _status = WL_IDLE_STATUS; + unsigned long start = millis(); + while (!(_status & WL_SCAN_COMPLETED) && millis() - start < 2000) { + m2m_wifi_handle_events(NULL); + } + + _status = tmp; + + int32_t rssi = _resolve; + + _resolve = 0; + + return rssi; +} + +uint8_t WiFiClass::encryptionType() +{ + int8_t net = scanNetworks(); + + for (uint8_t i = 0; i < net; ++i) { + SSID(i); + if (strcmp(_scan_ssid, _ssid) == 0) { + break; + } + } + + return _scan_auth; +} + +uint8_t WiFiClass::encryptionType(uint8_t pos) +{ + wl_status_t tmp = _status; + + // Get scan auth result: + if (m2m_wifi_req_scan_result(pos) < 0) { + return 0; + } + + // Wait for connection or timeout: + _status = WL_IDLE_STATUS; + unsigned long start = millis(); + while (!(_status & WL_SCAN_COMPLETED) && millis() - start < 2000) { + m2m_wifi_handle_events(NULL); + } + + _status = tmp; + _resolve = 0; + + return _scan_auth; +} + +uint8_t* WiFiClass::BSSID(uint8_t pos, uint8_t* bssid) +{ + wl_status_t tmp = _status; + + _remoteMacAddress = bssid; + + // Get scan auth result: + if (m2m_wifi_req_scan_result(pos) < 0) { + return 0; + } + + // Wait for connection or timeout: + _status = WL_IDLE_STATUS; + unsigned long start = millis(); + while (!(_status & WL_SCAN_COMPLETED) && millis() - start < 2000) { + m2m_wifi_handle_events(NULL); + } + + _status = tmp; + _resolve = 0; + _remoteMacAddress = 0; + + return bssid; +} + +uint8_t WiFiClass::channel(uint8_t pos) +{ + wl_status_t tmp = _status; + + // Get scan auth result: + if (m2m_wifi_req_scan_result(pos) < 0) { + return 0; + } + + // Wait for connection or timeout: + _status = WL_IDLE_STATUS; + unsigned long start = millis(); + while (!(_status & WL_SCAN_COMPLETED) && millis() - start < 2000) { + m2m_wifi_handle_events(NULL); + } + + _status = tmp; + _resolve = 0; + + return _scan_channel; +} + +uint8_t WiFiClass::status() +{ + if (!_init) { + init(); + } + + m2m_wifi_handle_events(NULL); + + return _status; +} + +int WiFiClass::hostByName(const char* aHostname, IPAddress& aResult) +{ + + // check if aHostname is already an ipaddress + if (aResult.fromString(aHostname)) { + // if fromString returns true we have an IP address ready + return 1; + + } else { +#ifdef CONF_PERIPH + // Network led ON (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO16, 0); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO5, 0); +#endif + + // Send DNS request: + _resolve = 0; + if (gethostbyname((uint8 *)aHostname) < 0) { +#ifdef CONF_PERIPH + // Network led OFF (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO16, 1); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO5, 1); +#endif + return 0; + } + + // Wait for connection or timeout: + unsigned long start = millis(); + while (_resolve == 0 && millis() - start < 20000) { + m2m_wifi_handle_events(NULL); + } + +#ifdef CONF_PERIPH + // Network led OFF (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO16, 1); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO5, 1); +#endif + + if (_resolve == 0) { + return 0; + } + + aResult = _resolve; + _resolve = 0; + return 1; + } +} + +void WiFiClass::refresh(void) +{ + // Update state machine: + m2m_wifi_handle_events(NULL); +} + +void WiFiClass::lowPowerMode(void) +{ + m2m_wifi_set_sleep_mode(M2M_PS_H_AUTOMATIC, true); +} + +void WiFiClass::maxLowPowerMode(void) +{ + m2m_wifi_set_sleep_mode(M2M_PS_DEEP_AUTOMATIC, true); +} + +void WiFiClass::noLowPowerMode(void) +{ + m2m_wifi_set_sleep_mode(M2M_NO_PS, false); +} + +int WiFiClass::ping(const char* hostname, uint8_t ttl) +{ + IPAddress ip; + + if (hostByName(hostname, ip) > 0) { + return ping(ip, ttl); + } else { + return WL_PING_UNKNOWN_HOST; + } +} + +int WiFiClass::ping(const String &hostname, uint8_t ttl) +{ + return ping(hostname.c_str(), ttl); +} + +int WiFiClass::ping(IPAddress host, uint8_t ttl) +{ +#ifdef CONF_PERIPH + // Network led ON (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO16, 0); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO5, 0); +#endif + + uint32_t dstHost = (uint32_t)host; + _resolve = dstHost; + + if (m2m_ping_req((uint32_t)host, ttl, &ping_cb) < 0) { +#ifdef CONF_PERIPH + // Network led OFF (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO16, 1); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO5, 1); +#endif + // Error sending ping request + return WL_PING_ERROR; + } + + // Wait for success or timeout: + unsigned long start = millis(); + while (_resolve == dstHost && millis() - start < 5000) { + m2m_wifi_handle_events(NULL); + } + +#ifdef CONF_PERIPH + // Network led OFF (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO16, 1); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO5, 1); +#endif + + if (_resolve == dstHost) { + _resolve = 0; + return WL_PING_TIMEOUT; + } else { + int rtt = (int)_resolve; + _resolve = 0; + return rtt; + } +} + +uint32_t WiFiClass::getTime() +{ +#ifdef WIFI_101_NO_TIME_H + #warning "No system header included, WiFi.getTime() will always return 0" + return 0; +#else + tstrSystemTime systemTime; + + _resolve = (uint32_t)&systemTime; + + m2m_wifi_get_sytem_time(); + + unsigned long start = millis(); + while (_resolve != 0 && millis() - start < 5000) { + m2m_wifi_handle_events(NULL); + } + + time_t t = 0; + + if (_resolve == 0 && systemTime.u16Year > 0) { + struct tm tm; + + tm.tm_year = systemTime.u16Year - 1900; + tm.tm_mon = systemTime.u8Month - 1; + tm.tm_mday = systemTime.u8Day; + tm.tm_hour = systemTime.u8Hour; + tm.tm_min = systemTime.u8Minute; + tm.tm_sec = systemTime.u8Second; + tm.tm_isdst = -1; + + t = mktime(&tm); + } + + _resolve = 0; + + return t; +#endif +} + +void WiFiClass::setTimeout(unsigned long timeout) +{ + _timeout = timeout; +} + +WiFiClass WiFi; diff --git a/lib/WiFi101/src/WiFi101.h b/lib/WiFi101/src/WiFi101.h new file mode 100644 index 0000000..00b3830 --- /dev/null +++ b/lib/WiFi101/src/WiFi101.h @@ -0,0 +1,197 @@ +/* + WiFi.h - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIFI_H +#define WIFI_H + +#define WIFI_FIRMWARE_LATEST_MODEL_A "19.4.4" +#define WIFI_FIRMWARE_LATEST_MODEL_B "19.6.1" + +// for backwards compatibility +#define WIFI_FIRMWARE_REQUIRED WIFI_FIRMWARE_LATEST_MODEL_B + +#include + +extern "C" { + #include "driver/include/m2m_wifi.h" +} + +#include "WiFiClient.h" +#include "WiFiSSLClient.h" +#include "WiFiServer.h" + +typedef enum { + WL_NO_SHIELD = 255, + WL_IDLE_STATUS = 0, + WL_NO_SSID_AVAIL, + WL_SCAN_COMPLETED, + WL_CONNECTED, + WL_CONNECT_FAILED, + WL_CONNECTION_LOST, + WL_DISCONNECTED, + WL_AP_LISTENING, + WL_AP_CONNECTED, + WL_AP_FAILED, + WL_PROVISIONING, + WL_PROVISIONING_FAILED +} wl_status_t; + +/* Encryption modes */ +enum wl_enc_type { /* Values map to 802.11 encryption suites... */ + ENC_TYPE_WEP = M2M_WIFI_SEC_WEP, + ENC_TYPE_TKIP = M2M_WIFI_SEC_WPA_PSK, + ENC_TYPE_CCMP = M2M_WIFI_SEC_802_1X, + /* ... except these two, 7 and 8 are reserved in 802.11-2007 */ + ENC_TYPE_NONE = M2M_WIFI_SEC_OPEN, + ENC_TYPE_AUTO = M2M_WIFI_SEC_INVALID +}; + +typedef enum { + WL_RESET_MODE = 0, + WL_STA_MODE, + WL_PROV_MODE, + WL_AP_MODE +} wl_mode_t; + +typedef enum { + WL_PING_DEST_UNREACHABLE = -1, + WL_PING_TIMEOUT = -2, + WL_PING_UNKNOWN_HOST = -3, + WL_PING_ERROR = -4 +} wl_ping_result_t; + +class WiFiClass +{ +public: + WiFiClass(); + + void setPins(int8_t cs, int8_t irq, int8_t rst, int8_t en = -1); + + int init(); + + char* firmwareVersion(); + + /* Start Wifi connection with WPA/WPA2 encryption. + * + * param ssid: Pointer to the SSID string. + * param key: Key input buffer. + */ + uint8_t begin(); + uint8_t begin(const char *ssid); + uint8_t begin(const char *ssid, uint8_t key_idx, const char* key); + uint8_t begin(const char *ssid, const char *key); + uint8_t begin(const String &ssid) { return begin(ssid.c_str()); } + uint8_t begin(const String &ssid, uint8_t key_idx, const String &key) { return begin(ssid.c_str(), key_idx, key.c_str()); } + uint8_t begin(const String &ssid, const String &key) { return begin(ssid.c_str(), key.c_str()); } + + /* Start Wifi in Access Point, with open security. + * Only one client can connect to the AP at a time. + * + * param ssid: Pointer to the SSID string. + * param channel: Wifi channel to use. Valid values are 1-12. + */ + uint8_t beginAP(const char *ssid); + uint8_t beginAP(const char *ssid, uint8_t channel); + uint8_t beginAP(const char *ssid, uint8_t key_idx, const char* key); + uint8_t beginAP(const char *ssid, uint8_t key_idx, const char* key, uint8_t channel); + uint8_t beginAP(const char *ssid, const char* key); + uint8_t beginAP(const char *ssid, const char* key, uint8_t channel); + + uint8_t beginProvision(); + uint8_t beginProvision(uint8_t channel); + + uint32_t provisioned(); + + void config(IPAddress local_ip); + void config(IPAddress local_ip, IPAddress dns_server); + void config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway); + void config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet); + + void hostname(const char* name); + + void disconnect(); + void end(); + + uint8_t *macAddress(uint8_t *mac); + + uint32_t localIP(); + uint32_t subnetMask(); + uint32_t gatewayIP(); + char* SSID(); + int32_t RSSI(); + uint8_t encryptionType(); + uint8_t* BSSID(uint8_t* bssid); + uint8_t* APClientMacAddress(uint8_t* mac); + int8_t scanNetworks(); + char* SSID(uint8_t pos); + int32_t RSSI(uint8_t pos); + uint8_t encryptionType(uint8_t pos); + uint8_t* BSSID(uint8_t pos, uint8_t* bssid); + uint8_t channel(uint8_t pos); + + uint8_t status(); + + int hostByName(const char* hostname, IPAddress& result); + int hostByName(const String &hostname, IPAddress& result) { return hostByName(hostname.c_str(), result); } + + int ping(const char* hostname, uint8_t ttl = 128); + int ping(const String &hostname, uint8_t ttl = 128); + int ping(IPAddress host, uint8_t ttl = 128); + + unsigned long getTime(); + + void refresh(void); + + void lowPowerMode(void); + void maxLowPowerMode(void); + void noLowPowerMode(void); + + void handleEvent(uint8_t u8MsgType, void *pvMsg); + void handleResolve(uint8_t * hostName, uint32_t hostIp); + void handlePingResponse(uint32 u32IPAddr, uint32 u32RTT, uint8 u8ErrorCode); + void setTimeout(unsigned long timeout); + +private: + int _init; + char _version[9]; + + uint32_t _localip; + uint32_t _submask; + uint32_t _gateway; + int _dhcp; + uint32_t _resolve; + byte *_remoteMacAddress; + wl_mode_t _mode; + wl_status_t _status; + char _scan_ssid[M2M_MAX_SSID_LEN]; + uint8_t _scan_auth; + uint8_t _scan_channel; + char _ssid[M2M_MAX_SSID_LEN]; + unsigned long _timeout; + + uint8_t startConnect(const char *ssid, uint8_t u8SecType, const void *pvAuthInfo); + uint8_t startAP(const char *ssid, uint8_t u8SecType, const void *pvAuthInfo, uint8_t channel); + uint8_t* remoteMacAddress(uint8_t* remoteMacAddress); + + uint8_t startProvision(const char *ssid, const char *url, uint8_t channel); +}; + +extern WiFiClass WiFi; + +#endif /* WIFI_H */ diff --git a/lib/WiFi101/src/WiFiClient.cpp b/lib/WiFi101/src/WiFiClient.cpp new file mode 100644 index 0000000..43e9cea --- /dev/null +++ b/lib/WiFi101/src/WiFiClient.cpp @@ -0,0 +1,228 @@ +/* + WiFiClient.cpp - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "utility/WiFiSocket.h" + +#include "WiFi101.h" +#include "WiFiClient.h" + +WiFiClient::WiFiClient() +{ + _socket = -1; +} + +WiFiClient::WiFiClient(uint8_t sock) +{ + // Spawn connected TCP client from TCP server socket: + _socket = sock; +} + +int WiFiClient::connectSSL(const char* host, uint16_t port) +{ + return connect(host, port, SOCKET_FLAGS_SSL); +} + +int WiFiClient::connectSSL(IPAddress ip, uint16_t port) +{ + return connect(ip, port, SOCKET_FLAGS_SSL, 0); +} + +int WiFiClient::connect(const char* host, uint16_t port) +{ + return connect(host, port, 0); +} + +int WiFiClient::connect(IPAddress ip, uint16_t port) +{ + return connect(ip, port, 0, 0); +} + +int WiFiClient::connect(const char* host, uint16_t port, uint8_t opt) +{ + IPAddress remote_addr; + if (WiFi.hostByName(host, remote_addr)) { + return connect(remote_addr, port, opt, (const uint8_t *)host); + } + return 0; +} + +int WiFiClient::connect(IPAddress ip, uint16_t port, uint8_t opt, const uint8_t *hostname) +{ + struct sockaddr_in addr; + + // Initialize socket address structure: + addr.sin_family = AF_INET; + addr.sin_port = _htons(port); + addr.sin_addr.s_addr = ip; + + if (connected()) { + stop(); + } + + // Create TCP socket: + if ((_socket = WiFiSocket.create(AF_INET, SOCK_STREAM, opt)) < 0) { + return 0; + } + + if (opt & SOCKET_FLAGS_SSL && hostname) { + WiFiSocket.setopt(_socket, SOL_SSL_SOCKET, SO_SSL_SNI, hostname, m2m_strlen((uint8_t *)hostname)); + } + + // Connect to remote host: + if (!WiFiSocket.connect(_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) { + WiFiSocket.close(_socket); + _socket = -1; + return 0; + } + + return 1; +} + +size_t WiFiClient::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t WiFiClient::write(const uint8_t *buf, size_t size) +{ + if (_socket < 0 || size == 0 || !connected()) { + setWriteError(); + return 0; + } + + int result = WiFiSocket.write(_socket, buf, size); + + if (result <= 0) { + setWriteError(); + return 0; + } + + return size; +} + +int WiFiClient::available() +{ + if (_socket == -1) { + return 0; + } + + return WiFiSocket.available(_socket); +} + +int WiFiClient::read() +{ + uint8_t b; + + if (read(&b, sizeof(b)) != 1) { + return -1; + } + + return b; +} + +int WiFiClient::read(uint8_t* buf, size_t size) +{ + // sizeof(size_t) is architecture dependent + // but we need a 16 bit data type here + uint16_t size_tmp = available(); + + if (size_tmp == 0) { + return -1; + } + + if (size < size_tmp) { + size_tmp = size; + } + + int result = WiFiSocket.read(_socket, buf, size); + + return result; +} + +int WiFiClient::peek() +{ + if (!available()) { + return -1; + } + + return WiFiSocket.peek(_socket); +} + +void WiFiClient::flush() +{ +} + +void WiFiClient::stop() +{ + if (_socket < 0) { + return; + } + + WiFiSocket.close(_socket); + + _socket = -1; +} + +uint8_t WiFiClient::connected() +{ + if (_socket < 0) { + return 0; + } + + return WiFiSocket.connected(_socket); +} + +uint8_t WiFiClient::status() +{ + // Deprecated. + return 0; +} + +WiFiClient::operator bool() +{ + return _socket != -1; +} + +bool WiFiClient::operator==(const WiFiClient &other) const +{ + return (_socket == other._socket); +} + +bool WiFiClient::operator!=(const WiFiClient &other) const +{ + return (_socket != other._socket); +} + +IPAddress WiFiClient::remoteIP() +{ + if (_socket == -1) { + return IPAddress(0, 0, 0, 0); + } + + return WiFiSocket.remoteIP(_socket); +} + +uint16_t WiFiClient::remotePort() +{ + if (_socket == -1) { + return 0; + } + + return _htons(WiFiSocket.remotePort(_socket)); +} diff --git a/lib/WiFi101/src/WiFiClient.h b/lib/WiFi101/src/WiFiClient.h new file mode 100644 index 0000000..d8de3c7 --- /dev/null +++ b/lib/WiFi101/src/WiFiClient.h @@ -0,0 +1,68 @@ +/* + WiFiClient.cpp - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIFICLIENT_H +#define WIFICLIENT_H + +#include +#include +#include + +extern "C" { + #include "socket/include/socket.h" +} + +class WiFiClient : public Client { + +public: + WiFiClient(); + WiFiClient(uint8_t sock); + + uint8_t status(); + + int connectSSL(IPAddress ip, uint16_t port); + int connectSSL(const char* host, uint16_t port); + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char* host, uint16_t port); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool(); + bool operator==(const WiFiClient &other) const; + bool operator!=(const WiFiClient &other) const; + + using Print::write; + + virtual IPAddress remoteIP(); + virtual uint16_t remotePort(); + +private: + SOCKET _socket; + + int connect(const char* host, uint16_t port, uint8_t opt); + int connect(IPAddress ip, uint16_t port, uint8_t opt, const uint8_t *hostname); +}; + +#endif /* WIFICLIENT_H */ diff --git a/lib/WiFi101/src/WiFiMDNSResponder.cpp b/lib/WiFi101/src/WiFiMDNSResponder.cpp new file mode 100644 index 0000000..a192113 --- /dev/null +++ b/lib/WiFi101/src/WiFiMDNSResponder.cpp @@ -0,0 +1,220 @@ +// Port of CC3000 MDNS Responder to WINC1500. +// Author: Tony DiCola +// +// This MDNSResponder class implements just enough MDNS functionality to respond +// to name requests, for example 'foo.local'. This does not implement any other +// MDNS or Bonjour functionality like services, etc. +// +// Copyright (c) 2016 Adafruit Industries. All right reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +#include +#ifndef ARDUINO_ARCH_AVR +#include +#endif + +#include "Arduino.h" +#include "WiFiMDNSResponder.h" + +// Important RFC's for reference: +// - DNS request and response: http://www.ietf.org/rfc/rfc1035.txt +// - Multicast DNS: http://www.ietf.org/rfc/rfc6762.txt + +#define HEADER_SIZE 12 +#define TTL_OFFSET 4 +#define IP_OFFSET 10 + +const uint8_t expectedRequestHeader[HEADER_SIZE] PROGMEM = { + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x01, // questions (these 2 bytes are ignored) + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00 +}; + +const uint8_t responseHeader[] PROGMEM = { + 0x00, 0x00, // ID = 0 + 0x84, 0x00, // Flags = response + authoritative answer + 0x00, 0x00, // Question count = 0 + 0x00, 0x01, // Answer count = 1 + 0x00, 0x00, // Name server records = 0 + 0x00, 0x01 // Additional records = 1 +}; + +// Generate positive response for IPV4 address +const uint8_t aRecord[] PROGMEM = { + 0x00, 0x01, // Type = 1, A record/IPV4 address + 0x80, 0x01, // Class = Internet, with cache flush bit + 0x00, 0x00, 0x00, 0x00, // TTL in seconds, to be filled in later + 0x00, 0x04, // Length of record + 0x00, 0x00, 0x00, 0x00 // IP address, to be filled in later +}; + +// Generate negative response for IPV6 address (CC3000 doesn't support IPV6) +const uint8_t nsecRecord[] PROGMEM = { + 0xC0, 0x0C, // Name offset + 0x00, 0x2F, // Type = 47, NSEC (overloaded by MDNS) + 0x80, 0x01, // Class = Internet, with cache flush bit + 0x00, 0x00, 0x00, 0x00, // TTL in seconds, to be filled in later + 0x00, 0x08, // Length of record + 0xC0, 0x0C, // Next domain = offset to FQDN + 0x00, // Block number = 0 + 0x04, // Length of bitmap = 4 bytes + 0x40, 0x00, 0x00, 0x00 // Bitmap value = Only first bit (A record/IPV4) is set +}; + +const uint8_t domain[] PROGMEM = { 'l', 'o', 'c', 'a', 'l' }; + +WiFiMDNSResponder::WiFiMDNSResponder() : + minimumExpectedRequestLength(0) +{ +} + +WiFiMDNSResponder::~WiFiMDNSResponder() +{ +} + +bool WiFiMDNSResponder::begin(const char* _name, uint32_t _ttlSeconds) +{ + int nameLength = strlen(_name); + + if (nameLength > 255) { + // Can only handle domains that are upto 255 chars in length. + minimumExpectedRequestLength = 0; + return false; + } + + name = _name; + ttlSeconds = _ttlSeconds; + + name.toLowerCase(); + minimumExpectedRequestLength = HEADER_SIZE + 1 + nameLength + 1 + sizeof(domain) + 5; + + // Open the MDNS UDP listening socket on port 5353 with multicast address + // 224.0.0.251 (0xE00000FB) + if (!udpSocket.beginMulticast(IPAddress(224, 0, 0, 251), 5353)) { + return false; + } + + return true; +} + +void WiFiMDNSResponder::poll() +{ + if (parseRequest()) { + replyToRequest(); + } +} + +bool WiFiMDNSResponder::parseRequest() +{ + int packetLength = udpSocket.parsePacket(); + + if (packetLength) { + // check if parsed packet matches expected request length + if (packetLength < minimumExpectedRequestLength) { + // it does not, read the full packet in and drop data + while(udpSocket.available()) { + udpSocket.read(); + } + + return false; + } + + // read up to the min expect request length + uint8_t request[minimumExpectedRequestLength]; + udpSocket.read(request, minimumExpectedRequestLength); + + // discard the rest + while(udpSocket.available()) { + udpSocket.read(); + } + + // parse request + uint8_t requestNameLength = request[HEADER_SIZE]; + uint8_t* requestName = &request[HEADER_SIZE + 1]; + uint8_t requestDomainLength = request[HEADER_SIZE + 1 + requestNameLength]; + uint8_t* requestDomain = &request[HEADER_SIZE + 1 + requestNameLength + 1]; + uint16_t requestQtype; + uint16_t requestQclass; + + memcpy(&requestQtype, &request[minimumExpectedRequestLength - 4], sizeof(requestQtype)); + memcpy(&requestQclass, &request[minimumExpectedRequestLength - 2], sizeof(requestQclass)); + + requestQtype = _ntohs(requestQtype); + requestQclass = _ntohs(requestQclass); + + // compare request + if (memcmp_P(request, expectedRequestHeader, 4) == 0 && // request header start match + memcmp_P(&request[6], &expectedRequestHeader[6], 6) == 0 && // request header end match + requestNameLength == name.length() && // name length match + strncasecmp(name.c_str(), (char*)requestName, requestNameLength) == 0 && // name match + requestDomainLength == sizeof(domain) && // domain length match + memcmp_P(requestDomain, domain, requestDomainLength) == 0 && // suffix match + requestQtype == 0x0001 && // request QType match + requestQclass == 0x0001) { // request QClass match + + return true; + } + } + + return false; +} + +void WiFiMDNSResponder::replyToRequest() +{ + int nameLength = name.length(); + int domainLength = sizeof(domain); + uint32_t ipAddress = WiFi.localIP(); + uint32_t ttl = _htonl(ttlSeconds); + + int responseSize = sizeof(responseHeader) + 1 + nameLength + 1 + domainLength + 1 + sizeof(aRecord) + sizeof(nsecRecord); + uint8_t response[responseSize]; + uint8_t* r = response; + + // copy header + memcpy_P(r, responseHeader, sizeof(responseHeader)); + r += sizeof(responseHeader); + + // copy name + *r = nameLength; + memcpy(r + 1, name.c_str(), nameLength); + r += (1 + nameLength); + + // copy domain + *r = domainLength; + memcpy_P(r + 1, domain, domainLength); + r += (1 + domainLength); + + // terminator + *r = 0x00; + r++; + + // copy A record + memcpy_P(r, aRecord, sizeof(aRecord)); + memcpy(r + TTL_OFFSET, &ttl, sizeof(ttl)); // replace TTL value + memcpy(r + IP_OFFSET, &ipAddress, sizeof(ipAddress)); // replace IP address value + r += sizeof(aRecord); + + // copy NSEC record + memcpy_P(r, nsecRecord, sizeof(nsecRecord)); + r += sizeof(nsecRecord); + + udpSocket.beginPacket(IPAddress(224, 0, 0, 251), 5353); + udpSocket.write(response, responseSize); + udpSocket.endPacket(); +} diff --git a/lib/WiFi101/src/WiFiMDNSResponder.h b/lib/WiFi101/src/WiFiMDNSResponder.h new file mode 100644 index 0000000..d7e3d43 --- /dev/null +++ b/lib/WiFi101/src/WiFiMDNSResponder.h @@ -0,0 +1,51 @@ +// Port of CC3000 MDNS Responder to WINC1500. +// Author: Tony DiCola +// +// This MDNSResponder class implements just enough MDNS functionality to respond +// to name requests, for example 'foo.local'. This does not implement any other +// MDNS or Bonjour functionality like services, etc. +// +// Copyright (c) 2016 Adafruit Industries. All right reserved. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library 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 +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +#ifndef WIFIMDNSRESPONDER_H +#define WIFIMDNSRESPONDER_H + +#include "WiFi101.h" +#include "WiFiUdp.h" + +class WiFiMDNSResponder { +public: + WiFiMDNSResponder(); + ~WiFiMDNSResponder(); + bool begin(const char* _name, uint32_t _ttlSeconds = 3600); + void poll(); + +private: + bool parseRequest(); + void replyToRequest(); + +private: + String name; + uint32_t ttlSeconds; + + int minimumExpectedRequestLength; + + // UDP socket for receiving/sending MDNS data. + WiFiUDP udpSocket; +}; + +#endif diff --git a/lib/WiFi101/src/WiFiSSLClient.cpp b/lib/WiFi101/src/WiFiSSLClient.cpp new file mode 100644 index 0000000..c6814c8 --- /dev/null +++ b/lib/WiFi101/src/WiFiSSLClient.cpp @@ -0,0 +1,40 @@ +/* + WiFiSSLClient.cpp - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "WiFiSSLClient.h" + +WiFiSSLClient::WiFiSSLClient() : + WiFiClient() +{ +} + +WiFiSSLClient::WiFiSSLClient(uint8_t sock) : + WiFiClient(sock) +{ +} + +int WiFiSSLClient::connect(IPAddress ip, uint16_t port) +{ + return WiFiClient::connectSSL(ip, port); +} + +int WiFiSSLClient::connect(const char* host, uint16_t port) +{ + return WiFiClient::connectSSL(host, port); +} diff --git a/lib/WiFi101/src/WiFiSSLClient.h b/lib/WiFi101/src/WiFiSSLClient.h new file mode 100644 index 0000000..9335076 --- /dev/null +++ b/lib/WiFi101/src/WiFiSSLClient.h @@ -0,0 +1,35 @@ +/* + WiFiSSLClient.cpp - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIFISSLCLIENT_H +#define WIFISSLCLIENT_H + +#include "WiFiClient.h" + +class WiFiSSLClient : public WiFiClient { + +public: + WiFiSSLClient(); + WiFiSSLClient(uint8_t sock); + + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char* host, uint16_t port); +}; + +#endif /* WIFISSLCLIENT_H */ diff --git a/lib/WiFi101/src/WiFiServer.cpp b/lib/WiFi101/src/WiFiServer.cpp new file mode 100644 index 0000000..fa72ddc --- /dev/null +++ b/lib/WiFi101/src/WiFiServer.cpp @@ -0,0 +1,129 @@ +/* + WiFiClient.cpp - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "utility/WiFiSocket.h" + +#include "WiFiClient.h" +#include "WiFiServer.h" + +WiFiServer::WiFiServer(uint16_t port) : + _socket(-1) +{ + _port = port; +} + +void WiFiServer::begin() +{ + begin(0); +} + +uint8_t WiFiServer::beginSSL() +{ + return begin(SOCKET_FLAGS_SSL); +} + +uint8_t WiFiServer::begin(uint8_t opt) +{ + struct sockaddr_in addr; + + // Initialize socket address structure. + addr.sin_family = AF_INET; + addr.sin_port = _htons(_port); + addr.sin_addr.s_addr = 0; + + if (_socket != -1 && WiFiSocket.listening(_socket)) { + WiFiSocket.close(_socket); + _socket = -1; + } + + // Open TCP server socket. + if ((_socket = WiFiSocket.create(AF_INET, SOCK_STREAM, opt)) < 0) { + return 0; + } + + // Bind socket: + if (!WiFiSocket.bind(_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) { + WiFiSocket.close(_socket); + _socket = -1; + return 0; + } + + // Listen socket: + if (!WiFiSocket.listen(_socket, 0)) { + WiFiSocket.close(_socket); + _socket = -1; + return 0; + } + + return 1; +} + +WiFiClient WiFiServer::available(uint8_t* status) +{ + if (status != NULL) { + *status = 0; + } + + if (_socket != -1 && !WiFiSocket.listening(_socket)) { + _socket = -1; + } + + if (_socket != -1) { + SOCKET child = WiFiSocket.accepted(_socket); + + if (child > -1) { + return WiFiClient(child); + } + + for (SOCKET s = 0; s < TCP_SOCK_MAX; s++) { + if (WiFiSocket.hasParent(_socket, s) && WiFiSocket.available(s)) { + return WiFiClient(s); + } + } + } + + return WiFiClient(); +} + +uint8_t WiFiServer::status() { + // Deprecated. + return 0; +} + +size_t WiFiServer::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t WiFiServer::write(const uint8_t *buffer, size_t size) +{ + if (_socket == -1) { + return 0; + } + + size_t n = 0; + + for (int sock = 0; sock < TCP_SOCK_MAX; sock++) { + if (WiFiSocket.hasParent(_socket, sock)) { + n += WiFiSocket.write(sock, buffer, size); + } + } + + return n; +} diff --git a/lib/WiFi101/src/WiFiServer.h b/lib/WiFi101/src/WiFiServer.h new file mode 100644 index 0000000..22ff743 --- /dev/null +++ b/lib/WiFi101/src/WiFiServer.h @@ -0,0 +1,48 @@ +/* + WiFiClient.cpp - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIFISERVER_H +#define WIFISERVER_H + +#include +#include + +class WiFiClient; + +class WiFiServer : public Server { + +private: + SOCKET _socket; + uint16_t _port; + uint8_t begin(uint8_t opt); + +public: + WiFiServer(uint16_t); + WiFiClient available(uint8_t* status = NULL); + void begin(); + uint8_t beginSSL(); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + uint8_t status(); + + using Print::write; + +}; + +#endif /* WIFISERVER_H */ diff --git a/lib/WiFi101/src/WiFiUdp.cpp b/lib/WiFi101/src/WiFiUdp.cpp new file mode 100644 index 0000000..1d08085 --- /dev/null +++ b/lib/WiFi101/src/WiFiUdp.cpp @@ -0,0 +1,242 @@ +/* + WiFiUdp.cpp - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include "utility/WiFiSocket.h" + +#include "WiFi101.h" +#include "WiFiUdp.h" + +/* Constructor. */ +WiFiUDP::WiFiUDP() +{ + _socket = -1; + _sndSize = 0; + _parsedPacketSize = 0; +} + +/* Start WiFiUDP socket, listening at local port PORT */ +uint8_t WiFiUDP::begin(uint16_t port) +{ + struct sockaddr_in addr; + uint32 u32EnableCallbacks = 0; + + _sndSize = 0; + _parsedPacketSize = 0; + + // Initialize socket address structure. + addr.sin_family = AF_INET; + addr.sin_port = _htons(port); + addr.sin_addr.s_addr = 0; + + if (_socket != -1 && WiFiSocket.bound(_socket)) { + WiFiSocket.close(_socket); + _socket = -1; + } + + // Open UDP server socket. + if ((_socket = WiFiSocket.create(AF_INET, SOCK_DGRAM, 0)) < 0) { + return 0; + } + + WiFiSocket.setopt(_socket, SOL_SOCKET, SO_SET_UDP_SEND_CALLBACK, &u32EnableCallbacks, 0); + + // Bind socket: + if (!WiFiSocket.bind(_socket, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))) { + WiFiSocket.close(_socket); + _socket = -1; + return 0; + } + + return 1; +} + +uint8_t WiFiUDP::beginMulticast(IPAddress ip, uint16_t port) +{ + uint32_t multiIp = ip; + + if (!begin(port)) { + return 0; + } + + setsockopt(_socket, SOL_SOCKET, IP_ADD_MEMBERSHIP, &multiIp, sizeof(multiIp)); + + return 1; +} + +/* return number of bytes available in the current packet, + will return zero if parsePacket hasn't been called yet */ +int WiFiUDP::available() +{ + if (_socket == -1) { + return 0; + } + + if (_parsedPacketSize <= 0) { + return 0; + } + + return WiFiSocket.available(_socket); + } + +/* Release any resources being used by this WiFiUDP instance */ +void WiFiUDP::stop() +{ + if (_socket == -1) { + return; + } + + WiFiSocket.close(_socket); + _socket = -1; +} + +int WiFiUDP::beginPacket(const char *host, uint16_t port) +{ + IPAddress ip; + + if (WiFi.hostByName(host, ip)) { + return beginPacket(ip, port); + } + + return 0; +} + +int WiFiUDP::beginPacket(IPAddress ip, uint16_t port) +{ + _sndIP = ip; + _sndPort = port; + _sndSize = 0; + + return 1; +} + +int WiFiUDP::endPacket() +{ + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + addr.sin_port = _htons(_sndPort); + addr.sin_addr.s_addr = _sndIP; + + int result = WiFiSocket.sendto(_socket, (void *)_sndBuffer, _sndSize, 0, (struct sockaddr *)&addr, sizeof(addr)); + + return (result < 0) ? 0 : 1; +} + +size_t WiFiUDP::write(uint8_t byte) +{ + return write(&byte, 1); +} + +size_t WiFiUDP::write(const uint8_t *buffer, size_t size) +{ + if ((size + _sndSize) > sizeof(_sndBuffer)) { + size = sizeof(_sndBuffer) - _sndSize; + } + + memcpy(_sndBuffer + _sndSize, buffer, size); + + _sndSize += size; + + return size; +} + +int WiFiUDP::parsePacket() +{ + if (_socket == -1) { + return 0; + } + + if (_parsedPacketSize > 0) { + // previously parsed data, discard data + while (available()) { + read(); + } + } + + _parsedPacketSize = WiFiSocket.available(_socket); + + return _parsedPacketSize; +} + +int WiFiUDP::read() +{ + uint8_t b; + + if (read(&b, sizeof(b)) != 1) { + return -1; + } + + return b; +} + +int WiFiUDP::read(unsigned char* buf, size_t size) +{ + // sizeof(size_t) is architecture dependent + // but we need a 16 bit data type here + uint16_t size_tmp = available(); + + if (size_tmp == 0) { + return -1; + } + + if (size < size_tmp) { + size_tmp = size; + } + + int result = WiFiSocket.read(_socket, buf, size); + + if (result > 0) { + _parsedPacketSize -= result; + } + + return result; +} + +int WiFiUDP::peek() +{ + if (!available()) { + return -1; + } + + return WiFiSocket.peek(_socket); +} + +void WiFiUDP::flush() +{ +} + +IPAddress WiFiUDP::remoteIP() +{ + if (_socket == -1) { + return IPAddress(0, 0, 0, 0); + } + + return WiFiSocket.remoteIP(_socket); +} + +uint16_t WiFiUDP::remotePort() +{ + if (_socket == -1) { + return 0; + } + + return _htons(WiFiSocket.remotePort(_socket)); +} diff --git a/lib/WiFi101/src/WiFiUdp.h b/lib/WiFi101/src/WiFiUdp.h new file mode 100644 index 0000000..d1cf6eb --- /dev/null +++ b/lib/WiFi101/src/WiFiUdp.h @@ -0,0 +1,93 @@ +/* + WiFiUdp.h - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIFIUDP_H +#define WIFIUDP_H + +extern "C" { + #include "socket/include/socket.h" +} + +#include + +#if defined LIMITED_RAM_DEVICE +#define SOCKET_BUFFER_UDP_SIZE (64u) +#else +#define SOCKET_BUFFER_UDP_SIZE (SOCKET_BUFFER_MAX_LENGTH) +#endif + +class WiFiUDP : public UDP { +private: + SOCKET _socket; + int _parsedPacketSize; + uint8_t _sndBuffer[SOCKET_BUFFER_UDP_SIZE]; + uint16_t _sndSize; + uint16_t _sndPort; + uint32_t _sndIP; + +public: + WiFiUDP(); // Constructor + virtual uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual uint8_t beginMulticast(IPAddress, uint16_t); // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 if there are no sockets available to use + virtual uint8_t beginMulti(IPAddress ip, uint16_t port) { return beginMulticast(ip, port); } + virtual void stop(); // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port); + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port); + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket(); + // Write a single byte into the packet + virtual size_t write(uint8_t); + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size); + + using Print::write; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket(); + // Number of bytes remaining in the current packet + virtual int available(); + // Read a single byte from the current packet + virtual int read(); + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len); + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek(); + virtual void flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP(); + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort(); + +}; + +#endif /* WIFIUDP_H */ diff --git a/lib/WiFi101/src/bsp/include/nm_bsp.h b/lib/WiFi101/src/bsp/include/nm_bsp.h new file mode 100644 index 0000000..5527bab --- /dev/null +++ b/lib/WiFi101/src/bsp/include/nm_bsp.h @@ -0,0 +1,283 @@ +/** + * + * \file + * + * \brief WINC BSP API Declarations. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +/** \defgroup nm_bsp BSP + */ +/**@defgroup BSPDefine Defines + * @ingroup nm_bsp + * @{ + */ +#ifndef _NM_BSP_H_ +#define _NM_BSP_H_ + +#define NMI_API +/*!< +* Attribute used to define memory section to map Functions in host memory. +*/ +#define CONST const + +/*!< +* Used for code portability. +*/ + +/*! + * @typedef void (*tpfNmBspIsr) (void); + * @brief Pointer to function.\n + * Used as a data type of ISR function registered by \ref nm_bsp_register_isr + * @return None + */ +typedef void (*tpfNmBspIsr)(void); + + + +#ifndef NULL +#define NULL ((void*)0) +#endif +/*!< +* Void Pointer to '0' in case of NULL is not defined. +*/ + + +#define BSP_MIN(x,y) ((x)>(y)?(y):(x)) +/*!< +* Computes the minimum of \b x and \b y. +*/ + + //@} + +/**@defgroup DataT DataTypes + * @ingroup nm_bsp + * @{ + */ + + /*! + * @ingroup DataTypes + * @typedef unsigned char uint8; + * @brief Range of values between 0 to 255 + */ +typedef unsigned char uint8; + + /*! + * @ingroup DataTypes + * @typedef unsigned short uint16; + * @brief Range of values between 0 to 65535 + */ +typedef unsigned short uint16; + + /*! + * @ingroup Data Types + * @typedef unsigned long uint32; + * @brief Range of values between 0 to 4294967295 + */ +typedef unsigned long uint32; + + + /*! + * @ingroup Data Types + * @typedef signed char sint8; + * @brief Range of values between -128 to 127 + */ +typedef signed char sint8; + + /*! + * @ingroup DataTypes + * @typedef signed short sint16; + * @brief Range of values between -32768 to 32767 + */ +typedef signed short sint16; + + /*! + * @ingroup DataTypes + * @typedef signed long sint32; + * @brief Range of values between -2147483648 to 2147483647 + */ + +typedef signed long sint32; + //@} + +#ifndef CORTUS_APP + + +#ifdef __cplusplus +extern "C"{ +#endif + +/** \defgroup BSPAPI Function + * @ingroup nm_bsp + */ + + +/** @defgroup NmBspInitFn nm_bsp_init + * @ingroup BSPAPI + * Initialization for BSP such as Reset and Chip Enable Pins for WINC, delays, register ISR, enable/disable IRQ for WINC, ...etc. You must use this function in the head of your application to + * enable WINC and Host Driver communicate each other. + */ + /**@{*/ +/*! + * @fn sint8 nm_bsp_init(void); + * @note Implementation of this function is host dependent. + * @warning Missing use will lead to unavailability of host communication.\n + * + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + + */ +sint8 nm_bsp_init(void); + /**@}*/ + + + /** @defgroup NmBspDeinitFn nm_bsp_deinit + * @ingroup BSPAPI + * De-initialization for BSP (\e Board \e Support \e Package) + */ + /**@{*/ +/*! + * @fn sint8 nm_bsp_deinit(void); + * @pre Initialize \ref nm_bsp_init first + * @note Implementation of this function is host dependent. + * @warning Missing use may lead to unknown behavior in case of soft reset.\n + * @see nm_bsp_init + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + + */ +sint8 nm_bsp_deinit(void); + /**@}*/ + + +/** @defgroup NmBspResetFn nm_bsp_reset +* @ingroup BSPAPI +* Resetting NMC1500 SoC by setting CHIP_EN and RESET_N signals low, then after specific delay the function will put CHIP_EN high then RESET_N high, +* for the timing between signals please review the WINC data-sheet +*/ +/**@{*/ + /*! + * @fn void nm_bsp_reset(void); + * @param [in] None + * @pre Initialize \ref nm_bsp_init first + * @note Implementation of this function is host dependent and called by HIF layer. + * @see nm_bsp_init + * @return None + + */ +void nm_bsp_reset(void); + /**@}*/ + + +/** @defgroup NmBspSleepFn nm_bsp_sleep +* @ingroup BSPAPI +* Sleep in units of milliseconds.\n +* This function used by HIF Layer according to different situations. +*/ +/**@{*/ +/*! + * @fn void nm_bsp_sleep(uint32); + * @brief + * @param [in] u32TimeMsec + * Time unit in milliseconds + * @pre Initialize \ref nm_bsp_init first + * @warning Maximum value must nor exceed 4294967295 milliseconds which is equal to 4294967.295 seconds.\n + * @note Implementation of this function is host dependent. + * @see nm_bsp_init + * @return None + */ +void nm_bsp_sleep(uint32 u32TimeMsec); +/**@}*/ + + +/** @defgroup NmBspRegisterFn nm_bsp_register_isr +* @ingroup BSPAPI +* Register ISR (Interrupt Service Routine) in the initialization of HIF (Host Interface) Layer. +* When the interrupt trigger the BSP layer should call the pfisr function once inside the interrupt. +*/ +/**@{*/ +/*! + * @fn void nm_bsp_register_isr(tpfNmBspIsr); + * @param [in] tpfNmBspIsr pfIsr + * Pointer to ISR handler in HIF + * @warning Make sure that ISR for IRQ pin for WINC is disabled by default in your implementation. + * @note Implementation of this function is host dependent and called by HIF layer. + * @see tpfNmBspIsr + * @return None + + */ +void nm_bsp_register_isr(tpfNmBspIsr pfIsr); +/**@}*/ + + +/** @defgroup NmBspInterruptCtrl nm_bsp_interrupt_ctrl +* @ingroup BSPAPI +* Synchronous enable/disable interrupts function +*/ +/**@{*/ +/*! + * @fn void nm_bsp_interrupt_ctrl(uint8); + * @brief Enable/Disable interrupts + * @param [in] u8Enable + * '0' disable interrupts. '1' enable interrupts + * @see tpfNmBspIsr + * @note Implementation of this function is host dependent and called by HIF layer. + * @return None + + */ +void nm_bsp_interrupt_ctrl(uint8 u8Enable); + /**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif + +#ifdef _NM_BSP_BIG_END +#define NM_BSP_B_L_32(x) \ +((((x) & 0x000000FF) << 24) + \ +(((x) & 0x0000FF00) << 8) + \ +(((x) & 0x00FF0000) >> 8) + \ +(((x) & 0xFF000000) >> 24)) +#define NM_BSP_B_L_16(x) \ +((((x) & 0x00FF) << 8) + \ +(((x) & 0xFF00) >> 8)) +#else +#define NM_BSP_B_L_32(x) (x) +#define NM_BSP_B_L_16(x) (x) +#endif + + +#endif /*_NM_BSP_H_*/ diff --git a/lib/WiFi101/src/bsp/include/nm_bsp_arduino.h b/lib/WiFi101/src/bsp/include/nm_bsp_arduino.h new file mode 100644 index 0000000..77417e8 --- /dev/null +++ b/lib/WiFi101/src/bsp/include/nm_bsp_arduino.h @@ -0,0 +1,74 @@ +/** + * + * \file + * + * \brief This module contains NMC1500 BSP APIs definitions. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _NM_BSP_ARDUINO_H_ +#define _NM_BSP_ARDUINO_H_ + +#include + +#include + +/* + * Arduino variants may redefine those pins. + * If no pins are specified the following defaults are used: + * WINC1501_RESET_PIN - pin 5 + * WINC1501_INTN_PIN - pin 7 + * WINC1501_CHIP_EN_PIN - not connected (tied to VCC) + */ +#if !defined(WINC1501_RESET_PIN) + #define WINC1501_RESET_PIN 5 +#endif +#if !defined(WINC1501_INTN_PIN) + #define WINC1501_INTN_PIN 7 +#endif +#if !defined(WINC1501_SPI_CS_PIN) + #define WINC1501_SPI_CS_PIN 10 +#endif +#if !defined(WINC1501_CHIP_EN_PIN) + #define WINC1501_CHIP_EN_PIN -1 +#endif + +extern int8_t gi8Winc1501CsPin; +extern int8_t gi8Winc1501ResetPin; +extern int8_t gi8Winc1501IntnPin; +extern int8_t gi8Winc1501ChipEnPin; + +#endif /* _NM_BSP_ARDUINO_H_ */ diff --git a/lib/WiFi101/src/bsp/include/nm_bsp_avr.h b/lib/WiFi101/src/bsp/include/nm_bsp_avr.h new file mode 100644 index 0000000..c5991f2 --- /dev/null +++ b/lib/WiFi101/src/bsp/include/nm_bsp_avr.h @@ -0,0 +1,54 @@ +/** + * + * \file + * + * \brief This module contains NMC1500 BSP APIs definitions. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _NM_BSP_AVR_H_ +#define _NM_BSP_AVR_H_ + +#pragma once + +#define NM_DEBUG 0 +#define NM_BSP_PRINTF + +#define CONF_WINC_USE_SPI 1 + +#define NM_EDGE_INTERRUPT 1 + +#endif /* _NM_BSP_AVR_H_ */ diff --git a/lib/WiFi101/src/bsp/include/nm_bsp_internal.h b/lib/WiFi101/src/bsp/include/nm_bsp_internal.h new file mode 100644 index 0000000..5117a1d --- /dev/null +++ b/lib/WiFi101/src/bsp/include/nm_bsp_internal.h @@ -0,0 +1,59 @@ +/** + * + * \file + * + * \brief This module contains NMC1500 BSP APIs declarations. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +/**@defgroup BSPDefine Defines + * @ingroup nm_bsp + * @{ + */ +#ifndef _NM_BSP_INTERNAL_H_ +#define _NM_BSP_INTERNAL_H_ + +#ifdef ARDUINO_ARCH_AVR +#define LIMITED_RAM_DEVICE +#include "bsp/include/nm_bsp_avr.h" +#else +#include "bsp/include/nm_bsp_samd21.h" +#endif + +#if defined(ARDUINO) && !defined(ARDUINO_SAMD_MKR1000) +#define CONF_PERIPH +#endif + +#endif //_NM_BSP_INTERNAL_H_ \ No newline at end of file diff --git a/lib/WiFi101/src/bsp/include/nm_bsp_samd21.h b/lib/WiFi101/src/bsp/include/nm_bsp_samd21.h new file mode 100644 index 0000000..296cd20 --- /dev/null +++ b/lib/WiFi101/src/bsp/include/nm_bsp_samd21.h @@ -0,0 +1,52 @@ +/** + * + * \file + * + * \brief This module contains NMC1500 BSP APIs definitions. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _NM_BSP_SAMD21_H_ +#define _NM_BSP_SAMD21_H_ + +#define NM_DEBUG 0 +#define NM_BSP_PRINTF + +#define CONF_WINC_USE_SPI 1 + +#define NM_EDGE_INTERRUPT 1 + +#endif /* _NM_BSP_SAMD21_H_ */ diff --git a/lib/WiFi101/src/bsp/source/nm_bsp_arduino.c b/lib/WiFi101/src/bsp/source/nm_bsp_arduino.c new file mode 100644 index 0000000..b10674b --- /dev/null +++ b/lib/WiFi101/src/bsp/source/nm_bsp_arduino.c @@ -0,0 +1,214 @@ +/** + * + * \file + * + * \brief This module contains SAMD21 BSP APIs implementation. + * + * Copyright (c) 2014 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include "bsp/include/nm_bsp.h" +#include "bsp/include/nm_bsp_arduino.h" +#include "common/include/nm_common.h" + +int8_t gi8Winc1501CsPin = WINC1501_SPI_CS_PIN; +int8_t gi8Winc1501ResetPin = WINC1501_RESET_PIN; +int8_t gi8Winc1501IntnPin = WINC1501_INTN_PIN; +int8_t gi8Winc1501ChipEnPin = WINC1501_CHIP_EN_PIN; + +static tpfNmBspIsr gpfIsr; + +void __attribute__((weak)) attachInterruptMultiArch(uint32_t pin, void *chip_isr, uint32_t mode) +{ + attachInterrupt(pin, chip_isr, mode); +} + +void __attribute__((weak)) detachInterruptMultiArch(uint32_t pin) +{ + detachInterrupt(pin); +} + +static void chip_isr(void) +{ + if (gpfIsr) { + gpfIsr(); + } +} + +/* + * @fn init_chip_pins + * @brief Initialize reset, chip enable and wake pin + * @author M.S.M + * @date 11 July 2012 + * @version 1.0 + */ +static void init_chip_pins(void) +{ + if (gi8Winc1501ResetPin > -1) + { + /* Configure RESETN pin as output. */ + pinMode(gi8Winc1501ResetPin, OUTPUT); + digitalWrite(gi8Winc1501ResetPin, HIGH); + } + + /* Configure INTN pins as input. */ + pinMode(gi8Winc1501IntnPin, INPUT); + + if (gi8Winc1501ChipEnPin > -1) + { + /* Configure CHIP_EN as pull-up */ + pinMode(gi8Winc1501ChipEnPin, INPUT_PULLUP); + } +} + +static void deinit_chip_pins(void) +{ + if (gi8Winc1501ResetPin > -1) + { + digitalWrite(gi8Winc1501ResetPin, LOW); + pinMode(gi8Winc1501ResetPin, INPUT); + } + + if (gi8Winc1501ChipEnPin > -1) + { + pinMode(gi8Winc1501ChipEnPin, INPUT); + } +} + +/* + * @fn nm_bsp_init + * @brief Initialize BSP + * @return 0 in case of success and -1 in case of failure + * @author M.S.M + * @date 11 July 2012 + * @version 1.0 + */ +sint8 nm_bsp_init(void) +{ + gpfIsr = NULL; + + init_chip_pins(); + + nm_bsp_reset(); + + return M2M_SUCCESS; +} + +/** + * @fn nm_bsp_deinit + * @brief De-iInitialize BSP + * @return 0 in case of success and -1 in case of failure + * @author M. Abdelmawla + * @date 11 July 2012 + * @version 1.0 + */ +sint8 nm_bsp_deinit(void) +{ + deinit_chip_pins(); + + return M2M_SUCCESS; +} + +/** + * @fn nm_bsp_reset + * @brief Reset NMC1500 SoC by setting CHIP_EN and RESET_N signals low, + * CHIP_EN high then RESET_N high + * @author M. Abdelmawla + * @date 11 July 2012 + * @version 1.0 + */ +void nm_bsp_reset(void) +{ + if (gi8Winc1501ResetPin > -1) + { + digitalWrite(gi8Winc1501ResetPin, LOW); + nm_bsp_sleep(100); + digitalWrite(gi8Winc1501ResetPin, HIGH); + nm_bsp_sleep(100); + } +} + +/* + * @fn nm_bsp_sleep + * @brief Sleep in units of mSec + * @param[IN] u32TimeMsec + * Time in milliseconds + * @author M.S.M + * @date 28 OCT 2013 + * @version 1.0 + */ +void nm_bsp_sleep(uint32 u32TimeMsec) +{ + while (u32TimeMsec--) { + delay(1); + } +} + +/* + * @fn nm_bsp_register_isr + * @brief Register interrupt service routine + * @param[IN] pfIsr + * Pointer to ISR handler + * @author M.S.M + * @date 28 OCT 2013 + * @sa tpfNmBspIsr + * @version 1.0 + */ +void nm_bsp_register_isr(tpfNmBspIsr pfIsr) +{ + gpfIsr = pfIsr; + attachInterruptMultiArch(gi8Winc1501IntnPin, chip_isr, FALLING); +} + +/* + * @fn nm_bsp_interrupt_ctrl + * @brief Enable/Disable interrupts + * @param[IN] u8Enable + * '0' disable interrupts. '1' enable interrupts + * @author M.S.M + * @date 28 OCT 2013 + * @version 1.0 + */ +void nm_bsp_interrupt_ctrl(uint8 u8Enable) +{ + if (u8Enable) { + attachInterruptMultiArch(gi8Winc1501IntnPin, chip_isr, FALLING); + } else { + detachInterruptMultiArch(gi8Winc1501IntnPin); + } +} diff --git a/lib/WiFi101/src/bsp/source/nm_bsp_arduino_avr.c b/lib/WiFi101/src/bsp/source/nm_bsp_arduino_avr.c new file mode 100644 index 0000000..050d5d5 --- /dev/null +++ b/lib/WiFi101/src/bsp/source/nm_bsp_arduino_avr.c @@ -0,0 +1,164 @@ +/** + * + * \file + * + * \brief This module contains SAMD21 BSP APIs implementation. + * + * Copyright (c) 2014 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifdef ARDUINO_ARCH_AVR + +#include "bsp/include/nm_bsp.h" +#include "bsp/include/nm_bsp_arduino.h" +#include "common/include/nm_common.h" + +#define IS_MEGA (defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA2560)) + +static tpfNmBspIsr gpfIsr; + +volatile uint8_t *_receivePortRegister; +volatile uint8_t *_pcint_maskreg; +uint8_t _receiveBitMask; +volatile uint8_t prev_pin_read = 1; + +uint8_t rx_pin_read() +{ + return *_receivePortRegister & _receiveBitMask; +} + +#if !IS_MEGA + +#if defined(PCINT0_vect) +ISR(PCINT0_vect) +{ + if (!rx_pin_read() && gpfIsr) + { + gpfIsr(); + } +} +#endif + +#if defined(PCINT1_vect) +ISR(PCINT1_vect, ISR_ALIASOF(PCINT0_vect)); +#endif + +#if defined(PCINT2_vect) +ISR(PCINT2_vect, ISR_ALIASOF(PCINT0_vect)); +#endif + +#if defined(PCINT3_vect) +ISR(PCINT3_vect, ISR_ALIASOF(PCINT0_vect)); +#endif + +#endif // !IS_MEGA + +#if defined(TIMER4_OVF_vect) +ISR(TIMER4_OVF_vect) { + uint8_t curr_pin_read = rx_pin_read(); + if ((curr_pin_read != prev_pin_read) && !curr_pin_read && gpfIsr) + { + gpfIsr(); + } + prev_pin_read = curr_pin_read; +} + +// stategy 3 - start a timer and perform a sort of polling +void attachFakeInterruptToTimer(void) { + TCCR4B = (1< I2C/UART. Parameter:tstrNmI2cDefault/tstrNmUartDefault */ +#define NM_BUS_IOCTL_W ((uint8)1) /*!< Write only ==> I2C/UART. Parameter type tstrNmI2cDefault/tstrNmUartDefault*/ +#define NM_BUS_IOCTL_W_SPECIAL ((uint8)2) /*!< Write two buffers within the same transaction + (same start/stop conditions) ==> I2C only. Parameter:tstrNmI2cSpecial */ +#define NM_BUS_IOCTL_RW ((uint8)3) /*!< Read/Write at the same time ==> SPI only. Parameter:tstrNmSpiRw */ + +#define NM_BUS_IOCTL_WR_RESTART ((uint8)4) /*!< Write buffer then made restart condition then read ==> I2C only. parameter:tstrNmI2cSpecial */ +/** +* @struct tstrNmBusCapabilities +* @brief Structure holding bus capabilities information +* @sa NM_BUS_TYPE_I2C, NM_BUS_TYPE_SPI +*/ +typedef struct +{ + uint16 u16MaxTrxSz; /*!< Maximum transfer size. Must be >= 16 bytes*/ +} tstrNmBusCapabilities; + +/** +* @struct tstrNmI2cDefault +* @brief Structure holding I2C default operation parameters +* @sa NM_BUS_IOCTL_R, NM_BUS_IOCTL_W +*/ +typedef struct +{ + uint8 u8SlaveAdr; + uint8 *pu8Buf; /*!< Operation buffer */ + uint16 u16Sz; /*!< Operation size */ +} tstrNmI2cDefault; + +/** +* @struct tstrNmI2cSpecial +* @brief Structure holding I2C special operation parameters +* @sa NM_BUS_IOCTL_W_SPECIAL +*/ +typedef struct +{ + uint8 u8SlaveAdr; + uint8 *pu8Buf1; /*!< pointer to the 1st buffer */ + uint8 *pu8Buf2; /*!< pointer to the 2nd buffer */ + uint16 u16Sz1; /*!< 1st buffer size */ + uint16 u16Sz2; /*!< 2nd buffer size */ +} tstrNmI2cSpecial; + +/** +* @struct tstrNmSpiRw +* @brief Structure holding SPI R/W parameters +* @sa NM_BUS_IOCTL_RW +*/ +typedef struct +{ + uint8 *pu8InBuf; /*!< pointer to input buffer. + Can be set to null and in this case zeros should be sent at MOSI */ + uint8 *pu8OutBuf; /*!< pointer to output buffer. + Can be set to null and in this case data from MISO can be ignored */ + uint16 u16Sz; /*!< Transfere size */ +} tstrNmSpiRw; + + +/** +* @struct tstrNmUartDefault +* @brief Structure holding UART default operation parameters +* @sa NM_BUS_IOCTL_R, NM_BUS_IOCTL_W +*/ +typedef struct +{ + uint8 *pu8Buf; /*!< Operation buffer */ + uint16 u16Sz; /*!< Operation size */ +} tstrNmUartDefault; +/*!< Bus capabilities. This structure must be declared at platform specific bus wrapper */ +extern tstrNmBusCapabilities egstrNmBusCapabilities; + + +#ifdef __cplusplus + extern "C" { + #endif +/** +* @fn nm_bus_init +* @brief Initialize the bus wrapper +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_bus_init(void *); + +/** +* @fn nm_bus_ioctl +* @brief send/receive from the bus +* @param [in] u8Cmd +* IOCTL command for the operation +* @param [in] pvParameter +* Arbitrary parameter depending on IOCTL +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +* @note For SPI only, it's important to be able to send/receive at the same time +*/ +sint8 nm_bus_ioctl(uint8 u8Cmd, void* pvParameter); + +/** +* @fn nm_bus_deinit +* @brief De-initialize the bus wrapper +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_bus_deinit(void); + +/* +* @fn nm_bus_reinit +* @brief re-initialize the bus wrapper +* @param [in] void *config +* re-init configuration data +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_bus_reinit(void *); +/* +* @fn nm_bus_get_chip_type +* @brief get chip type +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +#ifdef CONF_WINC_USE_UART +uint8 nm_bus_get_chip_type(void); +#endif +#ifdef __cplusplus + } + #endif + +#endif /*_NM_BUS_WRAPPER_H_*/ diff --git a/lib/WiFi101/src/bus_wrapper/source/nm_bus_wrapper_samd21.cpp b/lib/WiFi101/src/bus_wrapper/source/nm_bus_wrapper_samd21.cpp new file mode 100644 index 0000000..22a7473 --- /dev/null +++ b/lib/WiFi101/src/bus_wrapper/source/nm_bus_wrapper_samd21.cpp @@ -0,0 +1,200 @@ +/** + * + * \file + * + * \brief This module contains NMC1000 bus wrapper APIs implementation. + * + * Copyright (c) 2014 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include +#include + +/* + * Variants may define an alternative SPI instace to use for WiFi101. + * If not defined the following defaults are used: + * WINC1501_SPI - SPI + */ +#if !defined(WINC1501_SPI) + #define WINC1501_SPI SPI +#endif + +extern "C" { + +#include "bsp/include/nm_bsp.h" +#include "bsp/include/nm_bsp_arduino.h" +#include "common/include/nm_common.h" +#include "bus_wrapper/include/nm_bus_wrapper.h" + +} + +#define NM_BUS_MAX_TRX_SZ 256 + +tstrNmBusCapabilities egstrNmBusCapabilities = +{ + NM_BUS_MAX_TRX_SZ +}; + +static const SPISettings wifi_SPISettings(12000000L, MSBFIRST, SPI_MODE0); + +static sint8 spi_rw(uint8* pu8Mosi, uint8* pu8Miso, uint16 u16Sz) +{ + uint8 u8Dummy = 0; + uint8 u8SkipMosi = 0, u8SkipMiso = 0; + + if (!pu8Mosi) { + pu8Mosi = &u8Dummy; + u8SkipMosi = 1; + } + else if(!pu8Miso) { + pu8Miso = &u8Dummy; + u8SkipMiso = 1; + } + else { + return M2M_ERR_BUS_FAIL; + } + + WINC1501_SPI.beginTransaction(wifi_SPISettings); + digitalWrite(gi8Winc1501CsPin, LOW); + + while (u16Sz) { + *pu8Miso = WINC1501_SPI.transfer(*pu8Mosi); + + u16Sz--; + if (!u8SkipMiso) + pu8Miso++; + if (!u8SkipMosi) + pu8Mosi++; + } + + digitalWrite(gi8Winc1501CsPin, HIGH); + WINC1501_SPI.endTransaction(); + + return M2M_SUCCESS; +} + +extern "C" { + +/* +* @fn nm_bus_init +* @brief Initialize the bus wrapper +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M.S.M +* @date 28 oct 2013 +* @version 1.0 +*/ +sint8 nm_bus_init(void * /* pvInitValue */) +{ + sint8 result = M2M_SUCCESS; + + /* Configure SPI peripheral. */ + WINC1501_SPI.begin(); + + /* Configure CS PIN. */ + pinMode(gi8Winc1501CsPin, OUTPUT); + digitalWrite(gi8Winc1501CsPin, HIGH); + + /* Reset WINC1500. */ + nm_bsp_reset(); + nm_bsp_sleep(1); + + return result; +} + +/* +* @fn nm_bus_ioctl +* @brief send/receive from the bus +* @param[IN] u8Cmd +* IOCTL command for the operation +* @param[IN] pvParameter +* Arbitrary parameter depenging on IOCTL +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M.S.M +* @date 28 oct 2013 +* @note For SPI only, it's important to be able to send/receive at the same time +* @version 1.0 +*/ +sint8 nm_bus_ioctl(uint8 u8Cmd, void* pvParameter) +{ + sint8 s8Ret = 0; + switch(u8Cmd) + { + case NM_BUS_IOCTL_RW: { + tstrNmSpiRw *pstrParam = (tstrNmSpiRw *)pvParameter; + s8Ret = spi_rw(pstrParam->pu8InBuf, pstrParam->pu8OutBuf, pstrParam->u16Sz); + } + break; + default: + s8Ret = -1; + M2M_ERR("invalide ioclt cmd\n"); + break; + } + + return s8Ret; +} + +/* +* @fn nm_bus_deinit +* @brief De-initialize the bus wrapper +* @author M.S.M +* @date 28 oct 2013 +* @version 1.0 +*/ +sint8 nm_bus_deinit(void) +{ + WINC1501_SPI.end(); + return 0; +} + +/* +* @fn nm_bus_reinit +* @brief re-initialize the bus wrapper +* @param [in] void *config +* re-init configuration data +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author Dina El Sissy +* @date 19 Sept 2012 +* @version 1.0 +*/ +sint8 nm_bus_reinit(void* /* config */) +{ + return M2M_SUCCESS; +} + +} // extern "C" + diff --git a/lib/WiFi101/src/common/include/nm_common.h b/lib/WiFi101/src/common/include/nm_common.h new file mode 100644 index 0000000..d66fbdb --- /dev/null +++ b/lib/WiFi101/src/common/include/nm_common.h @@ -0,0 +1,153 @@ +/** + * + * \file + * + * \brief WINC Driver Common API Declarations. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _NM_COMMON_H_ +#define _NM_COMMON_H_ + +#include "bsp/include/nm_bsp.h" +#include "common/include/nm_debug.h" + +/**@defgroup CommonDefines CommonDefines + * @ingroup WlanDefines + */ +/**@{*/ +#define M2M_TIME_OUT_DELAY 10000 + +/*states*/ +#define M2M_SUCCESS ((sint8)0) +#define M2M_ERR_SEND ((sint8)-1) +#define M2M_ERR_RCV ((sint8)-2) +#define M2M_ERR_MEM_ALLOC ((sint8)-3) +#define M2M_ERR_TIME_OUT ((sint8)-4) +#define M2M_ERR_INIT ((sint8)-5) +#define M2M_ERR_BUS_FAIL ((sint8)-6) +#define M2M_NOT_YET ((sint8)-7) +#define M2M_ERR_FIRMWARE ((sint8)-8) +#define M2M_SPI_FAIL ((sint8)-9) +#define M2M_ERR_FIRMWARE_bURN ((sint8)-10) +#define M2M_ACK ((sint8)-11) +#define M2M_ERR_FAIL ((sint8)-12) +#define M2M_ERR_FW_VER_MISMATCH ((sint8)-13) +#define M2M_ERR_SCAN_IN_PROGRESS ((sint8)-14) +#define M2M_ERR_INVALID_ARG ((sint8)-15) +#define M2M_ERR_INVALID ((sint8)-16) + +/*i2c MAASTER ERR*/ +#define I2C_ERR_LARGE_ADDRESS 0xE1UL /*the address exceed the max addressing mode in i2c flash*/ +#define I2C_ERR_TX_ABRT 0xE2UL /*NO ACK from slave*/ +#define I2C_ERR_OVER_SIZE 0xE3UL /**/ +#define ERR_PREFIX_NMIS 0xE4UL /*wrong first four byte in flash NMIS*/ +#define ERR_FIRMEWARE_EXCEED_SIZE 0xE5UL /*Total size of firmware exceed the max size 256k*/ +/**/ +#define PROGRAM_START 0x26961735UL +#define BOOT_SUCCESS 0x10add09eUL +#define BOOT_START 0x12345678UL + + +#define NBIT31 (0x80000000) +#define NBIT30 (0x40000000) +#define NBIT29 (0x20000000) +#define NBIT28 (0x10000000) +#define NBIT27 (0x08000000) +#define NBIT26 (0x04000000) +#define NBIT25 (0x02000000) +#define NBIT24 (0x01000000) +#define NBIT23 (0x00800000) +#define NBIT22 (0x00400000) +#define NBIT21 (0x00200000) +#define NBIT20 (0x00100000) +#define NBIT19 (0x00080000) +#define NBIT18 (0x00040000) +#define NBIT17 (0x00020000) +#define NBIT16 (0x00010000) +#define NBIT15 (0x00008000) +#define NBIT14 (0x00004000) +#define NBIT13 (0x00002000) +#define NBIT12 (0x00001000) +#define NBIT11 (0x00000800) +#define NBIT10 (0x00000400) +#define NBIT9 (0x00000200) +#define NBIT8 (0x00000100) +#define NBIT7 (0x00000080) +#define NBIT6 (0x00000040) +#define NBIT5 (0x00000020) +#define NBIT4 (0x00000010) +#define NBIT3 (0x00000008) +#define NBIT2 (0x00000004) +#define NBIT1 (0x00000002) +#define NBIT0 (0x00000001) + +#define M2M_MAX(A,B) ((A) > (B) ? (A) : (B)) +#define M2M_SEL(x,m1,m2,m3) ((x>1)?((x>2)?(m3):(m2)):(m1)) +#define WORD_ALIGN(val) (((val) & 0x03) ? ((val) + 4 - ((val) & 0x03)) : (val)) + + + +#define DATA_PKT_OFFSET 4 + +#ifndef BIG_ENDIAN +#define BYTE_0(word) ((uint8)(((word) >> 0 ) & 0x000000FFUL)) +#define BYTE_1(word) ((uint8)(((word) >> 8 ) & 0x000000FFUL)) +#define BYTE_2(word) ((uint8)(((word) >> 16) & 0x000000FFUL)) +#define BYTE_3(word) ((uint8)(((word) >> 24) & 0x000000FFUL)) +#else +#define BYTE_0(word) ((uint8)(((word) >> 24) & 0x000000FFUL)) +#define BYTE_1(word) ((uint8)(((word) >> 16) & 0x000000FFUL)) +#define BYTE_2(word) ((uint8)(((word) >> 8 ) & 0x000000FFUL)) +#define BYTE_3(word) ((uint8)(((word) >> 0 ) & 0x000000FFUL)) +#endif + +/**@}*/ +#ifdef __cplusplus + extern "C" { + #endif +NMI_API void m2m_memcpy(uint8* pDst,uint8* pSrc,uint32 sz); +NMI_API void m2m_memset(uint8* pBuf,uint8 val,uint32 sz); +NMI_API uint16 m2m_strlen(uint8 * pcStr); +NMI_API sint8 m2m_memcmp(uint8 *pu8Buff1,uint8 *pu8Buff2 ,uint32 u32Size); +NMI_API uint8 m2m_strncmp(uint8 *pcS1, uint8 *pcS2, uint16 u16Len); +NMI_API uint8 * m2m_strstr(uint8 *pcIn, uint8 *pcStr); +NMI_API uint8 m2m_checksum(uint8* buf, int sz); + +#ifdef __cplusplus +} + #endif +#endif /*_NM_COMMON_H_*/ diff --git a/lib/WiFi101/src/common/include/nm_debug.h b/lib/WiFi101/src/common/include/nm_debug.h new file mode 100644 index 0000000..a710f6c --- /dev/null +++ b/lib/WiFi101/src/common/include/nm_debug.h @@ -0,0 +1,95 @@ +/** + * + * \file + * + * \brief This module contains debug APIs declarations. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _NM_DEBUG_H_ +#define _NM_DEBUG_H_ + +#include "bsp/include/nm_bsp.h" +#include "bsp/include/nm_bsp_internal.h" + +/**@defgroup DebugDefines DebugDefines + * @ingroup WlanDefines + */ +/**@{*/ + + +#define M2M_LOG_NONE 0 +#define M2M_LOG_ERROR 1 +#define M2M_LOG_INFO 2 +#define M2M_LOG_REQ 3 +#define M2M_LOG_DBG 4 + +#if (defined __APS3_CORTUS__) +#define M2M_LOG_LEVEL M2M_LOG_INFO +#else +#define M2M_LOG_LEVEL M2M_LOG_REQ +#endif + + +#define M2M_ERR(...) +#define M2M_INFO(...) +#define M2M_REQ(...) +#define M2M_DBG(...) +#define M2M_PRINT(...) + +#if (CONF_WINC_DEBUG == 1) +#undef M2M_PRINT +#define M2M_PRINT(...) do{CONF_WINC_PRINTF(__VA_ARGS__);CONF_WINC_PRINTF("\r");}while(0) +#if (M2M_LOG_LEVEL >= M2M_LOG_ERROR) +#undef M2M_ERR +#define M2M_ERR(...) do{CONF_WINC_PRINTF("(APP)(ERR)[%s][%d]",__FUNCTION__,__LINE__); CONF_WINC_PRINTF(__VA_ARGS__);CONF_WINC_PRINTF("\r");}while(0) +#if (M2M_LOG_LEVEL >= M2M_LOG_INFO) +#undef M2M_INFO +#define M2M_INFO(...) do{CONF_WINC_PRINTF("(APP)(INFO)"); CONF_WINC_PRINTF(__VA_ARGS__);CONF_WINC_PRINTF("\r");}while(0) +#if (M2M_LOG_LEVEL >= M2M_LOG_REQ) +#undef M2M_REQ +#define M2M_REQ(...) do{CONF_WINC_PRINTF("(APP)(R)"); CONF_WINC_PRINTF(__VA_ARGS__);CONF_WINC_PRINTF("\r");}while(0) +#if (M2M_LOG_LEVEL >= M2M_LOG_DBG) +#undef M2M_DBG +#define M2M_DBG(...) do{CONF_WINC_PRINTF("(APP)(DBG)[%s][%d]",__FUNCTION__,__LINE__); CONF_WINC_PRINTF(__VA_ARGS__);CONF_WINC_PRINTF("\r");}while(0) +#endif /*M2M_LOG_DBG*/ +#endif /*M2M_LOG_REQ*/ +#endif /*M2M_LOG_INFO*/ +#endif /*M2M_LOG_ERROR*/ +#endif /*CONF_WINC_DEBUG */ + +/**@}*/ +#endif /* _NM_DEBUG_H_ */ diff --git a/lib/WiFi101/src/common/source/nm_common.c b/lib/WiFi101/src/common/source/nm_common.c new file mode 100644 index 0000000..8b3c941 --- /dev/null +++ b/lib/WiFi101/src/common/source/nm_common.c @@ -0,0 +1,136 @@ +/** + * + * \file + * + * \brief This module contains common APIs declarations. + * + * Copyright (c) 2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#include "common/include/nm_common.h" + +void m2m_memcpy(uint8* pDst,uint8* pSrc,uint32 sz) +{ + if(sz == 0) return; + do + { + *pDst = *pSrc; + pDst++; + pSrc++; + }while(--sz); +} +uint8 m2m_checksum(uint8* buf, int sz) +{ + uint8 cs = 0; + while(--sz) + { + cs ^= *buf; + buf++; + } + + return cs; +} + +void m2m_memset(uint8* pBuf,uint8 val,uint32 sz) +{ + if(sz == 0) return; + do + { + *pBuf = val; + pBuf++; + }while(--sz); +} + +uint16 m2m_strlen(uint8 * pcStr) +{ + uint16 u16StrLen = 0; + while(*pcStr) + { + u16StrLen ++; + pcStr++; + } + return u16StrLen; +} + +uint8 m2m_strncmp(uint8 *pcS1, uint8 *pcS2, uint16 u16Len) +{ + for ( ; u16Len > 0; pcS1++, pcS2++, --u16Len) + if (*pcS1 != *pcS2) + return ((*(uint8 *)pcS1 < *(uint8 *)pcS2) ? -1 : +1); + else if (*pcS1 == '\0') + return 0; + return 0; +} + +/* Finds the occurance of pcStr in pcIn. +If pcStr is part of pcIn it returns a valid pointer to the start of pcStr within pcIn. +Otherwise a NULL Pointer is returned. +*/ +uint8 * m2m_strstr(uint8 *pcIn, uint8 *pcStr) +{ + uint8 u8c; + uint16 u16StrLen; + + u8c = *pcStr++; + if (!u8c) + return (uint8 *) pcIn; // Trivial empty string case + + u16StrLen = m2m_strlen(pcStr); + do { + uint8 u8Sc; + + do { + u8Sc = *pcIn++; + if (!u8Sc) + return (uint8 *) 0; + } while (u8Sc != u8c); + } while (m2m_strncmp(pcIn, pcStr, u16StrLen) != 0); + + return (uint8 *) (pcIn - 1); +} + +sint8 m2m_memcmp(uint8 *pu8Buff1,uint8 *pu8Buff2 ,uint32 u32Size) +{ + uint32 i; + sint8 s8Result = 0; + for(i = 0 ; i < u32Size ; i++) + { + if(pu8Buff1[i] != pu8Buff2[i]) + { + s8Result = 1; + break; + } + } + return s8Result; +} diff --git a/lib/WiFi101/src/driver/include/ecc_types.h b/lib/WiFi101/src/driver/include/ecc_types.h new file mode 100644 index 0000000..764c3b9 --- /dev/null +++ b/lib/WiFi101/src/driver/include/ecc_types.h @@ -0,0 +1,245 @@ +/** + * + * \file + * + * \brief WINC Application Interface Internal Types. + * + * Copyright (c) 2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef __ECC_TYPES_H__ +#define __ECC_TYPES_H__ + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +#include "m2m_types.h" + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +MACROS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + + + +#define ECC_LARGEST_CURVE_SIZE (32) +/*!< + The size of the the largest supported EC. For now, assuming + the 256-bit EC is the largest supported curve type. +*/ + + +#define ECC_POINT_MAX_SIZE ECC_LARGEST_CURVE_SIZE +/*!< + Maximum size of one coordinate of an EC point. +*/ + + +#define ECC_POINT_MAX_SIZE_WORDS (ECC_POINT_MAX_SIZE / 4) +/*!< + SIZE in 32-bit words. +*/ + +#if 0 +#define ECC_NUM_SUPP_CURVES ((sizeof(gastrECCSuppList)) / (sizeof(tstrEllipticCurve))) +#endif +/*!< +*/ + + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +DATA TYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + + +/*! +@enum \ + tenuEcNamedCurve + +@brief EC Named Curves + + Defines a list of supported ECC named curves. +*/ +typedef enum EcNamedCurve{ + EC_SECP192R1 = 19, + /*!< + It is defined by NIST as P192 and by the SEC Group as secp192r1. + */ + EC_SECP256R1 = 23, + /*!< + It is defined by NIST as P256 and by the SEC Group as secp256r1. + */ + EC_SECP384R1 = 24, + /*!< + It is defined by NIST as P384 and by the SEC Group as secp384r1. + */ + EC_SECP521R1 = 25, + /*!< + It is defined by NIST as P521 and by the SEC Group as secp521r1. + */ + EC_UNKNOWN = 255 +}tenuEcNamedCurve; + + +/*! +@struct \ + tstrECPoint + +@brief Elliptic Curve point representation +*/ +typedef struct EcPoint{ + uint8 X[ECC_POINT_MAX_SIZE]; + /*!< + The X-coordinate of the ec point. + */ + uint8 Y[ECC_POINT_MAX_SIZE]; + /*!< + The Y-coordinate of the ec point. + */ + uint16 u16Size; + /*!< + Point size in bytes (for each of the coordinates). + */ + uint16 u16PrivKeyID; + /*!< + ID for the corresponding private key. + */ +}tstrECPoint; + + +/*! +@struct \ + tstrECDomainParam + +@brief ECC Curve Domain Parameters + + The structure defines the ECC domain parameters for curves defined over prime finite fields. +*/ +typedef struct EcDomainParam{ + uint32 p[ECC_POINT_MAX_SIZE_WORDS]; + uint32 a[ECC_POINT_MAX_SIZE_WORDS]; + uint32 b[ECC_POINT_MAX_SIZE_WORDS]; + tstrECPoint G; +}tstrECDomainParam; + + +/*! +@struct \ + tstrEllipticCurve + +@brief + Definition of an elliptic curve +*/ +typedef struct{ + tenuEcNamedCurve enuType; + tstrECDomainParam strParam; +}tstrEllipticCurve; + + +typedef enum{ + ECC_REQ_NONE, + ECC_REQ_CLIENT_ECDH, + ECC_REQ_SERVER_ECDH, + ECC_REQ_GEN_KEY, + ECC_REQ_SIGN_GEN, + ECC_REQ_SIGN_VERIFY +}tenuEccREQ; + + +typedef struct{ + tstrECPoint strPubKey; + uint8 au8Key[ECC_POINT_MAX_SIZE]; +}tstrEcdhReqInfo; + + +typedef struct{ + uint32 u32nSig; +}tstrEcdsaVerifyReqInfo; + + +typedef struct{ + uint16 u16CurveType; + uint16 u16HashSz; +}tstrEcdsaSignReqInfo; + + +typedef struct{ + uint16 u16REQ; + uint16 u16Status; + uint32 u32UserData; + uint32 u32SeqNo; + union{ + tstrEcdhReqInfo strEcdhREQ; + tstrEcdsaSignReqInfo strEcdsaSignREQ; + tstrEcdsaVerifyReqInfo strEcdsaVerifyREQ; + }; +}tstrEccReqInfo; + + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +GLOBALS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +#if 0 +static tstrEllipticCurve gastrECCSuppList[] = { + { + EC_SECP256R1, + { + {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF}, + {0xFFFFFFFC, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF}, + {0x27D2604B, 0x3BCE3C3E, 0xCC53B0F6, 0x651D06B0, 0x769886BC, 0xB3EBBD55, 0xAA3A93E7, 0x5AC635D8}, + { + { + 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5, 0x63, 0xA4, 0x40, 0xF2, + 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96 + }, + { + 0x4F, 0xE3, 0x42, 0xE2, 0xFE, 0x1A, 0x7F, 0x9B, 0x8E, 0xE7, 0xEB, 0x4A, 0x7C, 0x0F, 0x9E, 0x16, + 0x2B, 0xCE, 0x33, 0x57, 0x6B, 0x31, 0x5E, 0xCE, 0xCB, 0xB6, 0x40, 0x68, 0x37, 0xBF, 0x51, 0xF5 + }, + 32 + } + } + } +}; +#endif + +/*!< + List of supported Elliptic Curves ordered by security level (most secure curve is at index ZERO). +*/ + + + +#endif /* __ECC_TYPES_H__ */ diff --git a/lib/WiFi101/src/driver/include/m2m_ate_mode.h b/lib/WiFi101/src/driver/include/m2m_ate_mode.h new file mode 100644 index 0000000..a17d298 --- /dev/null +++ b/lib/WiFi101/src/driver/include/m2m_ate_mode.h @@ -0,0 +1,732 @@ +/** + * + * \file + * + * \brief WINC ATE Test Driver Interface. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifdef _M2M_ATE_FW_ + +#ifndef _M2M_ATE_MODE_H_ +#define _M2M_ATE_MODE_H_ + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +#include "common/include/nm_common.h" +#include "driver/include/m2m_types.h" + +/** \defgroup m2m_ate ATE +*/ +/**@defgroup ATEDefine Defines + * @ingroup m2m_ate + * @{ + */ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +MACROS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +#define M2M_ATE_MAX_NUM_OF_RATES (20) +/*!< +Maximum number of all rates (b,g and n) + */ +#define M2M_ATE_MAX_FRAME_LENGTH (1024) +/*!< Maximum number of length for each frame + */ +#define M2M_ATE_MIN_FRAME_LENGTH (1) +/*!< Minimum number of length for each frame + */ +#define M2M_ATE_SUCCESS (M2M_SUCCESS) +/*!< No Error and operation has been completed successfully. +*/ +#define M2M_ATE_ERR_VALIDATE (M2M_ERR_FAIL) +/*!< Error in parameters passed to functions. + */ +#define M2M_ATE_ERR_TX_ALREADY_RUNNING (-1) +/*!< Error in starting a transmission test. Another test is already running and its not allowed to start another ATE test. + */ +#define M2M_ATE_ERR_RX_ALREADY_RUNNING (-2) +/*!< Error in starting a reception test. Another test is already running and its not allowed to start another ATE test. + */ +#define M2M_ATE_ERR_UNHANDLED_CASE (-3) +/*!< Invalid case. + */ +#define M2M_ATE_RX_DISABLE_DA 0x0 +/*!< Filter selection for received frames: Disable filtering received frames by the destination address. + */ +#define M2M_ATE_RX_ENABLE_DA 0x1 +/*!< Filter selection for received frames: Enable filtering received frames by the destination address. + */ +#define M2M_ATE_RX_DISABLE_SA 0x0 +/*!< Filter selection for received frames: Disable filtering received frames by the source address. + */ +#define M2M_ATE_RX_ENABLE_SA 0x1 +/*!< Filter selection for received frames: Enable filtering received frames by the source address. + */ +#define M2M_ATE_DISABLE_SELF_MACADDR 0x0 +/*!\n",ret); + while(1); + } + //Initialize the OTA module + m2m_ota_init(OtaUpdateCb,NULL); + //connect to AP that provide connection to the OTA server + m2m_wifi_default_connect(); + + while(1) + { + + //Handle the app state machine plus the WINC event handler + while(m2m_wifi_handle_events(NULL) != M2M_SUCCESS) { + + } + + } +} +@endcode + +*/ +NMI_API sint8 m2m_ota_start_update(uint8 * u8DownloadUrl); + /**@}*/ +/** @defgroup OtaStartUpdatefn m2m_ota_start_update_crt +* @ingroup WLANAPI +* Request OTA start for cortus application image using the downloaded URL, the OTA module will download the OTA image and ensure integrity of the image, +* and update the validity of the image in control structure. Switching to that image requires calling @ref m2m_ota_switch_crt API. +* As a prerequisite @ref m2m_ota_init should be called before using @ref m2m_ota_start_update_crt(). +*/ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_ota_start_update_crt(uint8 * u8DownloadUrl); + +@param [in] u8DownloadUrl + The cortus application image url. +@warning + Calling this API does not guarantee cortus application image update, It depends on the connection with the download server and the validity of the image. + If the API response is failure this may invalidate the roll-back image if it was previously valid, since the WINC does not have any internal memory + except the flash roll-back image location to validate the downloaded image from + +@see + m2m_ota_init + tpfOtaUpdateCb + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_start_update_crt(uint8 * u8DownloadUrl); + /**@}*/ +/** @defgroup OtaRollbackfn m2m_ota_rollback +* @ingroup WLANAPI + Request OTA Roll-back to the old (other) WINC image, the WINC firmware will check the validation of the Roll-back image + and switch to it if it is valid. + If the API response is success, system restart is required (re-initialize the driver with hardware rest) update the host driver version may + be required if it is did not match the minimum version supported by the WINC firmware. + +*/ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_ota_rollback(void); + +@sa + m2m_ota_init + m2m_ota_start_update + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_rollback(void); + /**@}*/ +/** @defgroup OtaRollbackfn m2m_ota_rollback_crt +* @ingroup WLANAPI + Request Cortus application OTA Roll-back to the old (other) cortus application image, the WINC firmware will check the validation of the Roll-back image + and switch to it if it is valid. + If the API response is success, system restart is required (re-initialize the driver with hardware rest) update the host driver version may + be required. + +*/ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_ota_rollback_crt(void); + +@sa + m2m_ota_init + m2m_ota_start_update_crt + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_rollback_crt(void); + /**@}*/ +/** @defgroup OtaAbortfn m2m_ota_abort +* @ingroup WLANAPI + Request abort of current OTA download. + The WINC firmware will terminate the OTA download if one is in progress. + If no download is in progress, the API will respond with failure. +*/ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_ota_abort(void); + +@return + The function returns @ref M2M_SUCCESS for successful operation and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_abort(void); + /**@}*/ + /**@}*/ +/** @defgroup OtaSwitchFirmware m2m_ota_switch_firmware +* @ingroup WLANAPI +* Switch to the upgraded Firmware, that API will update the control structure working image to the upgraded image + take effect will be on the next system restart +*/ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_ota_switch_firmware(void); + +@warning + It is important to note that if the API succeeds, system restart is required (re-initializing the driver with hardware reset) updating the host driver version may be required + if it does not match the minimum driver version supported by the WINC's firmware. +@sa + m2m_ota_init + m2m_ota_start_update + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_switch_firmware(void); + /**@}*/ + /**@}*/ +/** @defgroup OtaSwitchFirmware m2m_ota_switch_crt +* @ingroup WLANAPI +* Switch to the upgraded cortus application, that API will update the control structure working image to the upgraded image + take effect will be on the next system restart +*/ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_ota_switch_firmware(void); + +@warning + It is important to note that if the API succeeds, system restart is required (re-initializing the driver with hardware reset) updating the host driver version may be required + if it does not match the minimum driver version supported by the WINC's firmware. +@sa + m2m_ota_init + m2m_ota_start_update_crt + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_switch_crt(void); +/*! +@fn \ + NMI_API sint8 m2m_ota_get_firmware_version(void); + +@brief + Get the OTA Firmware version. + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_get_firmware_version(tstrM2mRev *pstrRev); + /**@}*/ +NMI_API sint8 m2m_ota_test(void); + +#ifdef __cplusplus +} +#endif +#endif /* __M2M_OTA_H__ */ diff --git a/lib/WiFi101/src/driver/include/m2m_periph.h b/lib/WiFi101/src/driver/include/m2m_periph.h new file mode 100644 index 0000000..1012882 --- /dev/null +++ b/lib/WiFi101/src/driver/include/m2m_periph.h @@ -0,0 +1,411 @@ +/** + * + * \file + * + * \brief WINC Peripherals Application Interface. + * + * Copyright (c) 2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _M2M_PERIPH_H_ +#define _M2M_PERIPH_H_ + + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + + +#include "common/include/nm_common.h" +#include "driver/include/m2m_types.h" + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +MACROS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +DATA TYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*! +@struct \ + tstrPerphInitParam + +@brief + Peripheral module initialization parameters. +*/ +typedef struct { + void * arg; +} tstrPerphInitParam; + + +/*! +@enum \ + tenuGpioNum + +@brief + A list of GPIO numbers configurable through the m2m_periph module. +*/ +typedef enum { + M2M_PERIPH_GPIO3, /*!< GPIO15 pad */ + M2M_PERIPH_GPIO4, /*!< GPIO16 pad */ + M2M_PERIPH_GPIO5, /*!< GPIO18 pad */ + M2M_PERIPH_GPIO6, /*!< GPIO18 pad */ + M2M_PERIPH_GPIO15, /*!< GPIO15 pad */ + M2M_PERIPH_GPIO16, /*!< GPIO16 pad */ + M2M_PERIPH_GPIO18, /*!< GPIO18 pad */ + M2M_PERIPH_GPIO_MAX +} tenuGpioNum; + + +/*! +@enum \ + tenuI2cMasterSclMuxOpt + +@brief + Allowed pin multiplexing options for I2C master SCL signal. +*/ +typedef enum { + M2M_PERIPH_I2C_MASTER_SCL_MUX_OPT_HOST_WAKEUP, /*!< I2C master SCL is avaiable on HOST_WAKEUP. */ + M2M_PERIPH_I2C_MASTER_SCL_MUX_OPT_SD_DAT3, /*!< I2C master SCL is avaiable on SD_DAT3 (GPIO 7). */ + M2M_PERIPH_I2C_MASTER_SCL_MUX_OPT_GPIO13, /*!< I2C master SCL is avaiable on GPIO 13. */ + M2M_PERIPH_I2C_MASTER_SCL_MUX_OPT_GPIO4, /*!< I2C master SCL is avaiable on GPIO 4.*/ + M2M_PERIPH_I2C_MASTER_SCL_MUX_OPT_I2C_SCL, /*!< I2C master SCL is avaiable on I2C slave SCL. */ + M2M_PERIPH_I2C_MASTER_SCL_MUX_OPT_NUM +} tenuI2cMasterSclMuxOpt; + +/*! +@enum \ + tenuI2cMasterSdaMuxOpt + +@brief + Allowed pin multiplexing options for I2C master SDA signal. +*/ +typedef enum { + M2M_PERIPH_I2C_MASTER_SDA_MUX_OPT_RTC_CLK , /*!< I2C master SDA is avaiable on RTC_CLK. */ + M2M_PERIPH_I2C_MASTER_SDA_MUX_OPT_SD_CLK, /*!< I2C master SDA is avaiable on SD_CLK (GPIO 8). */ + M2M_PERIPH_I2C_MASTER_SDA_MUX_OPT_GPIO14, /*!< I2C master SDA is avaiable on GPIO 14. */ + M2M_PERIPH_I2C_MASTER_SDA_MUX_OPT_GPIO6, /*!< I2C master SDA is avaiable on GPIO 6.*/ + M2M_PERIPH_I2C_MASTER_SDA_MUX_OPT_I2C_SDA, /*!< I2C master SDA is avaiable on I2C slave SDA. */ + M2M_PERIPH_I2C_MASTER_SDA_MUX_OPT_NUM +} tenuI2cMasterSdaMuxOpt; + + +/*! +@struct \ + tstrI2cMasterInitParam + +@brief + I2C master configuration parameters. +@sa + tenuI2cMasterSclMuxOpt + tenuI2cMasterSdaMuxOpt +*/ +typedef struct { + uint8 enuSclMuxOpt; /*!< SCL multiplexing option. Allowed value are defined in tenuI2cMasterSclMuxOpt */ + uint8 enuSdaMuxOpt; /*!< SDA multiplexing option. Allowed value are defined in tenuI2cMasterSdaMuxOpt */ + uint8 u8ClkSpeedKHz; /*!< I2C master clock speed in KHz. */ +} tstrI2cMasterInitParam; + +/*! +@enum \ + tenuI2cMasterFlags + +@brief + Bitwise-ORed flags for use in m2m_periph_i2c_master_write and m2m_periph_i2c_master_read +@sa + m2m_periph_i2c_master_write + m2m_periph_i2c_master_read +*/ +typedef enum { + I2C_MASTER_NO_FLAGS = 0x00, + /*!< No flags. */ + I2C_MASTER_NO_STOP = 0x01, + /*!< No stop bit after this transaction. Useful for scattered buffer read/write operations. */ + I2C_MASTER_NO_START = 0x02, + /*!< No start bit at the beginning of this transaction. Useful for scattered buffer read/write operations.*/ +} tenuI2cMasterFlags; + +/*! +@enum \ + tenuPullupMask + +@brief + Bitwise-ORed flags for use in m2m_perph_pullup_ctrl. +@sa + m2m_periph_pullup_ctrl + +*/ +typedef enum { + M2M_PERIPH_PULLUP_DIS_HOST_WAKEUP = (1ul << 0), + M2M_PERIPH_PULLUP_DIS_RTC_CLK = (1ul << 1), + M2M_PERIPH_PULLUP_DIS_IRQN = (1ul << 2), + M2M_PERIPH_PULLUP_DIS_GPIO_3 = (1ul << 3), + M2M_PERIPH_PULLUP_DIS_GPIO_4 = (1ul << 4), + M2M_PERIPH_PULLUP_DIS_GPIO_5 = (1ul << 5), + M2M_PERIPH_PULLUP_DIS_SD_DAT3 = (1ul << 6), + M2M_PERIPH_PULLUP_DIS_SD_DAT2_SPI_RXD = (1ul << 7), + M2M_PERIPH_PULLUP_DIS_SD_DAT1_SPI_SSN = (1ul << 9), + M2M_PERIPH_PULLUP_DIS_SD_CMD_SPI_SCK = (1ul << 10), + M2M_PERIPH_PULLUP_DIS_SD_DAT0_SPI_TXD = (1ul << 11), + M2M_PERIPH_PULLUP_DIS_GPIO_6 = (1ul << 12), + M2M_PERIPH_PULLUP_DIS_SD_CLK = (1ul << 13), + M2M_PERIPH_PULLUP_DIS_I2C_SCL = (1ul << 14), + M2M_PERIPH_PULLUP_DIS_I2C_SDA = (1ul << 15), + M2M_PERIPH_PULLUP_DIS_GPIO_11 = (1ul << 16), + M2M_PERIPH_PULLUP_DIS_GPIO_12 = (1ul << 17), + M2M_PERIPH_PULLUP_DIS_GPIO_13 = (1ul << 18), + M2M_PERIPH_PULLUP_DIS_GPIO_14 = (1ul << 19), + M2M_PERIPH_PULLUP_DIS_GPIO_15 = (1ul << 20), + M2M_PERIPH_PULLUP_DIS_GPIO_16 = (1ul << 21), + M2M_PERIPH_PULLUP_DIS_GPIO_17 = (1ul << 22), + M2M_PERIPH_PULLUP_DIS_GPIO_18 = (1ul << 23), + M2M_PERIPH_PULLUP_DIS_GPIO_19 = (1ul << 24), + M2M_PERIPH_PULLUP_DIS_GPIO_20 = (1ul << 25), + M2M_PERIPH_PULLUP_DIS_GPIO_21 = (1ul << 26), + M2M_PERIPH_PULLUP_DIS_GPIO_22 = (1ul << 27), + M2M_PERIPH_PULLUP_DIS_GPIO_23 = (1ul << 28), + M2M_PERIPH_PULLUP_DIS_GPIO_24 = (1ul << 29), +} tenuPullupMask; + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +FUNCTION PROTOTYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + + +#ifdef __cplusplus + extern "C" { +#endif + +/*! +@fn \ + NMI_API sint8 m2m_periph_init(tstrPerphInitParam * param); + +@brief + Initialize the NMC1500 peripheral driver module. + +@param [in] param + Peripheral module initialization structure. See members of tstrPerphInitParam. + +@return + The function SHALL return 0 for success and a negative value otherwise. + +@sa + tstrPerphInitParam +*/ +NMI_API sint8 m2m_periph_init(tstrPerphInitParam * param); + +/*! +@fn \ + NMI_API sint8 m2m_periph_gpio_set_dir(uint8 u8GpioNum, uint8 u8GpioDir); + +@brief + Configure a specific NMC1500 pad as a GPIO and sets its direction (input or output). + +@param [in] u8GpioNum + GPIO number. Allowed values are defined in tenuGpioNum. + +@param [in] u8GpioDir + GPIO direction: Zero = input. Non-zero = output. + +@return + The function SHALL return 0 for success and a negative value otherwise. + +@sa + tenuGpioNum +*/ +NMI_API sint8 m2m_periph_gpio_set_dir(uint8 u8GpioNum, uint8 u8GpioDir); + +/*! +@fn \ + NMI_API sint8 m2m_periph_gpio_set_val(uint8 u8GpioNum, uint8 u8GpioVal); + +@brief + Set an NMC1500 GPIO output level high or low. + +@param [in] u8GpioNum + GPIO number. Allowed values are defined in tenuGpioNum. + +@param [in] u8GpioVal + GPIO output value. Zero = low, non-zero = high. + +@return + The function SHALL return 0 for success and a negative value otherwise. + +@sa + tenuGpioNum +*/ +NMI_API sint8 m2m_periph_gpio_set_val(uint8 u8GpioNum, uint8 u8GpioVal); + +/*! +@fn \ + NMI_API sint8 m2m_periph_gpio_get_val(uint8 u8GpioNum, uint8 * pu8GpioVal); + +@brief + Read an NMC1500 GPIO input level. + +@param [in] u8GpioNum + GPIO number. Allowed values are defined in tenuGpioNum. + +@param [out] pu8GpioVal + GPIO input value. Zero = low, non-zero = high. + +@return + The function SHALL return 0 for success and a negative value otherwise. + +@sa + tenuGpioNum +*/ +NMI_API sint8 m2m_periph_gpio_get_val(uint8 u8GpioNum, uint8 * pu8GpioVal); + +/*! +@fn \ + NMI_API sint8 m2m_periph_gpio_pullup_ctrl(uint8 u8GpioNum, uint8 u8PullupEn); + +@brief + Set an NMC1500 GPIO pullup resisitor enable or disable. + +@param [in] u8GpioNum + GPIO number. Allowed values are defined in tenuGpioNum. + +@param [in] u8PullupEn + Zero: pullup disabled. Non-zero: pullup enabled. + +@return + The function SHALL return 0 for success and a negative value otherwise. + +@sa + tenuGpioNum +*/ +NMI_API sint8 m2m_periph_gpio_pullup_ctrl(uint8 u8GpioNum, uint8 u8PullupEn); + +/*! +@fn \ + NMI_API sint8 m2m_periph_i2c_master_init(tstrI2cMasterInitParam * param); + +@brief + Initialize and configure the NMC1500 I2C master peripheral. + +@param [in] param + I2C master initialization structure. See members of tstrI2cMasterInitParam. + +@return + The function SHALL return 0 for success and a negative value otherwise. + +@sa + tstrI2cMasterInitParam +*/ +NMI_API sint8 m2m_periph_i2c_master_init(tstrI2cMasterInitParam * param); + +/*! +@fn \ + NMI_API sint8 m2m_periph_i2c_master_write(uint8 u8SlaveAddr, uint8 * pu8Buf, uint16 u16BufLen, uint8 flags); + +@brief + Write a stream of bytes to the I2C slave device. + +@param [in] u8SlaveAddr + 7-bit I2C slave address. +@param [in] pu8Buf + A pointer to an input buffer which contains a stream of bytes. +@param [in] u16BufLen + Input buffer length in bytes. +@param [in] flags + Write operation bitwise-ORed flags. See tenuI2cMasterFlags. + +@return + The function SHALL return 0 for success and a negative value otherwise. + +@sa + tenuI2cMasterFlags +*/ +NMI_API sint8 m2m_periph_i2c_master_write(uint8 u8SlaveAddr, uint8 * pu8Buf, uint16 u16BufLen, uint8 flags); + + +/*! +@fn \ + NMI_API sint8 m2m_periph_i2c_master_read(uint8 u8SlaveAddr, uint8 * pu8Buf, uint16 u16BufLen, uint16 * pu16ReadLen, uint8 flags); + +@brief + Write a stream of bytes to the I2C slave device. + +@param [in] u8SlaveAddr + 7-bit I2C slave address. +@param [out] pu8Buf + A pointer to an output buffer in which a stream of bytes are received. +@param [in] u16BufLen + Max output buffer length in bytes. +@param [out] pu16ReadLen + Actual number of bytes received. +@param [in] flags + Write operation bitwise-ORed flags. See tenuI2cMasterFlags. + +@return + The function SHALL return 0 for success and a negative value otherwise. + +@sa + tenuI2cMasterFlags +*/ +NMI_API sint8 m2m_periph_i2c_master_read(uint8 u8SlaveAddr, uint8 * pu8Buf, uint16 u16BufLen, uint16 * pu16ReadLen, uint8 flags); + + +/*! +@fn \ + NMI_API sint8 m2m_periph_pullup_ctrl(uint32 pinmask, uint8 enable); + +@brief + Control the programmable pull-up resistor on the chip pads . + + +@param [in] pinmask + Write operation bitwise-ORed mask for which pads to control. Allowed values are defined in tenuPullupMask. + +@param [in] enable + Set to 0 to disable pull-up resistor. Non-zero will enable the pull-up. + +@return + The function SHALL return 0 for success and a negative value otherwise. + +@sa + tenuPullupMask +*/ +NMI_API sint8 m2m_periph_pullup_ctrl(uint32 pinmask, uint8 enable); + +#ifdef __cplusplus +} +#endif + + +#endif /* _M2M_PERIPH_H_ */ \ No newline at end of file diff --git a/lib/WiFi101/src/driver/include/m2m_ssl.h b/lib/WiFi101/src/driver/include/m2m_ssl.h new file mode 100644 index 0000000..f5271f0 --- /dev/null +++ b/lib/WiFi101/src/driver/include/m2m_ssl.h @@ -0,0 +1,182 @@ +/** + * + * \file + * + * \brief WINC Application Interface Internal Types. + * + * Copyright (c) 2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +/**@defgroup SSLAPI SSL +*/ + +#ifndef __M2M_SSL_H__ +#define __M2M_SSL_H__ + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +#include "common/include/nm_common.h" +#include "driver/include/m2m_types.h" +#include "driver/source/nmdrv.h" +#include "ecc_types.h" +#include "socket/include/socket.h" + +/**@defgroup SSLEnums Enumeration/Typedefs + * @ingroup SSLAPI + * @{*/ + +/*! +@typedef \ + void (*tpfAppSslCb) (uint8 u8MsgType, void * pvMsg); + +@brief A callback to get SSL notifications. + +@param[in] u8MsgType +@param[in] pvMsg A structure to provide notification payload. +*/ +typedef void (*tpfAppSSLCb) (uint8 u8MsgType, void * pvMsg); + +/**@} +*/ + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +FUNCTION PROTOTYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/** \defgroup SSLFUNCTIONS Functions +* @ingroup SSLAPI +*/ + +/**@{*/ +/*! + @fn \ m2m_ssl_init(tpfAppSslCb pfAppSslCb); + @brief Initializes the SSL layer. + @param [in] pfAppSslCb + Application SSL callback function. + @return The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ssl_init(tpfAppSSLCb pfAppSSLCb); + +/*! + @fn \ NMI_API sint8 m2m_ssl_handshake_rsp(tstrEccReqInfo* strECCResp, uint8* pu8RspDataBuff, uint16 u16RspDataSz) + @brief Sends ECC responses to the WINC + @param [in] strECCResp + ECC Response struct. + @param [in] pu8RspDataBuffe + Pointer of the response data to be sent. + @param [in] u16RspDataSz + Response data size. + @return The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ssl_handshake_rsp(tstrEccReqInfo* strECCResp, uint8* pu8RspDataBuff, uint16 u16RspDataSz); + +/*! + @fn \ NMI_API sint8 m2m_ssl_send_certs_to_winc(uint8* pu8Buffer, uint32 u32BufferSz) + @brief Sends certificates to the WINC + @param [in] pu8Buffer + Pointer to the certificates. + @param [in] u32BufferSz + Size of the certificates. + @return The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ssl_send_certs_to_winc(uint8* pu8Buffer, uint32 u32BufferSz); + +/*! + @fn \ NMI_API sint8 m2m_ssl_retrieve_cert(uint16* pu16CurveType, uint8* pu8Hash, uint8* pu8Sig, tstrECPoint* pu8Key) + @brief Retrieve the certificate to be verified from the WINC + @param [in] pu16CurveType + Pointer to the certificate curve type. + @param [in] pu8Hash + Pointer to the certificate hash. + @param [in] pu8Sig + Pointer to the certificate signature. + @param [in] pu8Key + Pointer to the certificate Key. + @return The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ssl_retrieve_cert(uint16* pu16CurveType, uint8* pu8Hash, uint8* pu8Sig, tstrECPoint* pu8Key); + +/*! + @fn \ NMI_API sint8 m2m_ssl_retrieve_hash(uint8* pu8Hash, uint16 u16HashSz) + @brief Retrieve the certificate hash + @param [in] pu8Hash + Pointer to the certificate hash. + @param [in] u16HashSz + Hash size. + @return The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ssl_retrieve_hash(uint8* pu8Hash, uint16 u16HashSz); + +/*! + @fn \ NMI_API void m2m_ssl_stop_processing_certs(void) + @brief Allow ssl driver to tidy up in case application does not read all available certificates. + @warning This API must only be called if some certificates are left unread. + @return None. +*/ +NMI_API void m2m_ssl_stop_processing_certs(void); + +/*! + @fn \ NMI_API void m2m_ssl_ecc_process_done(void) + @brief Allow ssl driver to tidy up after application has finished processing ecc message. + @warning This API must be called after receiving a SSL callback with type @ref M2M_SSL_REQ_ECC + @return None. +*/ +NMI_API void m2m_ssl_ecc_process_done(void); + +/*! +@fn \ + NMI_API sint8 m2m_ssl_set_active_ciphersuites(uint32 u32SslCsBMP); + Override the default Active SSL ciphers in the SSL module with a certain combination selected by the caller in the form of + a bitmap containing the required ciphers to be on. + There is no need to call this function if the application will not change the default ciphersuites. + +@param [in] u32SslCsBMP + Bitmap containing the desired ciphers to be enabled for the SSL module. The ciphersuites are defined in + @ref SSLCipherSuiteID. + The default ciphersuites are all ciphersuites supported by the firmware with the exception of ECC ciphersuites. + The caller can override the default with any desired combination, except for combinations involving both RSA + and ECC; if any RSA ciphersuite is enabled, then firmware will disable all ECC ciphersuites. + If u32SslCsBMP does not contain any ciphersuites supported by firmware, then the current active list will not + be changed. + +@return + - [SOCK_ERR_NO_ERROR](@ref SOCK_ERR_NO_ERROR) + - [SOCK_ERR_INVALID_ARG](@ref SOCK_ERR_INVALID_ARG) +*/ +sint8 m2m_ssl_set_active_ciphersuites(uint32 u32SslCsBMP); + + /**@}*/ +#endif /* __M2M_SSL_H__ */ \ No newline at end of file diff --git a/lib/WiFi101/src/driver/include/m2m_types.h b/lib/WiFi101/src/driver/include/m2m_types.h new file mode 100644 index 0000000..a847f3f --- /dev/null +++ b/lib/WiFi101/src/driver/include/m2m_types.h @@ -0,0 +1,2383 @@ +/** + * + * \file + * + * \brief WINC Application Interface Internal Types. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef __M2M_WIFI_TYPES_H__ +#define __M2M_WIFI_TYPES_H__ + + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +#ifndef _BOOT_ +#ifndef _FIRMWARE_ +#include "common/include/nm_common.h" +#else +#include "m2m_common.h" +#endif +#endif + + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +MACROS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/**@defgroup WlanDefines Defines + * @ingroup m2m_wifi + */ +/**@{*/ +#define M2M_MAJOR_SHIFT (8) +#define M2M_MINOR_SHIFT (4) +#define M2M_PATCH_SHIFT (0) + +#define M2M_DRV_VERSION_SHIFT (16) +#define M2M_FW_VERSION_SHIFT (0) + +#define M2M_GET_MAJOR(ver_info_hword) ((uint8)((ver_info_hword) >> M2M_MAJOR_SHIFT) & 0xff) +#define M2M_GET_MINOR(ver_info_hword) ((uint8)((ver_info_hword) >> M2M_MINOR_SHIFT) & 0x0f) +#define M2M_GET_PATCH(ver_info_hword) ((uint8)((ver_info_hword) >> M2M_PATCH_SHIFT) & 0x0f) + +#define M2M_GET_FW_VER(ver_info_word) ((uint16) ((ver_info_word) >> M2M_FW_VERSION_SHIFT)) +#define M2M_GET_DRV_VER(ver_info_word) ((uint16) ((ver_info_word) >> M2M_DRV_VERSION_SHIFT)) + +#define M2M_GET_DRV_MAJOR(ver_info_word) M2M_GET_MAJOR(M2M_GET_DRV_VER(ver_info_word)) +#define M2M_GET_DRV_MINOR(ver_info_word) M2M_GET_MINOR(M2M_GET_DRV_VER(ver_info_word)) +#define M2M_GET_DRV_PATCH(ver_info_word) M2M_GET_PATCH(M2M_GET_DRV_VER(ver_info_word)) + +#define M2M_GET_FW_MAJOR(ver_info_word) M2M_GET_MAJOR(M2M_GET_FW_VER(ver_info_word)) +#define M2M_GET_FW_MINOR(ver_info_word) M2M_GET_MINOR(M2M_GET_FW_VER(ver_info_word)) +#define M2M_GET_FW_PATCH(ver_info_word) M2M_GET_PATCH(M2M_GET_FW_VER(ver_info_word)) + +#define M2M_MAKE_VERSION(major, minor, patch) ( \ + ((uint16)((major) & 0xff) << M2M_MAJOR_SHIFT) | \ + ((uint16)((minor) & 0x0f) << M2M_MINOR_SHIFT) | \ + ((uint16)((patch) & 0x0f) << M2M_PATCH_SHIFT)) + +#define M2M_MAKE_VERSION_INFO(fw_major, fw_minor, fw_patch, drv_major, drv_minor, drv_patch) \ + ( \ + ( ((uint32)M2M_MAKE_VERSION((fw_major), (fw_minor), (fw_patch))) << M2M_FW_VERSION_SHIFT) | \ + ( ((uint32)M2M_MAKE_VERSION((drv_major), (drv_minor), (drv_patch))) << M2M_DRV_VERSION_SHIFT)) + +#define REL_19_5_2_VER M2M_MAKE_VERSION_INFO(19,5,2,19,3,0) +#define REL_19_5_1_VER M2M_MAKE_VERSION_INFO(19,5,1,19,3,0) +#define REL_19_5_0_VER M2M_MAKE_VERSION_INFO(19,5,0,19,3,0) +#define REL_19_4_6_VER M2M_MAKE_VERSION_INFO(19,4,6,19,3,0) +#define REL_19_4_5_VER M2M_MAKE_VERSION_INFO(19,4,5,19,3,0) +#define REL_19_4_4_VER M2M_MAKE_VERSION_INFO(19,4,4,19,3,0) +#define REL_19_4_3_VER M2M_MAKE_VERSION_INFO(19,4,3,19,3,0) +#define REL_19_4_2_VER M2M_MAKE_VERSION_INFO(19,4,2,19,3,0) +#define REL_19_4_1_VER M2M_MAKE_VERSION_INFO(19,4,1,19,3,0) +#define REL_19_4_0_VER M2M_MAKE_VERSION_INFO(19,4,0,19,3,0) +#define REL_19_3_1_VER M2M_MAKE_VERSION_INFO(19,3,1,19,3,0) +#define REL_19_3_0_VER M2M_MAKE_VERSION_INFO(19,3,0,19,3,0) +#define REL_19_2_2_VER M2M_MAKE_VERSION_INFO(19,2,2,19,2,0) +#define REL_19_2_1_VER M2M_MAKE_VERSION_INFO(19,2,1,19,2,0) +#define REL_19_2_0_VER M2M_MAKE_VERSION_INFO(19,2,0,19,2,0) +#define REL_19_1_0_VER M2M_MAKE_VERSION_INFO(19,1,0,18,2,0) +#define REL_19_0_0_VER M2M_MAKE_VERSION_INFO(19,0,0,18,1,1) + +/*======*======*======*======* + FIRMWARE VERSION NO INFO + *======*======*======*======*/ + +#define M2M_RELEASE_VERSION_MAJOR_NO (19) +/*!< Firmware Major release version number. +*/ + + +#define M2M_RELEASE_VERSION_MINOR_NO (5) +/*!< Firmware Minor release version number. +*/ + +#define M2M_RELEASE_VERSION_PATCH_NO (2) +/*!< Firmware patch release version number. +*/ + +/*======*======*======*======* + SUPPORTED DRIVER VERSION NO INFO + *======*======*======*======*/ + +#define M2M_MIN_REQ_DRV_VERSION_MAJOR_NO (19) +/*!< Driver Major release version number. +*/ + + +#define M2M_MIN_REQ_DRV_VERSION_MINOR_NO (3) +/*!< Driver Minor release version number. +*/ + +#define M2M_MIN_REQ_DRV_VERSION_PATCH_NO (0) +/*!< Driver patch release version number. +*/ + +#define M2M_MIN_REQ_DRV_SVN_VERSION (0) +/*!< Driver svn version. +*/ + + + +#if !defined(M2M_RELEASE_VERSION_MAJOR_NO) || !defined(M2M_RELEASE_VERSION_MINOR_NO) +#error Undefined version number +#endif + +#define M2M_BUFFER_MAX_SIZE (1600UL - 4) +/*!< Maximum size for the shared packet buffer. + */ + + +#define M2M_MAC_ADDRES_LEN 6 +/*!< The size fo 802 MAC address. + */ + +#define M2M_ETHERNET_HDR_OFFSET 34 +/*!< The offset of the Ethernet header within the WLAN Tx Buffer. + */ + + +#define M2M_ETHERNET_HDR_LEN 14 +/*!< Length of the Etherenet header in bytes. +*/ + + +#define M2M_MAX_SSID_LEN 33 +/*!< Maximum size for the Wi-Fi SSID including the NULL termination. + */ + + +#define M2M_MAX_PSK_LEN 65 +/*!< Maximum size for the WPA PSK including the NULL termination. + */ + +#define M2M_MIN_PSK_LEN 9 +/*!< Maximum size for the WPA PSK including the NULL termination. + */ + +#define M2M_DEVICE_NAME_MAX 48 +/*!< Maximum Size for the device name including the NULL termination. + */ + + +#define M2M_LISTEN_INTERVAL 1 +/*!< The STA uses the Listen Interval parameter to indicate to the AP how + many beacon intervals it shall sleep before it retrieves the queued frames + from the AP. +*/ + +#define MAX_HIDDEN_SITES 4 +/*!< + max number of hidden SSID suuported by scan request +*/ + + +#define M2M_1X_USR_NAME_MAX 21 +/*!< The maximum size of the user name including the NULL termination. + It is used for RADIUS authentication in case of connecting the device to + an AP secured with WPA-Enterprise. +*/ + + +#define M2M_1X_PWD_MAX 41 +/*!< The maximum size of the password including the NULL termination. + It is used for RADIUS authentication in case of connecting the device to + an AP secured with WPA-Enterprise. +*/ + +#define M2M_CUST_IE_LEN_MAX 252 +/*!< The maximum size of IE (Information Element). +*/ + +#define PWR_DEFAULT PWR_HIGH +/********************* + * + * WIFI GROUP requests + */ + +#define M2M_CONFIG_CMD_BASE 1 +/*!< The base value of all the host configuration commands opcodes. +*/ +#define M2M_STA_CMD_BASE 40 +/*!< The base value of all the station mode host commands opcodes. +*/ +#define M2M_AP_CMD_BASE 70 +/*!< The base value of all the Access Point mode host commands opcodes. +*/ +#define M2M_P2P_CMD_BASE 90 +/*!< The base value of all the P2P mode host commands opcodes. +*/ +#define M2M_SERVER_CMD_BASE 100 +/*!< The base value of all the power save mode host commands codes. +*/ +/********************** + * OTA GROUP requests + */ +#define M2M_OTA_CMD_BASE 100 +/*!< The base value of all the OTA mode host commands opcodes. + * The OTA Have special group so can extended from 1-M2M_MAX_GRP_NUM_REQ +*/ +/*********************** + * + * CRYPTO group requests + */ +#define M2M_CRYPTO_CMD_BASE 1 +/*!< The base value of all the crypto mode host commands opcodes. + * The crypto Have special group so can extended from 1-M2M_MAX_GRP_NUM_REQ +*/ + +#define M2M_MAX_GRP_NUM_REQ (127) +/*!< max number of request in one group equal to 127 as the last bit reserved for config or data pkt +*/ + +#define WEP_40_KEY_STRING_SIZE ((uint8)10) +/*!< Indicate the wep key size in bytes for 40 bit string passphrase. +*/ + +#define WEP_104_KEY_STRING_SIZE ((uint8)26) +/*!< Indicate the wep key size in bytes for 104 bit string passphrase. +*/ +#define WEP_KEY_MAX_INDEX ((uint8)4) +/*!< Indicate the max key index value for WEP authentication +*/ +#define M2M_SHA256_CONTEXT_BUFF_LEN (128) +/*!< sha256 context size +*/ +#define M2M_SCAN_DEFAULT_NUM_SLOTS (2) +/*!< The default. number of scan slots performed by the WINC board. +*/ +#define M2M_SCAN_DEFAULT_SLOT_TIME (30) +/*!< The default. duration in miliseconds of a scan slots performed by the WINC board. +*/ +#define M2M_SCAN_DEFAULT_NUM_PROBE (2) +/*!< The default. number of scan slots performed by the WINC board. +*/ + + +/*======*======*======*======* + CONNECTION ERROR DEFINITIONS + *======*======*======*======*/ +typedef enum { + M2M_DEFAULT_CONN_INPROGRESS = ((sint8)-23), + /*!< + A failure that indicates that a default connection or forced connection is in progress + */ + M2M_DEFAULT_CONN_FAIL, + /*!< + A failure response that indicates that the winc failed to connect to the cached network + */ + M2M_DEFAULT_CONN_SCAN_MISMATCH, + /*!< + A failure response that indicates that no one of the cached networks + was found in the scan results, as a result to the function call m2m_default_connect. + */ + M2M_DEFAULT_CONN_EMPTY_LIST + /*!< + A failure response that indicates an empty network list as + a result to the function call m2m_default_connect. + */ + +}tenuM2mDefaultConnErrcode; + + + +/*======*======*======*======* + TLS DEFINITIONS + *======*======*======*======*/ +#define TLS_FILE_NAME_MAX 48 +/*!< Maximum length for each TLS certificate file name including null terminator. +*/ +#define TLS_SRV_SEC_MAX_FILES 8 +/*!< Maximum number of certificates allowed in TLS_SRV section. +*/ +#define TLS_SRV_SEC_START_PATTERN_LEN 8 +/*!< Length of certificate struct start pattern. +*/ +/*======*======*======*======* + OTA DEFINITIONS + *======*======*======*======*/ + +#define OTA_STATUS_VALID (0x12526285) +/*!< + Magic value updated in the Control structure in case of ROLLACK image Valid +*/ +#define OTA_STATUS_INVALID (0x23987718) +/*!< + Magic value updated in the Control structure in case of ROLLACK image InValid +*/ +#define OTA_MAGIC_VALUE (0x1ABCDEF9) +/*!< + Magic value set at the beginning of the OTA image header +*/ +#define M2M_MAGIC_APP (0xef522f61UL) +/*!< + Magic value set at the beginning of the Cortus OTA image header +*/ + +#define OTA_FORMAT_VER_0 (0) /*Till 19.2.2 format*/ +#define OTA_FORMAT_VER_1 (1) /*starting from 19.3.0 CRC is used and sequence number is used*/ +/*!< + Control structure format version +*/ +#define OTA_SHA256_DIGEST_SIZE (32) +/*!< + Sha256 digest size in the OTA image, + the sha256 digest is set at the beginning of image before the OTA header + */ + +/*======*======*======*======* + SSL DEFINITIONS + *======*======*======*======*/ + +#define TLS_CRL_DATA_MAX_LEN 64 +/* Every bit have 3dB gain control each. + for example: + 1 ->3db + 3 ->6db + 7 ->9db + */ + uint16 u8PPAGFor11GN; + /*!< PPA gain for 11GN (as the RF document represented) + PPA_AGC<0:2> Every bit have 3dB gain control each. + for example: + 1 ->3db + 3 ->6db + 7 ->9db + */ +}tstrM2mWifiGainsParams; + +/*! +@struct \ + tstrM2mWifiWepParams + +@brief + WEP security key parameters. +*/ +typedef struct{ + uint8 u8KeyIndx; + /*!< Wep key Index. + */ + uint8 u8KeySz; + /*!< Wep key Size. + */ + uint8 au8WepKey[WEP_104_KEY_STRING_SIZE + 1]; + /*!< WEP Key represented as a NULL terminated ASCII string. + */ + uint8 __PAD24__[3]; + /*!< Padding bytes to keep the structure word alligned. + */ +}tstrM2mWifiWepParams; + + +/*! +@struct \ + tstr1xAuthCredentials + +@brief + Credentials for the user to authenticate with the AAA server (WPA-Enterprise Mode IEEE802.1x). +*/ +typedef struct{ + uint8 au8UserName[M2M_1X_USR_NAME_MAX]; + /*!< User Name. It must be Null terminated string. + */ + uint8 au8Passwd[M2M_1X_PWD_MAX]; + /*!< Password corresponding to the user name. It must be Null terminated string. + */ +}tstr1xAuthCredentials; + + +/*! +@union \ + tuniM2MWifiAuth + +@brief + Wi-Fi Security Parameters for all supported security modes. +*/ +typedef union{ + uint8 au8PSK[M2M_MAX_PSK_LEN]; + /*!< Pre-Shared Key in case of WPA-Personal security. + */ + tstr1xAuthCredentials strCred1x; + /*!< Credentials for RADIUS server authentication in case of WPA-Enterprise security. + */ + tstrM2mWifiWepParams strWepInfo; + /*!< WEP key parameters in case of WEP security. + */ +}tuniM2MWifiAuth; + + +/*! +@struct \ + tstrM2MWifiSecInfo + +@brief + Authentication credentials to connect to a Wi-Fi network. +*/ +typedef struct{ + tuniM2MWifiAuth uniAuth; + /*!< Union holding all possible authentication parameters corresponding the current security types. + */ + uint8 u8SecType; + /*!< Wi-Fi network security type. See tenuM2mSecType for supported security types. + */ +#define __PADDING__ (4 - ((sizeof(tuniM2MWifiAuth) + 1) % 4)) + uint8 __PAD__[__PADDING__]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2MWifiSecInfo; + + +/*! +@struct \ + tstrM2mWifiConnect + +@brief + Wi-Fi Connect Request +*/ +typedef struct{ + tstrM2MWifiSecInfo strSec; + /*!< Security parameters for authenticating with the AP. + */ + uint16 u16Ch; + /*!< RF Channel for the target SSID. + */ + uint8 au8SSID[M2M_MAX_SSID_LEN]; + /*!< SSID of the desired AP. It must be NULL terminated string. + */ + uint8 u8NoSaveCred; +#define __CONN_PAD_SIZE__ (4 - ((sizeof(tstrM2MWifiSecInfo) + M2M_MAX_SSID_LEN + 3) % 4)) + uint8 __PAD__[__CONN_PAD_SIZE__]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2mWifiConnect; + + +/*! +@struct \ + tstrM2MWPSConnect + +@brief + WPS Configuration parameters + +@sa + tenuWPSTrigger +*/ +typedef struct { + uint8 u8TriggerType; + /*!< WPS triggering method (Push button or PIN) + */ + char acPinNumber[8]; + /*!< WPS PIN No (for PIN method) + */ + uint8 __PAD24__[3]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2MWPSConnect; + + +/*! +@struct \ + tstrM2MWPSInfo + +@brief WPS Result + + This structure is passed to the application in response to a WPS request. If the WPS session is completed successfully, the + structure will have Non-ZERO authentication type. If the WPS Session fails (due to error or timeout) the authentication type + is set to ZERO. + +@sa + tenuM2mSecType +*/ +typedef struct{ + uint8 u8AuthType; + /*!< Network authentication type. + */ + uint8 u8Ch; + /*!< RF Channel for the AP. + */ + uint8 au8SSID[M2M_MAX_SSID_LEN]; + /*!< SSID obtained from WPS. + */ + uint8 au8PSK[M2M_MAX_PSK_LEN]; + /*!< PSK for the network obtained from WPS. + */ +}tstrM2MWPSInfo; + + +/*! +@struct \ + tstrM2MDefaultConnResp + +@brief + Response error of the m2m_default_connect + +@sa + M2M_DEFAULT_CONN_SCAN_MISMATCH + M2M_DEFAULT_CONN_EMPTY_LIST +*/ +typedef struct{ + sint8 s8ErrorCode; + /*!< + Default connect error code. possible values are: + - M2M_DEFAULT_CONN_EMPTY_LIST + - M2M_DEFAULT_CONN_SCAN_MISMATCH + */ + uint8 __PAD24__[3]; +}tstrM2MDefaultConnResp; + +/*! +@struct \ + tstrM2MScanOption + +@brief + Scan options and configurations. + +@sa + tenuM2mScanCh + tstrM2MScan +*/ +typedef struct { + uint8 u8NumOfSlot; + /*|< The min number of slots is 2 for every channel, + every slot the soc will send Probe Request on air, and wait/listen for PROBE RESP/BEACONS for the u16slotTime + */ + uint8 u8SlotTime; + /*|< the time that the Soc will wait on every channel listening to the frames on air + when that time increaseed number of AP will increased in the scan results + min time is 10 ms and the max is 250 ms + */ + uint8 u8ProbesPerSlot; + /*!< Number of probe requests to be sent per channel scan slot. + */ + sint8 s8RssiThresh; + /*! < The RSSI threshold of the AP which will be connected to directly. + */ + +}tstrM2MScanOption; + +/*! +@struct \ + tstrM2MScanRegion + +@brief + Wi-Fi channel regulation region information. + +@sa + tenuM2mScanRegion +*/ +typedef struct { + uint16 u16ScanRegion; + /*|< Specifies the number of channels allowed in the region (e.g. North America = 11 ... etc.). + */ + uint8 __PAD16__[2]; + +}tstrM2MScanRegion; + +/*! +@struct \ + tstrM2MScan + +@brief + Wi-Fi Scan Request + +@sa + tenuM2mScanCh + tstrM2MScanOption +*/ +typedef struct { + uint8 u8ChNum; + /*!< The Wi-Fi RF Channel number + */ + uint8 __RSVD8__[1]; + /*!< Reserved for future use. + */ + uint16 u16PassiveScanTime; + /*!< Passive Scan Timeout in ms. The field is ignored for active scan. + */ +}tstrM2MScan; + +/*! +@struct \ + tstrCyptoResp + +@brief + crypto response +*/ +typedef struct { + sint8 s8Resp; + /***/ + uint8 __PAD24__[3]; + /* + */ +}tstrCyptoResp; + + +/*! +@struct \ + tstrM2mScanDone + +@brief + Wi-Fi Scan Result +*/ +typedef struct{ + uint8 u8NumofCh; + /*!< Number of found APs + */ + sint8 s8ScanState; + /*!< Scan status + */ + uint8 __PAD16__[2]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2mScanDone; + + +/*! +@struct \ + tstrM2mReqScanResult + +@brief Scan Result Request + + The Wi-Fi Scan results list is stored in Firmware. The application can request a certain scan result by its index. +*/ +typedef struct { + uint8 u8Index; + /*!< Index of the desired scan result + */ + uint8 __PAD24__[3]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2mReqScanResult; + + +/*! +@struct \ + tstrM2mWifiscanResult + +@brief Wi-Fi Scan Result + + Information corresponding to an AP in the Scan Result list identified by its order (index) in the list. +*/ +typedef struct { + uint8 u8index; + /*!< AP index in the scan result list. + */ + sint8 s8rssi; + /*!< AP signal strength. + */ + uint8 u8AuthType; + /*!< AP authentication type. + */ + uint8 u8ch; + /*!< AP RF channel. + */ + uint8 au8BSSID[6]; + /*!< BSSID of the AP. + */ + uint8 au8SSID[M2M_MAX_SSID_LEN]; + /*!< AP ssid. + */ + uint8 _PAD8_; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2mWifiscanResult; + + +/*! +@struct \ + tstrM2mWifiStateChanged + +@brief + Wi-Fi Connection State + +@sa + M2M_WIFI_DISCONNECTED, M2M_WIFI_CONNECTED, M2M_WIFI_REQ_CON_STATE_CHANGED,tenuM2mConnChangedErrcode +*/ +typedef struct { + uint8 u8CurrState; + /*!< Current Wi-Fi connection state + */ + uint8 u8ErrCode; + /*!< Error type review tenuM2mConnChangedErrcode + */ + uint8 __PAD16__[2]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2mWifiStateChanged; + + +/*! +@struct \ + tstrM2mPsType + +@brief + Power Save Configuration + +@sa + tenuPowerSaveModes +*/ +typedef struct{ + uint8 u8PsType; + /*!< Power save operating mode + */ + uint8 u8BcastEn; + /*!< + */ + uint8 __PAD16__[2]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2mPsType; + +/*! +@struct \ + tstrM2mSlpReqTime + +@brief + Manual power save request sleep time + +*/ +typedef struct { + /*!< Sleep time in ms + */ + uint32 u32SleepTime; + +} tstrM2mSlpReqTime; + +/*! +@struct \ + tstrM2mLsnInt + +@brief Listen interval + + It is the value of the Wi-Fi STA listen interval for power saving. It is given in units of Beacon period. + Periodically after the listen interval fires, the WINC is wakeup and listen to the beacon and check for any buffered frames for it from the AP. +*/ +typedef struct { + uint16 u16LsnInt; + /*!< Listen interval in Beacon period count. + */ + uint8 __PAD16__[2]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2mLsnInt; + + +/*! +@struct \ + tstrM2MWifiMonitorModeCtrl + +@brief Wi-Fi Monitor Mode Filter + + This structure sets the filtering criteria for WLAN packets when monitoring mode is enable. + The received packets matching the filtering parameters, are passed directly to the application. +*/ +typedef struct{ + uint8 u8ChannelID; + /* !< RF Channel ID. It must use values from tenuM2mScanCh + */ + uint8 u8FrameType; + /*!< It must use values from tenuWifiFrameType. + */ + uint8 u8FrameSubtype; + /*!< It must use values from tenuSubTypes. + */ + uint8 au8SrcMacAddress[6]; + /* ZERO means DO NOT FILTER Source address. + */ + uint8 au8DstMacAddress[6]; + /* ZERO means DO NOT FILTER Destination address. + */ + uint8 au8BSSID[6]; + /* ZERO means DO NOT FILTER BSSID. + */ + uint8 u8EnRecvHdr; + /* + Enable recv the full hder before the payload + */ + uint8 __PAD16__[2]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2MWifiMonitorModeCtrl; + + +/*! +@struct \ + tstrM2MWifiRxPacketInfo + +@brief Wi-Fi RX Frame Header + + The M2M application has the ability to allow Wi-Fi monitoring mode for receiving all Wi-Fi Raw frames matching a well defined filtering criteria. + When a target Wi-Fi packet is received, the header information are extracted and assigned in this structure. +*/ +typedef struct{ + uint8 u8FrameType; + /*!< It must use values from tenuWifiFrameType. + */ + uint8 u8FrameSubtype; + /*!< It must use values from tenuSubTypes. + */ + uint8 u8ServiceClass; + /*!< Service class from Wi-Fi header. + */ + uint8 u8Priority; + /*!< Priority from Wi-Fi header. + */ + uint8 u8HeaderLength; + /*!< Frame Header length. + */ + uint8 u8CipherType; + /*!< Encryption type for the rx packet. + */ + uint8 au8SrcMacAddress[6]; + /* ZERO means DO NOT FILTER Source address. + */ + uint8 au8DstMacAddress[6]; + /* ZERO means DO NOT FILTER Destination address. + */ + uint8 au8BSSID[6]; + /* ZERO means DO NOT FILTER BSSID. + */ + uint16 u16DataLength; + /*!< Data payload length (Header excluded). + */ + uint16 u16FrameLength; + /*!< Total frame length (Header + Data). + */ + uint32 u32DataRateKbps; + /*!< Data Rate in Kbps. + */ + sint8 s8RSSI; + /*!< RSSI. + */ + uint8 __PAD24__[3]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2MWifiRxPacketInfo; + + +/*! +@struct \ + tstrM2MWifiTxPacketInfo + +@brief Wi-Fi TX Packet Info + + The M2M Application has the ability to compose a RAW Wi-Fi frames (under the application responsibility). + When transmitting a Wi-Fi packet, the application must supply the firmware with this structure for sending the target frame. +*/ +typedef struct{ + uint16 u16PacketSize; + /*!< Wlan frame length. + */ + uint16 u16HeaderLength; + /*!< Wlan frame header length. + */ +}tstrM2MWifiTxPacketInfo; + + +/*! + @struct \ + tstrM2MP2PConnect + + @brief + Set the device to operate in the Wi-Fi Direct (P2P) mode. +*/ +typedef struct { + uint8 u8ListenChannel; + /*!< P2P Listen Channel (1, 6 or 11) + */ + uint8 __PAD24__[3]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2MP2PConnect; + +/*! +@struct \ + tstrM2MAPConfig + +@brief AP Configuration + + This structure holds the configuration parameters for the M2M AP mode. It should be set by the application when + it requests to enable the M2M AP operation mode. The M2M AP mode currently supports only WEP security (with + the NO Security option available of course). +*/ +typedef struct { + /*!< + Configuration parameters for the WiFi AP. + */ + uint8 au8SSID[M2M_MAX_SSID_LEN]; + /*!< AP SSID + */ + uint8 u8ListenChannel; + /*!< Wi-Fi RF Channel which the AP will operate on + */ + uint8 u8KeyIndx; + /*!< Wep key Index + */ + uint8 u8KeySz; + /*!< Wep/WPA key Size + */ + uint8 au8WepKey[WEP_104_KEY_STRING_SIZE + 1]; + /*!< Wep key + */ + uint8 u8SecType; + /*!< Security type: Open or WEP or WPA in the current implementation + */ + uint8 u8SsidHide; + /*!< SSID Status "Hidden(1)/Visible(0)" + */ + uint8 au8DHCPServerIP[4]; + /*!< Ap IP server address + */ + uint8 au8Key[M2M_MAX_PSK_LEN]; + /*!< WPA key + */ + uint8 __PAD24__[2]; + /*!< Padding bytes for forcing alignment + */ +}tstrM2MAPConfig; + + +/*! +@struct \ + tstrM2mServerInit + +@brief + PS Server initialization. +*/ +typedef struct { + uint8 u8Channel; + /*!< Server Listen channel + */ + uint8 __PAD24__[3]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2mServerInit; + + +/*! +@struct \ + tstrM2mClientState + +@brief + PS Client State. +*/ +typedef struct { + uint8 u8State; + /*!< PS Client State + */ + uint8 __PAD24__[3]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2mClientState; + + +/*! +@struct \ + tstrM2Mservercmd + +@brief + PS Server CMD +*/ +typedef struct { + uint8 u8cmd; + /*!< PS Server Cmd + */ + uint8 __PAD24__[3]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2Mservercmd; + + +/*! +@struct \ + tstrM2mSetMacAddress + +@brief + Sets the MAC address from application. The WINC load the mac address from the effuse by default to the WINC configuration memory, + but that function is used to let the application overwrite the configuration memory with the mac address from the host. + +@note + It's recommended to call this only once before calling connect request and after the m2m_wifi_init +*/ +typedef struct { + uint8 au8Mac[6]; + /*!< MAC address array + */ + uint8 __PAD16__[2]; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2mSetMacAddress; + + +/*! +@struct \ + tstrM2MDeviceNameConfig + +@brief Device name + + It is assigned by the application. It is used mainly for Wi-Fi Direct device + discovery and WPS device information. +*/ +typedef struct { + uint8 au8DeviceName[M2M_DEVICE_NAME_MAX]; + /*!< NULL terminated device name + */ +}tstrM2MDeviceNameConfig; + + +/*! +@struct \ + tstrM2MIPConfig + +@brief + Static IP configuration. + +@note + All member IP addresses are expressed in Network Byte Order (eg. "192.168.10.1" will be expressed as 0x010AA8C0). + */ +typedef struct { + uint32 u32StaticIP; + /*!< The static IP assigned to the device. + */ + uint32 u32Gateway; + /*!< IP of the Default internet gateway. + */ + uint32 u32DNS; + /*!< IP for the DNS server. + */ + uint32 u32SubnetMask; + /*!< Subnet mask for the local area network. + */ + uint32 u32DhcpLeaseTime; + /*!< Dhcp Lease Time in sec + */ +} tstrM2MIPConfig; + +/*! +@struct \ + tstrM2mIpRsvdPkt + +@brief + Received Packet Size and Data Offset + + */ +typedef struct{ + uint16 u16PktSz; + uint16 u16PktOffset; +} tstrM2mIpRsvdPkt; + + +/*! +@struct \ + tstrM2MProvisionModeConfig + +@brief + M2M Provisioning Mode Configuration + */ + +typedef struct { + tstrM2MAPConfig strApConfig; + /*!< + Configuration parameters for the WiFi AP. + */ + char acHttpServerDomainName[64]; + /*!< + The device domain name for HTTP provisioning. + */ + uint8 u8EnableRedirect; + /*!< + A flag to enable/disable HTTP redirect feature for the HTTP Provisioning server. If the Redirect is enabled, + all HTTP traffic (http://URL) from the device associated with WINC AP will be redirected to the HTTP Provisioning Web page. + - 0 : Disable HTTP Redirect. + - 1 : Enable HTTP Redirect. + */ + uint8 __PAD24__[3]; +}tstrM2MProvisionModeConfig; + + +/*! +@struct \ + tstrM2MProvisionInfo + +@brief + M2M Provisioning Information obtained from the HTTP Provisioning server. + */ +typedef struct{ + uint8 au8SSID[M2M_MAX_SSID_LEN]; + /*!< + Provisioned SSID. + */ + uint8 au8Password[M2M_MAX_PSK_LEN]; + /*!< + Provisioned Password. + */ + uint8 u8SecType; + /*!< + Wifi Security type. + */ + uint8 u8Status; + /*!< + Provisioning status. It must be checked before reading the provisioning information. It may be + - M2M_SUCCESS : Provision successful. + - M2M_FAIL : Provision Failed. + */ +}tstrM2MProvisionInfo; + + +/*! +@struct \ + tstrM2MConnInfo + +@brief + M2M Provisioning Information obtained from the HTTP Provisioning server. + */ +typedef struct{ + char acSSID[M2M_MAX_SSID_LEN]; + /*!< AP connection SSID name */ + uint8 u8SecType; + /*!< Security type */ + uint8 au8IPAddr[4]; + /*!< Connection IP address */ + uint8 au8MACAddress[6]; + /*!< MAC address of the peer Wi-Fi station */ + sint8 s8RSSI; + /*!< Connection RSSI signal */ + uint8 __PAD24__[3]; + /*!< Padding bytes for forcing 4-byte alignment */ +}tstrM2MConnInfo; + +/*! +@struct \ + tstrOtaInitHdr + +@brief + OTA Image Header + */ + +typedef struct{ + uint32 u32OtaMagicValue; + /*!< Magic value kept in the OTA image after the + sha256 Digest buffer to define the Start of OTA Header */ + uint32 u32OtaPayloadSzie; + /*!< + The Total OTA image payload size, include the sha256 key size + */ + +}tstrOtaInitHdr; + + +/*! +@struct \ + tstrOtaControlSec + +@brief + Control section structure is used to define the working image and + the validity of the roll-back image and its offset, also both firmware versions is kept in that structure. + */ + +typedef struct { + uint32 u32OtaMagicValue; +/*!< + Magic value used to ensure the structure is valid or not +*/ + uint32 u32OtaFormatVersion; +/*!< + NA NA NA Flash version cs struct version + 00 00 00 00 00 + Control structure format version, the value will be incremented in case of structure changed or updated +*/ + uint32 u32OtaSequenceNumber; +/*!< + Sequence number is used while update the control structure to keep track of how many times that section updated +*/ + uint32 u32OtaLastCheckTime; +/*!< + Last time OTA check for update +*/ + uint32 u32OtaCurrentworkingImagOffset; +/*!< + Current working offset in flash +*/ + uint32 u32OtaCurrentworkingImagFirmwareVer; +/*!< + current working image version ex 18.0.1 +*/ + uint32 u32OtaRollbackImageOffset; +/*!< + Roll-back image offset in flash +*/ + uint32 u32OtaRollbackImageValidStatus; +/*!< + roll-back image valid status +*/ + uint32 u32OtaRollbackImagFirmwareVer; +/*!< + Roll-back image version (ex 18.0.3) +*/ + uint32 u32OtaCortusAppWorkingOffset; +/*!< + cortus app working offset in flash +*/ + uint32 u32OtaCortusAppWorkingValidSts; +/*!< + Working Cortus app valid status +*/ + uint32 u32OtaCortusAppWorkingVer; +/*!< + Working cortus app version (ex 18.0.3) +*/ + uint32 u32OtaCortusAppRollbackOffset; +/*!< + cortus app rollback offset in flash +*/ + uint32 u32OtaCortusAppRollbackValidSts; +/*!< + roll-back cortus app valid status +*/ + uint32 u32OtaCortusAppRollbackVer; +/*!< + Roll-back cortus app version (ex 18.0.3) +*/ + uint32 u32OtaControlSecCrc; +/*!< + CRC for the control structure to ensure validity +*/ +} tstrOtaControlSec; + +/*! +@enum \ + tenuOtaUpdateStatus + +@brief + OTA return status +*/ +typedef enum { + OTA_STATUS_SUCSESS = 0, + /*!< OTA Success with not errors. */ + OTA_STATUS_FAIL = 1, + /*!< OTA generic fail. */ + OTA_STATUS_INVAILD_ARG = 2, + /*!< Invalid or malformed download URL. */ + OTA_STATUS_INVAILD_RB_IMAGE = 3, + /*!< Invalid rollback image. */ + OTA_STATUS_INVAILD_FLASH_SIZE = 4, + /*!< Flash size on device is not enough for OTA. */ + OTA_STATUS_AlREADY_ENABLED = 5, + /*!< An OTA operation is already enabled. */ + OTA_STATUS_UPDATE_INPROGRESS = 6, + /*!< An OTA operation update is in progress */ + OTA_STATUS_IMAGE_VERIF_FAILED = 7, + /*!< OTA Verfication failed */ + OTA_STATUS_CONNECTION_ERROR = 8, + /*!< OTA connection error */ + OTA_STATUS_SERVER_ERROR = 9, + /*!< OTA server Error (file not found or else ...) */ + OTA_STATUS_ABORTED = 10 + /*!< OTA download has been aborted by the application. */ +} tenuOtaUpdateStatus; +/*! +@enum \ + tenuOtaUpdateStatusType + +@brief + OTA update Status type +*/ +typedef enum { + + DL_STATUS = 1, + /*!< Download OTA file status + */ + SW_STATUS = 2, + /*!< Switching to the upgrade firmware status + */ + RB_STATUS = 3, + /*!< Roll-back status + */ + AB_STATUS = 4 + /*!< Abort status + */ +}tenuOtaUpdateStatusType; + + +/*! +@struct \ + tstrOtaUpdateStatusResp + +@brief + OTA Update Information + +@sa + tenuWPSTrigger +*/ +typedef struct { + uint8 u8OtaUpdateStatusType; + /*!< + Status type tenuOtaUpdateStatusType + */ + uint8 u8OtaUpdateStatus; + /*!< + OTA_SUCCESS + OTA_ERR_WORKING_IMAGE_LOAD_FAIL + OTA_ERR_INVAILD_CONTROL_SEC + M2M_ERR_OTA_SWITCH_FAIL + M2M_ERR_OTA_START_UPDATE_FAIL + M2M_ERR_OTA_ROLLBACK_FAIL + M2M_ERR_OTA_INVAILD_FLASH_SIZE + M2M_ERR_OTA_INVAILD_ARG + */ + uint8 _PAD16_[2]; +}tstrOtaUpdateStatusResp; + +/*! +@struct \ + tstrOtaUpdateInfo + +@brief + OTA Update Information + +@sa + tenuWPSTrigger +*/ +typedef struct { + uint32 u8NcfUpgradeVersion; + /*!< NCF OTA Upgrade Version + */ + uint32 u8NcfCurrentVersion; + /*!< NCF OTA Current firmware version + */ + uint32 u8NcdUpgradeVersion; + /*!< NCD (host) upgraded version (if the u8NcdRequiredUpgrade == true) + */ + uint8 u8NcdRequiredUpgrade; + /*!< NCD Required upgrade to the above version + */ + uint8 u8DownloadUrlOffset; + /*!< Download URL offset in the received packet + */ + uint8 u8DownloadUrlSize; + /*!< Download URL size in the received packet + */ + uint8 __PAD8__; + /*!< Padding bytes for forcing 4-byte alignment + */ +} tstrOtaUpdateInfo; + +/*! +@struct \ + tstrSystemTime + +@brief + Used for time storage. +*/ +typedef struct{ + uint16 u16Year; + uint8 u8Month; + uint8 u8Day; + uint8 u8Hour; + uint8 u8Minute; + uint8 u8Second; + uint8 __PAD8__; +}tstrSystemTime; + +/*! +@struct \ + tstrM2MMulticastMac + +@brief + M2M add/remove multi-cast mac address + */ + typedef struct { + uint8 au8macaddress[M2M_MAC_ADDRES_LEN]; + /*!< + Mac address needed to be added or removed from filter. + */ + uint8 u8AddRemove; + /*!< + set by 1 to add or 0 to remove from filter. + */ + uint8 __PAD8__; + /*!< Padding bytes for forcing 4-byte alignment + */ +}tstrM2MMulticastMac; + +/*! +@struct \ + tstrPrng + +@brief + M2M Request PRNG + */ + typedef struct { + /*!< + return buffer address + */ + uint8 *pu8RngBuff; + /*!< + PRNG size requested + */ + uint16 u16PrngSize; + /*!< + PRNG pads + */ + uint8 __PAD16__[2]; +}tstrPrng; + +/* + * TLS certificate revocation list + * Typedefs common between fw and host + */ + +/*! +@struct \ + tstrTlsCrlEntry + +@brief + Certificate data for inclusion in a revocation list (CRL) +*/ +typedef struct { + uint8 u8DataLen; + /*!< + Length of certificate data (maximum possible is @ref TLS_CRL_DATA_MAX_LEN) + */ + uint8 au8Data[TLS_CRL_DATA_MAX_LEN]; + /*!< + Certificate data + */ + uint8 __PAD24__[3]; + /*!< + Padding bytes for forcing 4-byte alignment + */ +}tstrTlsCrlEntry; + +/*! +@struct \ + tstrTlsCrlInfo + +@brief + Certificate revocation list details +*/ +typedef struct { + uint8 u8CrlType; + /*!< + Type of certificate data contained in list + */ + uint8 u8Rsv1; + /*!< + Reserved for future use + */ + uint8 u8Rsv2; + /*!< + Reserved for future use + */ + uint8 u8Rsv3; + /*!< + Reserved for future use + */ + tstrTlsCrlEntry astrTlsCrl[TLS_CRL_MAX_ENTRIES]; + /*!< + List entries + */ +}tstrTlsCrlInfo; + + /*! +@enum\ + tenuSslCertExpSettings + +@brief SSL Certificate Expiry Validation Options +*/ +typedef enum{ + SSL_CERT_EXP_CHECK_DISABLE, + /*!< + ALWAYS OFF. + Ignore certificate expiration date validation. If a certificate is + expired or there is no configured system time, the SSL connection SUCCEEDs. + */ + SSL_CERT_EXP_CHECK_ENABLE, + /*!< + ALWAYS ON. + Validate certificate expiration date. If a certificate is expired or + there is no configured system time, the SSL connection FAILs. + */ + SSL_CERT_EXP_CHECK_EN_IF_SYS_TIME + /*!< + CONDITIONAL VALIDATION (Default setting at startup). + Validate the certificate expiration date only if there is a configured system time. + If there is no configured system time, the certificate expiration is bypassed and the + SSL connection SUCCEEDs. + */ +}tenuSslCertExpSettings; + + +/*! +@struct \ + tstrTlsSrvSecFileEntry + +@brief + This struct contains a TLS certificate. + */ +typedef struct{ + char acFileName[TLS_FILE_NAME_MAX]; + /*!< Name of the certificate. */ + uint32 u32FileSize; + /*!< Size of the certificate. */ + uint32 u32FileAddr; + /*!< Error Code. */ +}tstrTlsSrvSecFileEntry; + +/*! +@struct \ + tstrTlsSrvSecHdr + +@brief + This struct contains a set of TLS certificates. + */ +typedef struct{ + uint8 au8SecStartPattern[TLS_SRV_SEC_START_PATTERN_LEN]; + /*!< Start pattern. */ + uint32 u32nEntries; + /*!< Number of certificates stored in the struct. */ + uint32 u32NextWriteAddr; + /*!< TLS Certificates. */ + tstrTlsSrvSecFileEntry astrEntries[TLS_SRV_SEC_MAX_FILES]; +}tstrTlsSrvSecHdr; + +typedef struct{ + uint32 u32CsBMP; +}tstrSslSetActiveCsList; + + + /**@}*/ + +#endif diff --git a/lib/WiFi101/src/driver/include/m2m_wifi.h b/lib/WiFi101/src/driver/include/m2m_wifi.h new file mode 100644 index 0000000..3477196 --- /dev/null +++ b/lib/WiFi101/src/driver/include/m2m_wifi.h @@ -0,0 +1,2882 @@ +/** + * + * \file + * + * \brief WINC WLAN Application Interface. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef __M2M_WIFI_H__ +#define __M2M_WIFI_H__ + +/** \defgroup m2m_wifi WLAN + * + */ + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +#include "common/include/nm_common.h" +#include "driver/include/m2m_types.h" +#include "driver/source/nmdrv.h" + +#ifdef CONF_MGMT + + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +MACROS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/**@defgroup WlanEnums DataTypes + * @ingroup m2m_wifi + * @{*/ +/*! +@enum \ + tenuWifiFrameType + +@brief + Enumeration for Wi-Fi MAC frame type codes (2-bit) + The following types are used to identify the type of frame sent or received. + Each frame type constitutes a number of frame subtypes as defined in @ref tenuSubTypes to specify the exact type of frame. + Values are defined as per the IEEE 802.11 standard. + +@remarks + The following frame types are useful for advanced user usage when monitoring mode is used (defining @ref CONF_MGMT) + and the user application requires to monitor the frame transmission and reception. +@see + tenuSubTypes +*/ +typedef enum { + MANAGEMENT = 0x00, + /*!< Wi-Fi Management frame (Probe Req/Resp, Beacon, Association Req/Resp ...etc). + */ + CONTROL = 0x04, + /*!< Wi-Fi Control frame (eg. ACK frame). + */ + DATA_BASICTYPE = 0x08, + /*!< Wi-Fi Data frame. + */ + RESERVED = 0x0C, + + M2M_WIFI_FRAME_TYPE_ANY = 0xFF +/*!< Set monitor mode to receive any of the frames types +*/ +}tenuWifiFrameType; + + +/*! +@enum \ + tenuSubTypes + +@brief + Enumeration for Wi-Fi MAC Frame subtype code (6-bit). + The frame subtypes fall into one of the three frame type groups as defined in @ref tenuWifiFrameType + (MANAGEMENT, CONTROL & DATA). + Values are defined as per the IEEE 802.11 standard. +@remarks + The following sub-frame types are useful for advanced user usage when @ref CONF_MGMT is defined + and the application developer requires to monitor the frame transmission and reception. +@see + tenuWifiFrameType + tstrM2MWifiMonitorModeCtrl +*/ +typedef enum { + /*!< Sub-Types related to Management Sub-Types */ + ASSOC_REQ = 0x00, + ASSOC_RSP = 0x10, + REASSOC_REQ = 0x20, + REASSOC_RSP = 0x30, + PROBE_REQ = 0x40, + PROBE_RSP = 0x50, + BEACON = 0x80, + ATIM = 0x90, + DISASOC = 0xA0, + AUTH = 0xB0, + DEAUTH = 0xC0, + ACTION = 0xD0, +/**@{*/ + /* Sub-Types related to Control */ + PS_POLL = 0xA4, + RTS = 0xB4, + CTS = 0xC4, + ACK = 0xD4, + CFEND = 0xE4, + CFEND_ACK = 0xF4, + BLOCKACK_REQ = 0x84, + BLOCKACK = 0x94, +/**@{*/ + /* Sub-Types related to Data */ + DATA = 0x08, + DATA_ACK = 0x18, + DATA_POLL = 0x28, + DATA_POLL_ACK = 0x38, + NULL_FRAME = 0x48, + CFACK = 0x58, + CFPOLL = 0x68, + CFPOLL_ACK = 0x78, + QOS_DATA = 0x88, + QOS_DATA_ACK = 0x98, + QOS_DATA_POLL = 0xA8, + QOS_DATA_POLL_ACK = 0xB8, + QOS_NULL_FRAME = 0xC8, + QOS_CFPOLL = 0xE8, + QOS_CFPOLL_ACK = 0xF8, + M2M_WIFI_FRAME_SUB_TYPE_ANY = 0xFF + /*!< Set monitor mode to receive any of the frames types + */ +}tenuSubTypes; + + +/*! +@enum \ + tenuInfoElementId + +@brief + Enumeration for the Wi-Fi Information Element(IE) IDs, which indicates the specific type of IEs. + IEs are management frame information included in management frames. + Values are defined as per the IEEE 802.11 standard. + +*/ +typedef enum { + ISSID = 0, + /*!< Service Set Identifier (SSID) + */ + ISUPRATES = 1, + /*!< Supported Rates + */ + IFHPARMS = 2, + /*!< FH parameter set + */ + IDSPARMS = 3, + /*!< DS parameter set + */ + ICFPARMS = 4, + /*!< CF parameter set + */ + ITIM = 5, + /*!< Traffic Information Map + */ + IIBPARMS = 6, + /*!< IBSS parameter set + */ + ICOUNTRY = 7, + /*!< Country element. + */ + IEDCAPARAMS = 12, + /*!< EDCA parameter set + */ + ITSPEC = 13, + /*!< Traffic Specification + */ + ITCLAS = 14, + /*!< Traffic Classification + */ + ISCHED = 15, + /*!< Schedule. + */ + ICTEXT = 16, + /*!< Challenge Text + */ + IPOWERCONSTRAINT = 32, + /*!< Power Constraint. + */ + IPOWERCAPABILITY = 33, + /*!< Power Capability + */ + ITPCREQUEST = 34, + /*!< TPC Request + */ + ITPCREPORT = 35, + /*!< TPC Report + */ + ISUPCHANNEL = 36, + /* Supported channel list + */ + ICHSWANNOUNC = 37, + /*!< Channel Switch Announcement + */ + IMEASUREMENTREQUEST = 38, + /*!< Measurement request + */ + IMEASUREMENTREPORT = 39, + /*!< Measurement report + */ + IQUIET = 40, + /*!< Quiet element Info + */ + IIBSSDFS = 41, + /*!< IBSS DFS + */ + IERPINFO = 42, + /*!< ERP Information + */ + ITSDELAY = 43, + /*!< TS Delay + */ + ITCLASPROCESS = 44, + /*!< TCLAS Processing + */ + IHTCAP = 45, + /*!< HT Capabilities + */ + IQOSCAP = 46, + /*!< QoS Capability + */ + IRSNELEMENT = 48, + /*!< RSN Information Element + */ + IEXSUPRATES = 50, + /*!< Extended Supported Rates + */ + IEXCHSWANNOUNC = 60, + /*!< Extended Ch Switch Announcement + */ + IHTOPERATION = 61, + /*!< HT Information + */ + ISECCHOFF = 62, + /*!< Secondary Channel Offset + */ + I2040COEX = 72, + /*!< 20/40 Coexistence IE + */ + I2040INTOLCHREPORT = 73, + /*!< 20/40 Intolerant channel report + */ + IOBSSSCAN = 74, + /*!< OBSS Scan parameters + */ + IEXTCAP = 127, + /*!< Extended capability + */ + IWMM = 221, + /*!< WMM parameters + */ + IWPAELEMENT = 221 + /*!< WPA Information Element + */ +}tenuInfoElementId; + + +/*! +@struct \ + tenuWifiCapability + +@brief + Enumeration for capability Information field bit. + The value of the capability information field from the 802.11 management frames received by the wireless LAN interface. + Defining the capabilities of the Wi-Fi system. Values are defined as per the IEEE 802.11 standard. + +@details + Capabilities:- + ESS/IBSS : Defines whether a frame is coming from an AP or not. + POLLABLE : CF Poll-able + POLLREQ : Request to be polled + PRIVACY : WEP encryption supported + SHORTPREAMBLE : Short Preamble is supported + SHORTSLOT : Short Slot is supported + PBCC :PBCC + CHANNELAGILITY :Channel Agility + SPECTRUM_MGMT :Spectrum Management + DSSS_OFDM : DSSS-OFDM +*/ +typedef enum{ + ESS = 0x01, + /*!< ESS capability + */ + IBSS = 0x02, + /*!< IBSS mode + */ + POLLABLE = 0x04, + /*!< CF Pollable + */ + POLLREQ = 0x08, + /*!< Request to be polled + */ + PRIVACY = 0x10, + /*!< WEP encryption supported + */ + SHORTPREAMBLE = 0x20, + /*!< Short Preamble is supported + */ + SHORTSLOT = 0x400, + /*!< Short Slot is supported + */ + PBCC = 0x40, + /*!< PBCC + */ + CHANNELAGILITY = 0x80, + /*!< Channel Agility + */ + SPECTRUM_MGMT = 0x100, + /*!< Spectrum Management + */ + DSSS_OFDM = 0x2000 + /*!< DSSS-OFDM + */ +}tenuWifiCapability; + + +#endif + +/*! +@typedef \ + tpfAppWifiCb + +@brief + Wi-Fi's main callback function handler, for handling the M2M_WIFI events received on the Wi-Fi interface. + Such notifications are received in response to Wi-Fi/P2P operations such as @ref m2m_wifi_request_scan, + @ref m2m_wifi_connect. + Wi-Fi/P2P operations are implemented in an asynchronous mode, and all incoming information/status + are to be handled through this callback function when the corresponding notification is received. + Applications are expected to assign this wi-fi callback function by calling @ref m2m_wifi_init +@param [in] u8MsgType + Type of notifications. Possible types are: + /ref M2M_WIFI_RESP_CON_STATE_CHANGED + /ref M2M_WIFI_RESP_CONN_INFO + /ref M2M_WIFI_REQ_DHCP_CONF + /ref M2M_WIFI_REQ_WPS + /ref M2M_WIFI_RESP_IP_CONFLICT + /ref M2M_WIFI_RESP_SCAN_DONE + /ref M2M_WIFI_RESP_SCAN_RESULT + /ref M2M_WIFI_RESP_CURRENT_RSSI + /ref M2M_WIFI_RESP_CLIENT_INFO + /ref M2M_WIFI_RESP_PROVISION_INFO + /ref M2M_WIFI_RESP_DEFAULT_CONNECT + + In case Ethernet/Bypass mode is defined : + @ref M2M_WIFI_RESP_ETHERNET_RX_PACKET + + In case monitoring mode is used: + @ref M2M_WIFI_RESP_WIFI_RX_PACKET + +@param [in] pvMsg + A pointer to a buffer containing the notification parameters (if any). It should be + casted to the correct data type corresponding to the notification type. + +@see + tstrM2mWifiStateChanged + tstrM2MWPSInfo + tstrM2mScanDone + tstrM2mWifiscanResult +*/ +typedef void (*tpfAppWifiCb) (uint8 u8MsgType, void * pvMsg); + +/*! +@typedef \ + tpfAppEthCb + +@brief + ETHERNET (bypass mode) notification callback function receiving Bypass mode events as defined in + the Wi-Fi responses enumeration @ref tenuM2mStaCmd. + +@param [in] u8MsgType + Type of notification. Possible types are: + - [M2M_WIFI_RESP_ETHERNET_RX_PACKET](@ref M2M_WIFI_RESP_ETHERNET_RX_PACKET) + +@param [in] pvMsg + A pointer to a buffer containing the notification parameters (if any). It should be + casted to the correct data type corresponding to the notification type. + For example, it could be a pointer to the buffer holding the received frame in case of @ref M2M_WIFI_RESP_ETHERNET_RX_PACKET + event. + +@param [in] pvControlBuf + A pointer to control buffer describing the accompanied message. + To be casted to @ref tstrM2mIpCtrlBuf in case of @ref M2M_WIFI_RESP_ETHERNET_RX_PACKET event. + +@warning + Make sure that the application defines @ref ETH_MODE. + +@see + m2m_wifi_init + +*/ +typedef void (*tpfAppEthCb) (uint8 u8MsgType, void * pvMsg,void * pvCtrlBuf); + +/*! +@typedef \ + tpfAppMonCb + +@brief + Wi-Fi monitoring mode callback function. This function delivers all received wi-Fi packets through the Wi-Fi interface. + Applications requiring to operate in the monitoring should call the asynchronous function m2m_wifi_enable_monitoring_mode + and expect to receive the Wi-Fi packets through this callback function, when the event is received. + To disable the monitoring mode a call to @ref m2m_wifi_disable_monitoring_mode should be made. +@param [in] pstrWifiRxPacket + Pointer to a structure holding the Wi-Fi packet header parameters. + +@param [in] pu8Payload + Pointer to the buffer holding the Wi-Fi packet payload information required by the application starting from the + defined OFFSET by the application (when calling m2m_wifi_enable_monitoring_mode). + Could hold a value of NULL, if the application does not need any data from the payload. + +@param [in] u16PayloadSize + The size of the payload in bytes. + +@see + m2m_wifi_enable_monitoring_mode,m2m_wifi_init + +@warning + u16PayloadSize should not exceed the buffer size given through m2m_wifi_enable_monitoring_mode. + +*/ +typedef void (*tpfAppMonCb) (tstrM2MWifiRxPacketInfo *pstrWifiRxPacket, uint8 * pu8Payload, uint16 u16PayloadSize); + +/** +@struct \ + tstrEthInitParam + +@brief + Structure to hold Ethernet interface parameters. + Structure is to be defined and have its attributes set,based on the application's functionality before + a call is made to initialize the Wi-Fi operations by calling the @ref m2m_wifi_init function. + This structure is part of the Wi-Fi configuration structure @ref tstrWifiInitParam. + Applications shouldn't need to define this structure, if the bypass mode is not defined. + +@see + tpfAppEthCb + tpfAppWifiCb + m2m_wifi_init + +@warning + Make sure that application defines @ref ETH_MODE before using @ref tstrEthInitParam. + +*/ +typedef struct { + tpfAppWifiCb pfAppWifiCb; + /*!< + Callback for wifi notifications. + */ + tpfAppEthCb pfAppEthCb; + /*!< + Callback for Ethernet interface. + */ + uint8 * au8ethRcvBuf; + /*!< + Pointer to Receive Buffer of Ethernet Packet + */ + uint16 u16ethRcvBufSize; + /*!< + Size of Receive Buffer for Ethernet Packet + */ + uint8 u8EthernetEnable; + /*!< + Enable Ethernet mode flag + */ + uint8 __PAD8__; + /*!< + Padding + */ +} tstrEthInitParam; +/*! +@struct \ + tstrM2mIpCtrlBuf + +@brief + Structure holding the incoming buffer's data size information, indicating the data size of the buffer and the remaining buffer's data size . + The data of the buffer which holds the packet sent to the host when in the bypass mode, is placed in the @ref tstrEthInitParam structure in the + @ref au8ethRcvBuf attribute. This following information is retrieved in the host when an event @ref M2M_WIFI_RESP_ETHERNET_RX_PACKET is received in + the Wi-Fi callback function @ref tpfAppWifiCb. + + The application is expected to use this structure's information to determine if there is still incoming data to be received from the firmware. + + @see + tpfAppEthCb + tstrEthInitParam + + @warning + Make sure that ETHERNET/bypass mode is defined before using @ref tstrM2mIpCtrlBuf + + */ +typedef struct{ + uint16 u16DataSize; + /*!< + Size of the received data in bytes. + */ + uint16 u16RemainigDataSize; + /*!< + Size of the remaining data bytes to be delivered to host. + */ +} tstrM2mIpCtrlBuf; + + +/** +@struct \ + tstrWifiInitParam + +@brief + Structure, holding the Wi-fi configuration attributes such as the wi-fi callback , monitoring mode callback and Ethernet parameter initialization structure. + Such configuration parameters are required to be set before calling the wi-fi initialization function @ref m2m_wifi_init. + @ref pfAppWifiCb attribute must be set to handle the wi-fi callback operations. + @ref pfAppMonCb attribute, is optional based on whether the application requires the monitoring mode configuration, and can there not + be set before the initialization. + @ref strEthInitParam structure, is another optional configuration based on whether the bypass mode is set. + + @see + tpfAppEthCb + tpfAppMonCb + tstrEthInitParam + +*/ +typedef struct { + tpfAppWifiCb pfAppWifiCb; + /*!< + Callback for Wi-Fi notifications. + */ + tpfAppMonCb pfAppMonCb; + /*!< + Callback for monitoring interface. + */ + tstrEthInitParam strEthInitParam ; + /*!< + Structure to hold Ethernet interface parameters. + */ + +} tstrWifiInitParam; + //@} +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +FUNCTION PROTOTYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/** \defgroup WLANAPI Function + * @ingroup m2m_wifi + */ +#ifdef __cplusplus + extern "C" { +#endif + /** @defgroup WiFiDownloadFn m2m_wifi_download_mode + * @ingroup WLANAPI + * Synchronous download mode entry function that prepares the WINC board to enter the download mode, ready for the firmware or certificate download. +* The WINC board is prepared for download, through initializations for the WINC driver including bus initializations and interrupt enabling, it also halts the chip, to allow for the firmware downloads. +* Firmware can be downloaded through a number of interfaces, UART, I2C and SPI. + */ + /**@{*/ +/*! +@fn \ + NMI_API void m2m_wifi_download_mode(void); +@brief Prepares the WINC broard before downloading any data (Firmware, Certificates .. etc) + + This function should called before starting to download any data to the WINC board. The WINC board is prepared for download, through initializations for the WINC driver including bus initializations + and interrupt enabling, it also halts the chip, to allow for the firmware downloads Firmware can be downloaded through a number of interfaces, UART, I2C and SPI. + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_download_mode(void); + + /**@}*/ + /** @defgroup WifiInitFn m2m_wifi_init + * @ingroup WLANAPI + * Synchronous initialization function for the WINC driver. This function initializes the driver by, registering the call back function for M2M_WIFI layer(also the call back function for bypass mode/monitoring mode if defined), + * initializing the host interface layer and the bus interfaces. + * Wi-Fi callback registering is essential to allow the handling of the events received, in response to the asynchronous Wi-Fi operations. + +Following are the possible Wi-Fi events that are expected to be received through the call back function(provided by the application) to the M2M_WIFI layer are : + + @ref M2M_WIFI_RESP_CON_STATE_CHANGED \n + @ref M2M_WIFI_RESP_CONN_INFO \n + @ref M2M_WIFI_REQ_DHCP_CONF \n + @ref M2M_WIFI_REQ_WPS \n + @ref M2M_WIFI_RESP_IP_CONFLICT \n + @ref M2M_WIFI_RESP_SCAN_DONE \n + @ref M2M_WIFI_RESP_SCAN_RESULT \n + @ref M2M_WIFI_RESP_CURRENT_RSSI \n + @ref M2M_WIFI_RESP_CLIENT_INFO \n + @ref M2M_WIFI_RESP_PROVISION_INFO \n + @ref M2M_WIFI_RESP_DEFAULT_CONNECT \n + Example: \n + In case Bypass mode is defined : \n + @ref M2M_WIFI_RESP_ETHERNET_RX_PACKET + + In case Monitoring mode is used: \n + @ref M2M_WIFI_RESP_WIFI_RX_PACKET + + Any application using the WINC driver must call this function at the start of its main function. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_init(tstrWifiInitParam * pWifiInitParam); + +@param [in] pWifiInitParam + This is a pointer to the @ref tstrWifiInitParam structure which holds the pointer to the application WIFI layer call back function, + monitoring mode call back and @ref tstrEthInitParam structure containing bypass mode parameters. + +@brief Initialize the WINC host driver. + This function initializes the driver by, registering the call back function for M2M_WIFI layer(also the call back function for bypass mode/monitoring mode if defined), + initializing the host interface layer and the bus interfaces. + +@pre + Prior to this function call, The application should initialize the BSP using "nm_bsp_init". + Also,application users must provide a call back function responsible for receiving all the WI-FI events that are received on the M2M_WIFI layer. + +@warning + Failure to successfully complete function indicates that the driver couldn't be initialized and a fatal error will prevent the application from proceeding. + +@see + nm_bsp_init + m2m_wifi_deinit + tenuM2mStaCmd + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_init(tstrWifiInitParam * pWifiInitParam); + /**@}*/ + /** @defgroup WifiDeinitFn m2m_wifi_deinit + * @ingroup WLANAPI + * Synchronous de-initialization function to the WINC1500 driver. De-initializes the host interface and frees any resources used by the M2M_WIFI layer. + * This function must be called in the application closing phase to ensure that all resources have been correctly released. No arguments are expected to be passed in. + */ +/**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_deinit(void * arg); + +@param [in] arg + Generic argument. Not used in the current implementation. +@brief Deinitilize the WINC driver and host enterface. + This function must be called at the De-initilization stage of the application. Generally This function should be the last function before switching off the chip + and it should be followed only by "nm_bsp_deinit" function call. Every function call of "nm_wifi_init" should be matched with a call to nm_wifi_deinit. +@see + nm_bsp_deinit + nm_wifi_init + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_deinit(void * arg); + + /**@}*/ +/** @defgroup WifiHandleEventsFn m2m_wifi_handle_events +* @ingroup WLANAPI +* Synchronous M2M event handler function, responsible for handling interrupts received from the WINC firmware. +* Application developers should call this function periodically in-order to receive the events that are to be handled by the +* callback functions implemented by the application. + + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_handle_events(void * arg); + +@pre + Prior to receiving events, the WINC driver should have been successfully initialized by calling the @ref m2m_wifi_init function. + +@brief Handle the varios events received from the WINC board. + Whenever an event happen in the WINC board (e.g. Connection, Disconnection , DHCP .. etc), WINC will interrupt the host to let it know that a new + event has occured. The host driver will attempt to handle these events whenever the host driver decides to do that by calling the "m2m_wifi_handle_events" function. + It's mandatory to call this function periodically and independantly of any other condition. It's ideal to include this function in the main and the most frequent loop of the + host application. +@warning + Failure to successfully complete this function indicates bus errors and hence a fatal error that will prevent the application from proceeding. + +@return + The function returns @ref M2M_SUCCESS for successful interrupt handling and a negative value otherwise. +*/ + +NMI_API sint8 m2m_wifi_handle_events(void * arg); + + /**@}*/ +/** @defgroup WifiSendCRLFn m2m_wifi_send_crl +* @ingroup WLANAPI +* Asynchronous API that notifies the WINC with the Certificate Revocation List to be used for TLS. + + */ + /**@{*/ +/*! +@fn \ + sint8 m2m_wifi_send_crl(tstrTlsCrlInfo* pCRL); + +@brief + Asynchronous API that notifies the WINC with the Certificate Revocation List. + +@param [in] pCRL + Pointer to the structure containing certificate revocation list details. + +@return + The function returns @ref M2M_SUCCESS if the command has been successfully queued to the WINC, + and a negative value otherwise. +*/ + +sint8 m2m_wifi_send_crl(tstrTlsCrlInfo* pCRL); + + /**@}*/ +/** @defgroup WifiDefaultConnectFn m2m_wifi_default_connect + * @ingroup WLANAPI + * Asynchronous Wi-Fi connection function. An application calling this function will cause the firmware to correspondingly connect to the last successfully connected AP from the cached connections. + * A failure to connect will result in a response of @ref M2M_WIFI_RESP_DEFAULT_CONNECT indicating the connection error as defined in the structure @ref tstrM2MDefaultConnResp. + * Possible errors are: + * The connection list is empty @ref M2M_DEFAULT_CONN_EMPTY_LIST or a mismatch for the saved AP name @ref M2M_DEFAULT_CONN_SCAN_MISMATCH. + * only difference between this function and @ref m2m_wifi_connect, is the connection parameters. + * Connection using this function is expected to connect using cached connection parameters. + + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_default_connect(void); + +@pre + Prior to connecting, the WINC driver should have been successfully initialized by calling the @ref m2m_wifi_init function. + +@brief Connect to the last successfully connected AP from the cached connections. + +@warning + This function must be called in station mode only. + It's important to note that successful completion of a call to m2m_wifi_default_connect() does not guarantee success of the WIFI connection, + and a negative return value indicates only locally-detected errors. + +@see + m2m_wifi_connect + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + +*/ +NMI_API sint8 m2m_wifi_default_connect(void); + /**@}*/ +/** @defgroup WifiConnectFn m2m_wifi_connect + * @ingroup WLANAPI + * Asynchronous wi-fi connection function to a specific AP. Prior to a successful connection, the application must define the SSID of the AP, the security type, + * the authentication information parameters and the channel number to which the connection will be established. + * The connection status is known when a response of @ref M2M_WIFI_RESP_CON_STATE_CHANGED is received based on the states defined in @ref tenuM2mConnState, + * successful connection is defined by @ref M2M_WIFI_CONNECTED +* + * The only difference between this function and @ref m2m_wifi_default_connect, is the connection parameters. + * Connection using this function is expected to be made to a specific AP and to a specified channel. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_connect(char *pcSsid, uint8 u8SsidLen, uint8 u8SecType, void *pvAuthInfo, uint16 u16Ch); + +@param [in] pcSsid + A buffer holding the SSID corresponding to the requested AP. + +@param [in] u8SsidLen + Length of the given SSID (not including the NULL termination). + A length less than ZERO or greater than the maximum defined SSID @ref M2M_MAX_SSID_LEN will result in a negative error + @ref M2M_ERR_FAIL. + +@param [in] u8SecType + Wi-Fi security type security for the network. It can be one of the following types: + -@ref M2M_WIFI_SEC_OPEN + -@ref M2M_WIFI_SEC_WEP + -@ref M2M_WIFI_SEC_WPA_PSK + -@ref M2M_WIFI_SEC_802_1X + A value outside these possible values will result in a negative return error @ref M2M_ERR_FAIL. + +@param [in] pvAuthInfo + Authentication parameters required for completing the connection. It is type is based on the Security type. + If the authentication parameters are NULL or are greater than the maximum length of the authentication parameters length as defined by + @ref M2M_MAX_PSK_LEN a negative error will return @ref M2M_ERR_FAIL(-12) indicating connection failure. + +@param [in] u16Ch + Wi-Fi channel number as defined in @ref tenuM2mScanCh enumeration. + Channel number greater than @ref M2M_WIFI_CH_14 returns a negative error @ref M2M_ERR_FAIL(-12). + Except if the value is M2M_WIFI_CH_ALL(255), since this indicates that the firmware should scan all channels to find the SSID requested to connect to. + Failure to find the connection match will return a negative error @ref M2M_DEFAULT_CONN_SCAN_MISMATCH. +@pre + Prior to a successful connection request, the Wi-Fi driver must have been successfully initialized through the call of the @ref @m2m_wifi_init function +@see + tuniM2MWifiAuth + tstr1xAuthCredentials + tstrM2mWifiWepParams + +@warning + -This function must be called in station mode only. + -Successful completion of this function does not guarantee success of the WIFI connection, and + a negative return value indicates only locally-detected errors. + +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + +*/ +NMI_API sint8 m2m_wifi_connect(char *pcSsid, uint8 u8SsidLen, uint8 u8SecType, void *pvAuthInfo, uint16 u16Ch); + /**@}*/ +/** @defgroup WifiConnectFn m2m_wifi_connect_sc + * @ingroup WLANAPI + * Asynchronous wi-fi connection function to a specific AP. Prior to a successful connection, the application developers must know the SSID of the AP, the security type, + * the authentication information parameters and the channel number to which the connection will be established.this API allows the user to choose + * whether to + * The connection status is known when a response of @ref M2M_WIFI_RESP_CON_STATE_CHANGED is received based on the states defined in @ref tenuM2mConnState, + * successful connection is defined by @ref M2M_WIFI_CONNECTED + * The only difference between this function and @ref m2m_wifi_connect, is the option to save the acess point info ( SSID, password...etc) or not. + * Connection using this function is expected to be made to a specific AP and to a specified channel. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_connect_sc(char *pcSsid, uint8 u8SsidLen, uint8 u8SecType, void *pvAuthInfo, uint16 u16Ch,uint8 u8SaveCred); + +@param [in] pcSsid + A buffer holding the SSID corresponding to the requested AP. + +@param [in] u8SsidLen + Length of the given SSID (not including the NULL termination). + A length less than ZERO or greater than the maximum defined SSID @ref M2M_MAX_SSID_LEN will result in a negative error + @ref M2M_ERR_FAIL. + +@param [in] u8SecType + Wi-Fi security type security for the network. It can be one of the following types: + -@ref M2M_WIFI_SEC_OPEN + -@ref M2M_WIFI_SEC_WEP + -@ref M2M_WIFI_SEC_WPA_PSK + -@ref M2M_WIFI_SEC_802_1X + A value outside these possible values will result in a negative return error @ref M2M_ERR_FAIL. + +@param [in] pvAuthInfo + Authentication parameters required for completing the connection. It is type is based on the Security type. + If the authentication parameters are NULL or are greater than the maximum length of the authentication parameters length as defined by + @ref M2M_MAX_PSK_LEN a negative error will return @ref M2M_ERR_FAIL(-12) indicating connection failure. + +@param [in] u16Ch + Wi-Fi channel number as defined in @ref tenuM2mScanCh enumeration. + Channel number greater than @ref M2M_WIFI_CH_14 returns a negative error @ref M2M_ERR_FAIL(-12). + Except if the value is M2M_WIFI_CH_ALL(255), since this indicates that the firmware should scan all channels to find the SSID requested to connect to. + Failure to find the connection match will return a negative error @ref M2M_DEFAULT_CONN_SCAN_MISMATCH. + +@param [in] u8NoSaveCred + Option to store the acess point SSID and password into the WINC flash memory or not. + +@pre + Prior to a successful connection request, the wi-fi driver must have been successfully initialized through the call of the @ref @m2m_wifi_init function +@see + tuniM2MWifiAuth + tstr1xAuthCredentials + tstrM2mWifiWepParams + +@warning + -This function must be called in station mode only. + -Successful completion of this function does not guarantee success of the WIFI connection, and + a negative return value indicates only locally-detected errors. + +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + +*/ + NMI_API sint8 m2m_wifi_connect_sc(char *pcSsid, uint8 u8SsidLen, uint8 u8SecType, void *pvAuthInfo, uint16 u16Ch, uint8 u8SaveCred); + /**@}*/ +/** @defgroup WifiDisconnectFn m2m_wifi_disconnect + * @ingroup WLANAPI + * Synchronous wi-fi disconnection function, requesting a Wi-Fi disconnection from the currently connected AP. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_disconnect(void); + +@pre + Disconnection request must be made to a successfully connected AP. If the WINC is not in the connected state, a call to this function will hold insignificant. + +@brief Request a Wi-Fi disconnect from the currently connected AP. + After the Disconnect is complete the driver should recieve a response of @ref M2M_WIFI_RESP_CON_STATE_CHANGED based on the states defined + in @ref tenuM2mConnState, successful disconnection is defined by @ref M2M_WIFI_DISCONNECTED . +@warning + This function must be called in station mode only. + +@see + m2m_wifi_connect + m2m_wifi_default_connect + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_disconnect(void); + + /**@}*/ +/** @defgroup StartProvisionModeFn m2m_wifi_start_provision_mode + * @ingroup WLANAPI + * Asynchronous Wi-Fi provisioning function, which starts the WINC HTTP PROVISIONING mode. + The function triggers the WINC to activate the Wi-Fi AP (HOTSPOT) mode with the passed configuration parameters and then starts the + HTTP Provision WEB Server. + The provisioning status is returned in an event @ref M2M_WIFI_RESP_PROVISION_INFO + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_start_provision_mode(tstrM2MAPConfig *pstrAPConfig, char *pcHttpServerDomainName, uint8 bEnableHttpRedirect); + +@param [in] pstrAPConfig + AP configuration parameters as defined in @ref tstrM2MAPConfig configuration structure. + A NULL value passed in, will result in a negative error @ref M2M_ERR_FAIL. + +@param [in] pcHttpServerDomainName + Domain name of the HTTP Provision WEB server which others will use to load the provisioning Home page. + The domain name can have one of the following 3 forms: + 1- "wincprov.com" + 2- "http://wincprov.com" + 3- "https://wincprov.com" + The forms 1 and 2 are equivalent, they both will start a plain http server, while form 3 + will start a secure HTTP provisioning Session (HTTP over SSL connection). + +@param [in] bEnableHttpRedirect + A flag to enable/disable the HTTP redirect feature. If Secure provisioning is enabled (i.e. the server + domain name uses "https" prefix) this flag is ignored (no meaning for redirect in HTTPS). + Possible values are: + - ZERO DO NOT Use HTTP Redirect. In this case the associated device could open the provisioning page ONLY when + the HTTP Provision URL of the WINC HTTP Server is correctly written on the browser. + - Non-Zero value Use HTTP Redirect. In this case, all http traffic (http://URL) from the associated + device (Phone, PC, ...etc) will be redirected to the WINC HTTP Provisioning Home page. + +@pre + - A Wi-Fi notification callback of type @ref tpfAppWifiCb MUST be implemented and registered at startup. Registering the callback + is done through passing it to the initialization @ref m2m_wifi_init function. + - The event @ref M2M_WIFI_RESP_CONN_INFO must be handled in the callback to receive the requested connection info. + +@see + tpfAppWifiCb + m2m_wifi_init + M2M_WIFI_RESP_PROVISION_INFO + m2m_wifi_stop_provision_mode + tstrM2MAPConfig + +@warning + DO Not use ".local" in the pcHttpServerDomainName. + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + +\section Example + The example demonstrates a code snippet for how provisioning is triggered and the response event received accordingly. +@code + #include "m2m_wifi.h" + #include "m2m_types.h" + + + void wifi_event_cb(uint8 u8WiFiEvent, void * pvMsg) + { + switch(u8WiFiEvent) + { + case M2M_WIFI_RESP_PROVISION_INFO: + { + tstrM2MProvisionInfo *pstrProvInfo = (tstrM2MProvisionInfo*)pvMsg; + if(pstrProvInfo->u8Status == M2M_SUCCESS) + { + m2m_wifi_connect((char*)pstrProvInfo->au8SSID, (uint8)strlen(pstrProvInfo->au8SSID), pstrProvInfo->u8SecType, + pstrProvInfo->au8Password, M2M_WIFI_CH_ALL); + + printf("PROV SSID : %s\n",pstrProvInfo->au8SSID); + printf("PROV PSK : %s\n",pstrProvInfo->au8Password); + } + else + { + printf("(ERR) Provisioning Failed\n"); + } + } + break; + + default: + break; + } + } + + int main() + { + tstrWifiInitParam param; + + param.pfAppWifiCb = wifi_event_cb; + if(!m2m_wifi_init(¶m)) + { + tstrM2MAPConfig apConfig; + uint8 bEnableRedirect = 1; + + strcpy(apConfig.au8SSID, "WINC_SSID"); + apConfig.u8ListenChannel = 1; + apConfig.u8SecType = M2M_WIFI_SEC_OPEN; + apConfig.u8SsidHide = 0; + + // IP Address + apConfig.au8DHCPServerIP[0] = 192; + apConfig.au8DHCPServerIP[1] = 168; + apConfig.au8DHCPServerIP[2] = 1; + apConfig.au8DHCPServerIP[0] = 1; + + m2m_wifi_start_provision_mode(&apConfig, "atmelwincconf.com", bEnableRedirect); + + while(1) + { + m2m_wifi_handle_events(NULL); + } + } + } + +@endcode +*/ +NMI_API sint8 m2m_wifi_start_provision_mode(tstrM2MAPConfig *pstrAPConfig, char *pcHttpServerDomainName, uint8 bEnableHttpRedirect); + /**@}*/ +/** @defgroup StopProvisioningModeFn m2m_wifi_stop_provision_mode + * @ingroup WLANAPI + * Synchronous provision termination function which stops the provision mode if it is active. + */ + /**@{*/ +/*! +@fn \ + sint8 m2m_wifi_stop_provision_mode(void); + +@pre + An active provisioning session must be active before it is terminated through this function. +@see + m2m_wifi_start_provision_mode + +@return + The function returns ZERO for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_stop_provision_mode(void); + /**@}*/ +/** @defgroup GetConnectionInfoFn m2m_wifi_get_connection_info + * @ingroup WLANAPI + * Asynchronous connection status retrieval function, retrieves the status information of the currently connected AP. The result is passed to the Wi-Fi notification callback +* through the event @ref M2M_WIFI_RESP_CONN_INFO. Connection information is retrieved from the structure @ref tstrM2MConnInfo. + */ + /**@{*/ +/*! +@fn \ + sint8 m2m_wifi_get_connection_info(void); + +@brief + Retrieve the current Connection information. The result is passed to the Wi-Fi notification callback + with [M2M_WIFI_RESP_CONN_INFO](@ref M2M_WIFI_RESP_CONN_INFO). +@pre + - A Wi-Fi notification callback of type @ref tpfAppWifiCb MUST be implemented and registered at startup. Registering the callback + is done through passing it to the initialization @ref m2m_wifi_init function. + - The event @ref M2M_WIFI_RESP_CONN_INFO must be handled in the callback to receive the requested connection info. + + Connection Information retrieved: + + + -Connection Security + -Connection RSSI + -Remote MAC address + -Remote IP address + + and in case of WINC station mode the SSID of the AP is also retrieved. +@warning + -In case of WINC AP mode or P2P mode, ignore the SSID field (NULL string). +@sa + M2M_WIFI_RESP_CONN_INFO, + tstrM2MConnInfo +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +\section Example + The code snippet shows an example of how wi-fi connection information is retrieved . +@code + + #include "m2m_wifi.h" + #include "m2m_types.h" + + + void wifi_event_cb(uint8 u8WiFiEvent, void * pvMsg) + { + switch(u8WiFiEvent) + { + case M2M_WIFI_RESP_CONN_INFO: + { + tstrM2MConnInfo *pstrConnInfo = (tstrM2MConnInfo*)pvMsg; + + printf("CONNECTED AP INFO\n"); + printf("SSID : %s\n",pstrConnInfo->acSSID); + printf("SEC TYPE : %d\n",pstrConnInfo->u8SecType); + printf("Signal Strength : %d\n", pstrConnInfo->s8RSSI); + printf("Local IP Address : %d.%d.%d.%d\n", + pstrConnInfo->au8IPAddr[0] , pstrConnInfo->au8IPAddr[1], pstrConnInfo->au8IPAddr[2], pstrConnInfo->au8IPAddr[3]); + } + break; + + case M2M_WIFI_REQ_DHCP_CONF: + { + // Get the current AP information. + m2m_wifi_get_connection_info(); + } + break; + default: + break; + } + } + + int main() + { + tstrWifiInitParam param; + + param.pfAppWifiCb = wifi_event_cb; + if(!m2m_wifi_init(¶m)) + { + // connect to the default AP + m2m_wifi_default_connect(); + + while(1) + { + m2m_wifi_handle_events(NULL); + } + } + } + +@endcode +*/ +NMI_API sint8 m2m_wifi_get_connection_info(void); + /**@}*/ +/** @defgroup WifiSetMacAddFn m2m_wifi_set_mac_address + * @ingroup WLANAPI + * Synchronous MAC address assigning to the NMC1500. It is used for non-production SW. Assign MAC address to the WINC device. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_set_mac_address(uint8 au8MacAddress[6]); + +@brief Assign a MAC address to the WINC board. + This function override the already assigned MAC address of the WINC board with a user provided one. This is for experimental + use only and should never be used in the production SW. + +@param [in] au8MacAddress + MAC Address to be set to the WINC. + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_set_mac_address(uint8 au8MacAddress[6]); + + /**@}*/ +/** @defgroup WifiWpsFn m2m_wifi_wps + * @ingroup WLANAPI + * Asynchronous WPS triggering function. + * This function is called for the WINC to enter the WPS (Wi-Fi Protected Setup) mode. The result is passed to the Wi-Fi notification callback +* with the event @ref M2M_WIFI_REQ_WPS. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_wps(uint8 u8TriggerType,const char * pcPinNumber); + +@param [in] u8TriggerType + WPS Trigger method. Could be: + - [WPS_PIN_TRIGGER](@ref WPS_PIN_TRIGGER) Push button method + - [WPS_PBC_TRIGGER](@ref WPS_PBC_TRIGGER) Pin method + +@param [in] pcPinNumber + PIN number for WPS PIN method. It is not used if the trigger type is WPS_PBC_TRIGGER. It must follow the rules + stated by the WPS standard. + +@warning + This function is not allowed in AP or P2P modes. + +@pre + - A Wi-Fi notification callback of type (@ref tpfAppWifiCb MUST be implemented and registered at startup. Registering the callback + is done through passing it to the [m2m_wifi_init](@ref m2m_wifi_init). + - The event [M2M_WIFI_REQ_WPS](@ref M2M_WIFI_REQ_WPS) must be handled in the callback to receive the WPS status. + - The WINC device MUST be in IDLE or STA mode. If AP or P2P mode is active, the WPS will not be performed. + - The [m2m_wifi_handle_events](@ref m2m_wifi_handle_events) MUST be called periodically to receive the responses in the callback. +@see + tpfAppWifiCb + m2m_wifi_init + M2M_WIFI_REQ_WPS + tenuWPSTrigger + tstrM2MWPSInfo + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +\section Example + The code snippet shows an example of how Wi-Fi WPS is triggered . +@code + + #include "m2m_wifi.h" + #include "m2m_types.h" + + void wifi_event_cb(uint8 u8WiFiEvent, void * pvMsg) + { + switch(u8WiFiEvent) + { + case M2M_WIFI_REQ_WPS: + { + tstrM2MWPSInfo *pstrWPS = (tstrM2MWPSInfo*)pvMsg; + if(pstrWPS->u8AuthType != 0) + { + printf("WPS SSID : %s\n",pstrWPS->au8SSID); + printf("WPS PSK : %s\n",pstrWPS->au8PSK); + printf("WPS SSID Auth Type : %s\n",pstrWPS->u8AuthType == M2M_WIFI_SEC_OPEN ? "OPEN" : "WPA/WPA2"); + printf("WPS Channel : %d\n",pstrWPS->u8Ch + 1); + + // establish Wi-Fi connection + m2m_wifi_connect((char*)pstrWPS->au8SSID, (uint8)m2m_strlen(pstrWPS->au8SSID), + pstrWPS->u8AuthType, pstrWPS->au8PSK, pstrWPS->u8Ch); + } + else + { + printf("(ERR) WPS Is not enabled OR Timed out\n"); + } + } + break; + + default: + break; + } + } + + int main() + { + tstrWifiInitParam param; + + param.pfAppWifiCb = wifi_event_cb; + if(!m2m_wifi_init(¶m)) + { + // Trigger WPS in Push button mode. + m2m_wifi_wps(WPS_PBC_TRIGGER, NULL); + + while(1) + { + m2m_wifi_handle_events(NULL); + } + } + } + +@endcode +*/ +NMI_API sint8 m2m_wifi_wps(uint8 u8TriggerType,const char *pcPinNumber); + /**@}*/ +/** @defgroup WifiWpsDisableFn m2m_wifi_wps_disable + * @ingroup WLANAPI + * Disable the WINC1500 WPS operation. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_wps_disable(void); + +@pre WINC should be already in WPS mode using @ref m2m_wifi_wps + +@brief Stops the WPS ongoing session. + +@see + m2m_wifi_wps + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_wps_disable(void); + + /**@}*/ +/** @defgroup WifiP2PFn m2m_wifi_p2p + * @ingroup WLANAPI + * Asynchronous Wi-Fi direct (P2P) enabling mode function. + The WINC supports P2P in device listening mode ONLY (intent is ZERO). + The WINC P2P implementation does not support P2P GO (Group Owner) mode. + Active P2P devices (e.g. phones) could find the WINC in the search list. When a device is connected to WINC, a Wi-Fi notification event + @ref M2M_WIFI_RESP_CON_STATE_CHANGED is triggered. After a short while, the DHCP IP Address is obtained + and an event @ref M2M_WIFI_REQ_DHCP_CONF is triggered. Refer to the code examples for a more illustrative example. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_p2p(uint8 u8Channel); + +@param [in] u8Channel + P2P Listen RF channel. According to the P2P standard It must hold only one of the following values 1, 6 or 11. + +@pre + - A Wi-Fi notification callback of type @ref tpfAppWifiCb MUST be implemented and registered at initialization. Registering the callback + is done through passing it to the @ref m2m_wifi_init. + - The events @ref M2M_WIFI_RESP_CON_STATE_CHANGED and @ref M2M_WIFI_REQ_DHCP_CONF + must be handled in the callback. + - The @ref m2m_wifi_handle_events MUST be called to receive the responses in the callback. + +@warning + This function is not allowed in AP or STA modes. + +@see + tpfAppWifiCb + m2m_wifi_init + M2M_WIFI_RESP_CON_STATE_CHANGED + M2M_WIFI_REQ_DHCP_CONF + tstrM2mWifiStateChanged + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +\section Example + The code snippet shown an example of how the p2p mode operates. +@code + #include "m2m_wifi.h" + #include "m2m_types.h" + + void wifi_event_cb(uint8 u8WiFiEvent, void * pvMsg) + { + switch(u8WiFiEvent) + { + case M2M_WIFI_RESP_CON_STATE_CHANGED: + { + tstrM2mWifiStateChanged *pstrWifiState = (tstrM2mWifiStateChanged*)pvMsg; + M2M_INFO("Wifi State :: %s :: ErrCode %d\n", pstrWifiState->u8CurrState? "CONNECTED":"DISCONNECTED",pstrWifiState->u8ErrCode); + + // Do something + } + break; + + case M2M_WIFI_REQ_DHCP_CONF: + { + uint8 *pu8IPAddress = (uint8*)pvMsg; + + printf("P2P IP Address \"%u.%u.%u.%u\"\n",pu8IPAddress[0],pu8IPAddress[1],pu8IPAddress[2],pu8IPAddress[3]); + } + break; + + default: + break; + } + } + + int main() + { + tstrWifiInitParam param; + + param.pfAppWifiCb = wifi_event_cb; + if(!m2m_wifi_init(¶m)) + { + // Trigger P2P + m2m_wifi_p2p(M2M_WIFI_CH_1); + + while(1) + { + m2m_wifi_handle_events(NULL); + } + } + } + +@endcode + +*/ +NMI_API sint8 m2m_wifi_p2p(uint8 u8Channel); + /**@}*/ +/** @defgroup WifiP2PDisconnectFn m2m_wifi_p2p_disconnect + * @ingroup WLANAPI + * Disable the WINC1500 device Wi-Fi direct mode (P2P). + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_p2p_disconnect(void); +@pre + The p2p mode must have be enabled and active before a disconnect can be called. + +@see + m2m_wifi_p2p +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_p2p_disconnect(void); + /**@}*/ +/** @defgroup WifiEnableApFn m2m_wifi_enable_ap + * @ingroup WLANAPI + * Asynchronous Wi-FI hot-spot enabling function. + * The WINC supports AP mode operation with the following limitations: + - Only 1 STA could be associated at a time. + - Open and WEP are the only supported security types + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_enable_ap(CONST tstrM2MAPConfig* pstrM2MAPConfig); + +@param [in] pstrM2MAPConfig + A structure holding the AP configurations. + +@warning + This function is not allowed in P2P or STA modes. + +@pre + - A Wi-Fi notification callback of type @ref tpfAppWifiCb MUST be implemented and registered at initialization. Registering the callback + is done through passing it to the [m2m_wifi_init](@ref m2m_wifi_init). + - The event @ref M2M_WIFI_REQ_DHCP_CONF must be handled in the callback. + - The @ref m2m_wifi_handle_events MUST be called to receive the responses in the callback. + +@see + tpfAppWifiCb + tenuM2mSecType + m2m_wifi_init + M2M_WIFI_REQ_DHCP_CONF + tstrM2mWifiStateChanged + tstrM2MAPConfig + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +\section Example + The code snippet demonstrates how the AP mode is enabled after the driver is initialized in the application's main function and the handling + of the event @ref M2M_WIFI_REQ_DHCP_CONF, to indicate successful connection. +@code + #include "m2m_wifi.h" + #include "m2m_types.h" + + void wifi_event_cb(uint8 u8WiFiEvent, void * pvMsg) + { + switch(u8WiFiEvent) + { + case M2M_WIFI_REQ_DHCP_CONF: + { + uint8 *pu8IPAddress = (uint8*)pvMsg; + + printf("Associated STA has IP Address \"%u.%u.%u.%u\"\n",pu8IPAddress[0],pu8IPAddress[1],pu8IPAddress[2],pu8IPAddress[3]); + } + break; + + default: + break; + } + } + + int main() + { + tstrWifiInitParam param; + + param.pfAppWifiCb = wifi_event_cb; + if(!m2m_wifi_init(¶m)) + { + tstrM2MAPConfig apConfig; + + strcpy(apConfig.au8SSID, "WINC_SSID"); + apConfig.u8ListenChannel = 1; + apConfig.u8SecType = M2M_WIFI_SEC_OPEN; + apConfig.u8SsidHide = 0; + + // IP Address + apConfig.au8DHCPServerIP[0] = 192; + apConfig.au8DHCPServerIP[1] = 168; + apConfig.au8DHCPServerIP[2] = 1; + apConfig.au8DHCPServerIP[0] = 1; + + // Trigger AP + m2m_wifi_enable_ap(&apConfig); + + while(1) + { + m2m_wifi_handle_events(NULL); + } + } + } + +@endcode + +*/ +NMI_API sint8 m2m_wifi_enable_ap(CONST tstrM2MAPConfig* pstrM2MAPConfig); + /**@}*/ +/** @defgroup WifiDisableApFn m2m_wifi_disable_ap + * @ingroup WLANAPI + * Synchronous Wi-Fi hot-spot disabling function. Must be called only when the AP is enabled through the @ref m2m_wifi_enable_ap + * function. Otherwise the call to this function will not be useful. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_disable_ap(void); +@see + m2m_wifi_enable_ap +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_disable_ap(void); + /**@}*/ +/** @defgroup SetStaticIPFn m2m_wifi_set_static_ip + * @ingroup WLANAPI + * Synchronous static IP Address configuration function. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_set_static_ip(tstrM2MIPConfig * pstrStaticIPConf); + +@param [in] pstrStaticIPConf + Pointer to a structure holding the static IP Configurations (IP, + Gateway, subnet mask and DNS address). + +@pre The application must disable auto DHCP using @ref m2m_wifi_enable_dhcp before assigning a static IP address. + +@brief Assign a static IP address to the WINC board. + This function assigns a static IP address in case the AP doesn't have a DHCP server or in case the application wants to assign + a predefined known IP address. The user must take in mind that assigning a static IP address might result in an IP address + conflict. In case of an IP address conflict observed by the WINC board the user will get a response of @ref M2M_WIFI_RESP_IP_CONFLICT + in the wifi callback. The application is then responsible to either solve the conflict or assign another IP address. +@warning + Normally this function normally should not be used. DHCP configuration is requested automatically after successful Wi-Fi connection is established. + +@see + tstrM2MIPConfig + + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_set_static_ip(tstrM2MIPConfig * pstrStaticIPConf); + + /**@}*/ +/** @defgroup RequestDHCPClientFn m2m_wifi_request_dhcp_client + * @ingroup WLANAPI + * Starts the DHCP client operation(DHCP requested by the firmware automatically in STA/AP/P2P mode). + * + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_request_dhcp_client(void); + +@warning + This function is legacy and exists only for compatability with older applications. DHCP configuration is requested automatically after successful Wi-Fi connection is established. + +@return + The function returns @ref M2M_SUCCESS always. +*/ +NMI_API sint8 m2m_wifi_request_dhcp_client(void); + /**@}*/ +/** @defgroup RequestDHCPServerFn m2m_wifi_request_dhcp_server + * @ingroup WLANAPI + * Dhcp requested by the firmware automatically in STA/AP/P2P mode). + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_request_dhcp_server(uint8* addr); + +@warning + This function is legacy and exists only for compatability with older applications. DHCP server is started automatically when enabling the AP mode. + + +@return + The function returns @ref M2M_SUCCESS always. +*/ +NMI_API sint8 m2m_wifi_request_dhcp_server(uint8* addr); + /**@}*/ +/** @defgroup WifiDHCPEnableFn m2m_wifi_enable_dhcp + * @ingroup WLANAPI + * Synchronous Wi-Fi DHCP enable function. This function Enable/Disable DHCP protocol. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_enable_dhcp(uint8 u8DhcpEn ); + +@brief + Enable/Disable the DHCP client after connection. + +@param [in] u8DhcpEn + Possible values: + 1: Enable DHCP client after connection. + 0: Disable DHCP client after connection. +@warnings + -DHCP client is enabled by default + -This Function should be called before using m2m_wifi_set_static_ip() + + +@sa + m2m_wifi_set_static_ip() + +@return + The function SHALL return @ref M2M_SUCCESS for successful operation and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_enable_dhcp(uint8 u8DhcpEn ); + /**@}*/ +/** @defgroup WifiSetScanOptionFn m2m_wifi_set_scan_options + * @ingroup WLANAPI + * Synchronous Wi-Fi scan settings function. This function sets the time configuration parameters for the scan operation. + */ + +/*! +@fn \ + sint8 m2m_wifi_set_scan_options(tstrM2MScanOption* ptstrM2MScanOption) + +@param [in] ptstrM2MScanOption; + Pointer to the structure holding the Scan Parameters. + +@see + tenuM2mScanCh + m2m_wifi_request_scan + tstrM2MScanOption + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_set_scan_options(tstrM2MScanOption* ptstrM2MScanOption); + /**@}*/ +/** @defgroup WifiSetScanRegionFn m2m_wifi_set_scan_region + * @ingroup WLANAPI + * Synchronous wi-fi scan region setting function. + * This function sets the scan region, which will affect the range of possible scan channels. + * For 2.5GHz supported in the current release, the requested scan region can't exceed the maximum number of channels (14). + *@{*/ +/*! +@fn \ + sint8 m2m_wifi_set_scan_region(uint16 ScanRegion) + +@param [in] ScanRegion; + ASIA + NORTH_AMERICA +@see + tenuM2mScanCh + m2m_wifi_request_scan + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + +*/ +NMI_API sint8 m2m_wifi_set_scan_region(uint16 ScanRegion); + /**@}*/ +/** @defgroup WifiRequestScanFn m2m_wifi_request_scan +* @ingroup WLANAPI +* Asynchronous Wi-FI scan request on the given channel. The scan status is delivered in the wifi event callback and then the application +* is supposed to read the scan results sequentially. +* The number of APs found (N) is returned in event @ref M2M_WIFI_RESP_SCAN_DONE with the number of found +* APs. +* The application reads the list of APs by calling the function @ref m2m_wifi_req_scan_result N times. +* +*@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_request_scan(uint8 ch); + +@param [in] ch + RF Channel ID for SCAN operation. It should be set according to tenuM2mScanCh. + With a value of M2M_WIFI_CH_ALL(255)), means to scan all channels. + +@warning + This function is not allowed in P2P or AP modes. It works only for STA mode (both connected or disconnected states). + +@pre + - A Wi-Fi notification callback of type @ref tpfAppWifiCb MUST be implemented and registered at initialization. Registering the callback + is done through passing it to the @ref m2m_wifi_init. + - The events @ref M2M_WIFI_RESP_SCAN_DONE and @ref M2M_WIFI_RESP_SCAN_RESULT. + must be handled in the callback. + - The @ref m2m_wifi_handle_events function MUST be called to receive the responses in the callback. + +@see + M2M_WIFI_RESP_SCAN_DONE + M2M_WIFI_RESP_SCAN_RESULT + tpfAppWifiCb + tstrM2mWifiscanResult + tenuM2mScanCh + m2m_wifi_init + m2m_wifi_handle_events + m2m_wifi_req_scan_result + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +\section Example + The code snippet demonstrates an example of how the scan request is called from the application's main function and the handling of + the events received in response. +@code + + #include "m2m_wifi.h" + #include "m2m_types.h" + + void wifi_event_cb(uint8 u8WiFiEvent, void * pvMsg) + { + static uint8 u8ScanResultIdx = 0; + + switch(u8WiFiEvent) + { + case M2M_WIFI_RESP_SCAN_DONE: + { + tstrM2mScanDone *pstrInfo = (tstrM2mScanDone*)pvMsg; + + printf("Num of AP found %d\n",pstrInfo->u8NumofCh); + if(pstrInfo->s8ScanState == M2M_SUCCESS) + { + u8ScanResultIdx = 0; + if(pstrInfo->u8NumofCh >= 1) + { + m2m_wifi_req_scan_result(u8ScanResultIdx); + u8ScanResultIdx ++; + } + else + { + printf("No AP Found Rescan\n"); + m2m_wifi_request_scan(M2M_WIFI_CH_ALL); + } + } + else + { + printf("(ERR) Scan fail with error <%d>\n",pstrInfo->s8ScanState); + } + } + break; + + case M2M_WIFI_RESP_SCAN_RESULT: + { + tstrM2mWifiscanResult *pstrScanResult =(tstrM2mWifiscanResult*)pvMsg; + uint8 u8NumFoundAPs = m2m_wifi_get_num_ap_found(); + + printf(">>%02d RI %d SEC %s CH %02d BSSID %02X:%02X:%02X:%02X:%02X:%02X SSID %s\n", + pstrScanResult->u8index,pstrScanResult->s8rssi, + pstrScanResult->u8AuthType, + pstrScanResult->u8ch, + pstrScanResult->au8BSSID[0], pstrScanResult->au8BSSID[1], pstrScanResult->au8BSSID[2], + pstrScanResult->au8BSSID[3], pstrScanResult->au8BSSID[4], pstrScanResult->au8BSSID[5], + pstrScanResult->au8SSID); + + if(u8ScanResultIdx < u8NumFoundAPs) + { + // Read the next scan result + m2m_wifi_req_scan_result(index); + u8ScanResultIdx ++; + } + } + break; + default: + break; + } + } + + int main() + { + tstrWifiInitParam param; + + param.pfAppWifiCb = wifi_event_cb; + if(!m2m_wifi_init(¶m)) + { + // Scan all channels + m2m_wifi_request_scan(M2M_WIFI_CH_ALL); + + while(1) + { + m2m_wifi_handle_events(NULL); + } + } + } + +@endcode +*/ +NMI_API sint8 m2m_wifi_request_scan(uint8 ch); + + /**@}*/ +/** @defgroup WifiRequestScanFn m2m_wifi_request_scan_passive +* @ingroup WLANAPI +* Same as m2m_wifi_request_scan but perform passive scanning while the other one perform active scanning. + +* +*@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_request_scan_passive(uint8 ch, uint16 scan_time); + +@param [in] ch + RF Channel ID for SCAN operation. It should be set according to tenuM2mScanCh. + With a value of M2M_WIFI_CH_ALL(255)), means to scan all channels. + +@param [in] scan_time + The time in ms that passive scan is listening to beacons on each channel per one slot, enter 0 for deafult setting. + +@warning + This function is not allowed in P2P or AP modes. It works only for STA mode (both connected or disconnected states). + +@pre + - A Wi-Fi notification callback of type @ref tpfAppWifiCb MUST be implemented and registered at initialization. Registering the callback + is done through passing it to the @ref m2m_wifi_init. + - The events @ref M2M_WIFI_RESP_SCAN_DONE and @ref M2M_WIFI_RESP_SCAN_RESULT. + must be handled in the callback. + - The @ref m2m_wifi_handle_events function MUST be called to receive the responses in the callback. + +@see + m2m_wifi_request_scan + M2M_WIFI_RESP_SCAN_DONE + M2M_WIFI_RESP_SCAN_RESULT + tpfAppWifiCb + tstrM2mWifiscanResult + tenuM2mScanCh + m2m_wifi_init + m2m_wifi_handle_events + m2m_wifi_req_scan_result + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + +*/ +NMI_API sint8 m2m_wifi_request_scan_passive(uint8 ch, uint16 scan_time); + + + /**@}*/ +/** @defgroup WifiRequestScanFn m2m_wifi_request_scan_ssid_list +* @ingroup WLANAPI +* Asynchronous wi-fi scan request on the given channel and the hidden scan list. The scan status is delivered in the wi-fi event callback and then the application +* is to read the scan results sequentially. +* The number of APs found (N) is returned in event @ref M2M_WIFI_RESP_SCAN_DONE with the number of found +* APs. +* The application could read the list of APs by calling the function @ref m2m_wifi_req_scan_result N times. +* +*@{*/ +/*! +@fn \ + NMI_API sint8 m2m_wifi_request_scan_ssid_list(uint8 ch,uint8 * u8SsidList); + +@param [in] ch + RF Channel ID for SCAN operation. It should be set according to tenuM2mScanCh. + With a value of M2M_WIFI_CH_ALL(255)), means to scan all channels. +@param [in] u8SsidList + u8SsidList is a buffer containing a list of hidden SSIDs to + include during the scan. The first byte in the buffer, u8SsidList[0], + is the number of SSIDs encoded in the string. The number of hidden SSIDs + cannot exceed MAX_HIDDEN_SITES. All SSIDs are concatenated in the following + bytes and each SSID is prefixed with a one-byte header containing its length. + The total number of bytes in u8SsidList buffer, including length byte, cannot + exceed 133 bytes (MAX_HIDDEN_SITES SSIDs x 32 bytes each, which is max SSID length). + For instance, encoding the two hidden SSIDs "DEMO_AP" and "TEST" + results in the following buffer content: +@code + uint8 u8SsidList[14]; + u8SsidList[0] = 2; // Number of SSIDs is 2 + u8SsidList[1] = 7; // Length of the string "DEMO_AP" without NULL termination + memcpy(&u8SsidList[2], "DEMO_AP", 7); // Bytes index 2-9 containing the string DEMO_AP + u8SsidList[9] = 4; // Length of the string "TEST" without NULL termination + memcpy(&u8SsidList[10], "TEST", 4); // Bytes index 10-13 containing the string TEST +@endcode + +@warning + This function is not allowed in P2P. It works only for STA/AP mode (connected or disconnected). + +@pre + - A Wi-Fi notification callback of type @ref tpfAppWifiCb MUST be implemented and registered at initialization. Registering the callback + is done through passing it to the @ref m2m_wifi_init. + - The events @ref M2M_WIFI_RESP_SCAN_DONE and @ref M2M_WIFI_RESP_SCAN_RESULT. + must be handled in the callback. + - The @ref m2m_wifi_handle_events function MUST be called to receive the responses in the callback. + +@see + M2M_WIFI_RESP_SCAN_DONE + M2M_WIFI_RESP_SCAN_RESULT + tpfAppWifiCb + tstrM2mWifiscanResult + tenuM2mScanCh + m2m_wifi_init + m2m_wifi_handle_events + m2m_wifi_req_scan_result + +@return + The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +\section Example + The code snippet demonstrates an example of how the scan request is called from the application's main function and the handling of + the events received in response. +@code + + #include "m2m_wifi.h" + #include "m2m_types.h" + + static void request_scan_hidden_demo_ap(void); + + void wifi_event_cb(uint8 u8WiFiEvent, void * pvMsg) + { + static uint8 u8ScanResultIdx = 0; + + switch(u8WiFiEvent) + { + case M2M_WIFI_RESP_SCAN_DONE: + { + tstrM2mScanDone *pstrInfo = (tstrM2mScanDone*)pvMsg; + + printf("Num of AP found %d\n",pstrInfo->u8NumofCh); + if(pstrInfo->s8ScanState == M2M_SUCCESS) + { + u8ScanResultIdx = 0; + if(pstrInfo->u8NumofCh >= 1) + { + m2m_wifi_req_scan_result(u8ScanResultIdx); + u8ScanResultIdx ++; + } + else + { + printf("No AP Found Rescan\n"); + request_scan_hidden_demo_ap(); + } + } + else + { + printf("(ERR) Scan fail with error <%d>\n",pstrInfo->s8ScanState); + } + } + break; + + case M2M_WIFI_RESP_SCAN_RESULT: + { + tstrM2mWifiscanResult *pstrScanResult =(tstrM2mWifiscanResult*)pvMsg; + uint8 u8NumFoundAPs = m2m_wifi_get_num_ap_found(); + + printf(">>%02d RI %d SEC %s CH %02d BSSID %02X:%02X:%02X:%02X:%02X:%02X SSID %s\n", + pstrScanResult->u8index,pstrScanResult->s8rssi, + pstrScanResult->u8AuthType, + pstrScanResult->u8ch, + pstrScanResult->au8BSSID[0], pstrScanResult->au8BSSID[1], pstrScanResult->au8BSSID[2], + pstrScanResult->au8BSSID[3], pstrScanResult->au8BSSID[4], pstrScanResult->au8BSSID[5], + pstrScanResult->au8SSID); + + if(u8ScanResultIdx < u8NumFoundAPs) + { + // Read the next scan result + m2m_wifi_req_scan_result(index); + u8ScanResultIdx ++; + } + } + break; + default: + break; + } + } + + static void request_scan_hidden_demo_ap(void) + { + uint8 list[9]; + char ssid[] = "DEMO_AP"; + uint8 len = (uint8)(sizeof(ssid)-1); + + list[0] = 1; + list[1] = len; + memcpy(&list[2], ssid, len); // copy 7 bytes + // Scan all channels + m2m_wifi_request_scan_ssid_list(M2M_WIFI_CH_ALL, list); + } + + + int main() + { + tstrWifiInitParam param; + + param.pfAppWifiCb = wifi_event_cb; + if(!m2m_wifi_init(¶m)) + { + request_scan_hidden_demo_ap(); + + while(1) + { + m2m_wifi_handle_events(NULL); + } + } + } + +@endcode +*/ +NMI_API sint8 m2m_wifi_request_scan_ssid_list(uint8 ch,uint8 * u8Ssidlist); + +/**@}*/ +/** @defgroup WifiGetNumAPFoundFn m2m_wifi_get_num_ap_found + * @ingroup WLANAPI +* Synchronous function to retrieve the number of AP's found in the last scan request, The function reads the number of APs from global variable which was updated in the Wi-Fi callback function through the M2M_WIFI_RESP_SCAN_DONE event. +* Function used only in STA mode only. + */ + /**@{*/ +/*! +@fn NMI_API uint8 m2m_wifi_get_num_ap_found(void); + +@see m2m_wifi_request_scan + M2M_WIFI_RESP_SCAN_DONE + M2M_WIFI_RESP_SCAN_RESULT +@pre m2m_wifi_request_scan need to be called first + - A Wi-Fi notification callback of type @ref tpfAppWifiCb MUST be implemented and registered at initialization. Registering the callback + is done through passing it to the @ref m2m_wifi_init. + - The event @ref M2M_WIFI_RESP_SCAN_DONE must be handled in the callback to receive the requested scan information. +@warning This function must be called only in the wi-fi callback function when the events @ref M2M_WIFI_RESP_SCAN_DONE or @ref M2M_WIFI_RESP_SCAN_RESULT + are received. + Calling this function in any other place will result in undefined/outdated numbers. +@return Return the number of AP's found in the last Scan Request. + +\section Example + The code snippet demonstrates an example of how the scan request is called from the application's main function and the handling of + the events received in response. +@code + + #include "m2m_wifi.h" + #include "m2m_types.h" + + void wifi_event_cb(uint8 u8WiFiEvent, void * pvMsg) + { + static uint8 u8ScanResultIdx = 0; + + switch(u8WiFiEvent) + { + case M2M_WIFI_RESP_SCAN_DONE: + { + tstrM2mScanDone *pstrInfo = (tstrM2mScanDone*)pvMsg; + + printf("Num of AP found %d\n",pstrInfo->u8NumofCh); + if(pstrInfo->s8ScanState == M2M_SUCCESS) + { + u8ScanResultIdx = 0; + if(pstrInfo->u8NumofCh >= 1) + { + m2m_wifi_req_scan_result(u8ScanResultIdx); + u8ScanResultIdx ++; + } + else + { + printf("No AP Found Rescan\n"); + m2m_wifi_request_scan(M2M_WIFI_CH_ALL); + } + } + else + { + printf("(ERR) Scan fail with error <%d>\n",pstrInfo->s8ScanState); + } + } + break; + + case M2M_WIFI_RESP_SCAN_RESULT: + { + tstrM2mWifiscanResult *pstrScanResult =(tstrM2mWifiscanResult*)pvMsg; + uint8 u8NumFoundAPs = m2m_wifi_get_num_ap_found(); + + printf(">>%02d RI %d SEC %s CH %02d BSSID %02X:%02X:%02X:%02X:%02X:%02X SSID %s\n", + pstrScanResult->u8index,pstrScanResult->s8rssi, + pstrScanResult->u8AuthType, + pstrScanResult->u8ch, + pstrScanResult->au8BSSID[0], pstrScanResult->au8BSSID[1], pstrScanResult->au8BSSID[2], + pstrScanResult->au8BSSID[3], pstrScanResult->au8BSSID[4], pstrScanResult->au8BSSID[5], + pstrScanResult->au8SSID); + + if(u8ScanResultIdx < u8NumFoundAPs) + { + // Read the next scan result + m2m_wifi_req_scan_result(index); + u8ScanResultIdx ++; + } + } + break; + default: + break; + } + } + + int main() + { + tstrWifiInitParam param; + + param.pfAppWifiCb = wifi_event_cb; + if(!m2m_wifi_init(¶m)) + { + // Scan all channels + m2m_wifi_request_scan(M2M_WIFI_CH_ALL); + + while(1) + { + m2m_wifi_handle_events(NULL); + } + } + } + +@endcode +*/ +NMI_API uint8 m2m_wifi_get_num_ap_found(void); +/**@}*/ +/** @defgroup WifiReqScanResult m2m_wifi_req_scan_result +* @ingroup WLANAPI +* Synchronous call to read the AP information from the SCAN Result list with the given index. +* This function is expected to be called when the response events M2M_WIFI_RESP_SCAN_RESULT or +* M2M_WIFI_RESP_SCAN_DONE are received in the wi-fi callback function. +* The response information received can be obtained through the casting to the @ref tstrM2mWifiscanResult structure + */ + /**@{*/ +/*! +@fn NMI_API sint8 m2m_wifi_req_scan_result(uint8 index); +@param [in] index + Index for the requested result, the index range start from 0 till number of AP's found + +@see tstrM2mWifiscanResult + m2m_wifi_get_num_ap_found + m2m_wifi_request_scan + +@pre @ref m2m_wifi_request_scan needs to be called first, then m2m_wifi_get_num_ap_found + to get the number of AP's found + - A Wi-Fi notification callback of type @ref tpfAppWifiCb MUST be implemented and registered at startup. Registering the callback + is done through passing it to the @ref m2m_wifi_init function. + - The event @ref M2M_WIFI_RESP_SCAN_RESULT must be handled in the callback to receive the requested scan information. +@warning Function used in STA mode only. the scan results are updated only if the scan request is called. + Calling this function only without a scan request will lead to firmware errors. + Refrain from introducing a large delay between the scan request and the scan result request, to prevent + errors occurring. + +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +\section Example + The code snippet demonstrates an example of how the scan request is called from the application's main function and the handling of + the events received in response. +@code + #include "m2m_wifi.h" + #include "m2m_types.h" + + void wifi_event_cb(uint8 u8WiFiEvent, void * pvMsg) + { + static uint8 u8ScanResultIdx = 0; + + switch(u8WiFiEvent) + { + case M2M_WIFI_RESP_SCAN_DONE: + { + tstrM2mScanDone *pstrInfo = (tstrM2mScanDone*)pvMsg; + + printf("Num of AP found %d\n",pstrInfo->u8NumofCh); + if(pstrInfo->s8ScanState == M2M_SUCCESS) + { + u8ScanResultIdx = 0; + if(pstrInfo->u8NumofCh >= 1) + { + m2m_wifi_req_scan_result(u8ScanResultIdx); + u8ScanResultIdx ++; + } + else + { + printf("No AP Found Rescan\n"); + m2m_wifi_request_scan(M2M_WIFI_CH_ALL); + } + } + else + { + printf("(ERR) Scan fail with error <%d>\n",pstrInfo->s8ScanState); + } + } + break; + + case M2M_WIFI_RESP_SCAN_RESULT: + { + tstrM2mWifiscanResult *pstrScanResult =(tstrM2mWifiscanResult*)pvMsg; + uint8 u8NumFoundAPs = m2m_wifi_get_num_ap_found(); + + printf(">>%02d RI %d SEC %s CH %02d BSSID %02X:%02X:%02X:%02X:%02X:%02X SSID %s\n", + pstrScanResult->u8index,pstrScanResult->s8rssi, + pstrScanResult->u8AuthType, + pstrScanResult->u8ch, + pstrScanResult->au8BSSID[0], pstrScanResult->au8BSSID[1], pstrScanResult->au8BSSID[2], + pstrScanResult->au8BSSID[3], pstrScanResult->au8BSSID[4], pstrScanResult->au8BSSID[5], + pstrScanResult->au8SSID); + + if(u8ScanResultIdx < u8NumFoundAPs) + { + // Read the next scan result + m2m_wifi_req_scan_result(index); + u8ScanResultIdx ++; + } + } + break; + default: + break; + } + } + + int main() + { + tstrWifiInitParam param; + + param.pfAppWifiCb = wifi_event_cb; + if(!m2m_wifi_init(¶m)) + { + // Scan all channels + m2m_wifi_request_scan(M2M_WIFI_CH_ALL); + + while(1) + { + m2m_wifi_handle_events(NULL); + } + } + } + +@endcode +*/ +NMI_API sint8 m2m_wifi_req_scan_result(uint8 index); +/**@}*/ +/** @defgroup WifiReqCurrentRssiFn m2m_wifi_req_curr_rssi + * @ingroup WLANAPI + * Asynchronous request for the current RSSI of the connected AP. + * The response received in through the @ref M2M_WIFI_RESP_CURRENT_RSSI event. + */ + /**@{*/ +/*! +@fn NMI_API sint8 m2m_wifi_req_curr_rssi(void); +@pre - A Wi-Fi notification callback of type @ref tpfAppWifiCb MUST be implemented and registered before initialization. Registering the callback + is done through passing it to the [m2m_wifi_init](@ref m2m_wifi_init) through the @ref tstrWifiInitParam initialization structure. + - The event @ref M2M_WIFI_RESP_CURRENT_RSSI must be handled in the callback to receive the requested Rssi information. +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +\section Example + The code snippet demonstrates how the RSSI request is called in the application's main function and the handling of the event received in the callback. +@code + + #include "m2m_wifi.h" + #include "m2m_types.h" + + void wifi_event_cb(uint8 u8WiFiEvent, void * pvMsg) + { + static uint8 u8ScanResultIdx = 0; + + switch(u8WiFiEvent) + { + case M2M_WIFI_RESP_CURRENT_RSSI: + { + sint8 *rssi = (sint8*)pvMsg; + M2M_INFO("ch rssi %d\n",*rssi); + } + break; + default: + break; + } + } + + int main() + { + tstrWifiInitParam param; + + param.pfAppWifiCb = wifi_event_cb; + if(!m2m_wifi_init(¶m)) + { + // Scan all channels + m2m_wifi_req_curr_rssi(); + + while(1) + { + m2m_wifi_handle_events(NULL); + } + } + } + +@endcode + +*/ +NMI_API sint8 m2m_wifi_req_curr_rssi(void); +/**@}*/ +/** @defgroup WifiGetOtpMacAddFn m2m_wifi_get_otp_mac_address +* @ingroup WLANAPI +* Request the MAC address stored on the One Time Programmable(OTP) memory of the device. +* The function is blocking until the response is received. +*/ + /**@{*/ +/*! +@fn NMI_API sint8 m2m_wifi_get_otp_mac_address(uint8 *pu8MacAddr, uint8 * pu8IsValid); + +@param [out] pu8MacAddr + Output MAC address buffer of 6 bytes size. Valid only if *pu8Valid=1. +@param [out] pu8IsValid + Output boolean value to indicate the validity of pu8MacAddr in OTP. + Output zero if the OTP memory is not programmed, non-zero otherwise. +@pre m2m_wifi_init required to be called before any WIFI/socket function +@see m2m_wifi_get_mac_address + +@return The function returns @ref M2M_SUCCESS for success and a negative value otherwise. + +*/ +NMI_API sint8 m2m_wifi_get_otp_mac_address(uint8 *pu8MacAddr, uint8 * pu8IsValid); +/**@}*/ +/** @defgroup WifiGetMacAddFn m2m_wifi_get_mac_address +* @ingroup WLANAPI +* Function to retrieve the current MAC address. The function is blocking until the response is received. +*/ +/**@{*/ +/*! +@fn NMI_API sint8 m2m_wifi_get_mac_address(uint8 *pu8MacAddr) +@param [out] pu8MacAddr + Output MAC address buffer of 6 bytes size. +@pre m2m_wifi_init required to be called before any WIFI/socket function +@see m2m_wifi_get_otp_mac_address +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + +*/ +NMI_API sint8 m2m_wifi_get_mac_address(uint8 *pu8MacAddr); +/**@}*/ +/** @defgroup SetSleepModeFn m2m_wifi_set_sleep_mode + * @ingroup WLANAPI + * This is one of the two synchronous power-save setting functions that + * allow the host MCU application to tweak the system power consumption. Such tweaking can be done through one of two ways: +* 1) Changing the power save mode, to one of the allowed power save modes @ref tenuPowerSaveModes. This is done by setting the first parameter +* 2) Configuring DTIM monitoring: Configuring beacon monitoring parameters by enabling or disabling the reception of broadcast/multicast data. +* this is done by setting the second parameter. + */ + /**@{*/ +/*! +@fn NMI_API sint8 m2m_wifi_set_sleep_mode(uint8 PsTyp, uint8 BcastEn); +@param [in] PsTyp + Desired power saving mode. Supported types are enumerated in @ref tenuPowerSaveModes. +@param [in] BcastEn + Broadcast reception enable flag. + If it is 1, the WINC1500 will be awake each DTIM beacon for receiving broadcast traffic. + If it is 0, the WINC1500: disable broadcast traffic. Through this flag the WINC1500 will not wakeup at the DTIM beacon, but it will wakeup depends only + on the the configured Listen Interval. + +@warning The function called once after initialization. + +@see tenuPowerSaveModes + m2m_wifi_get_sleep_mode + m2m_wifi_set_lsn_int + +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_set_sleep_mode(uint8 PsTyp, uint8 BcastEn); +/**@}*/ +/** @defgroup WifiRequestSleepFn m2m_wifi_request_sleep + * @ingroup WLANAPI + * Synchronous power-save sleep request function, which requests from the WINC1500 device to sleep in the currenlty configured power save mode as defined + * by the @ref m2m_wifi_set_sleep_mode, for a specific time as defined by the passed in parameter. + * This function should be used in the @ref M2M_PS_MANUAL power save mode only. + * A wake up request is automatically performed by the WINC1500 device when any host driver API function, e.g. Wi-Fi or socket operation is called. + */ + /**@{*/ +/*! +@fn NMI_API sint8 m2m_wifi_request_sleep(uint32 u32SlpReqTime); +@param [in] u32SlpReqTime + Request sleep time in ms + The best recommended sleep duration is left to be determined by the application. Taking into account that if the application sends notifications very rarely, + sleeping for a long time can be a power-efficient decision. In contrast applications that are senstive for long periods of absence can experience + performance degradation in the connection if long sleeping times are used. +@warning The function should be called in @ref M2M_PS_MANUAL power save mode only. As enumerated in @ref tenuPowerSaveModes + It's also important to note that during the sleeping time while in the M2M_PS_MANUAL mode, AP beacon monitoring is bypassed and the wifi-connection may drop if + the sleep period is enlongated. +@see tenuPowerSaveModes + m2m_wifi_set_sleep_mode + +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_request_sleep(uint32 u32SlpReqTime); +/**@}*/ +/** @defgroup GetSleepModeFn m2m_wifi_get_sleep_mode + * @ingroup WLANAPI + * Synchronous power save mode retrieval function. + */ + /**@{*/ +/*! +@fn NMI_API uint8 m2m_wifi_get_sleep_mode(void); +@see tenuPowerSaveModes + m2m_wifi_set_sleep_mode +@return The current operating power saving mode based on the enumerated sleep modes @ref tenuPowerSaveModes. +*/ +NMI_API uint8 m2m_wifi_get_sleep_mode(void); +/**@}*/ +/** @defgroup WifiReqClientCtrlFn m2m_wifi_req_client_ctrl + * @ingroup WLANAPI + * Asynchronous command sending function to the PS Client (An WINC1500 board running the ps_firmware) +* if the PS client send any command it will be received through the @ref M2M_WIFI_RESP_CLIENT_INFO event + */ + /**@{*/ +/*! +@fn NMI_API sint8 m2m_wifi_req_client_ctrl(uint8 cmd); +@brief +@param [in] cmd + Control command sent from PS Server to PS Client (command values defined by the application) +@pre @ref m2m_wifi_req_server_init should be called first +@warning This mode is not supported in the current release. +@see m2m_wifi_req_server_init + M2M_WIFI_RESP_CLIENT_INFO +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_req_client_ctrl(uint8 cmd); +/**@}*/ +/** @defgroup WifiReqServerInit m2m_wifi_req_server_init + * @ingroup WLANAPI + * Synchronous function to initialize the PS Server. + * The WINC1500 supports non secure communication with another WINC1500, +* (SERVER/CLIENT) through one byte command (probe request and probe response) without any connection setup. +* The server mode can't be used with any other modes (STA/P2P/AP) +*/ + /**@{*/ +/*! +@fn NMI_API sint8 m2m_wifi_req_server_init(uint8 ch); +@param [in] ch + Server listening channel +@see m2m_wifi_req_client_ctrl +@warning This mode is not supported in the current release. +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_req_server_init(uint8 ch); +/**@}*/ +/** @defgroup WifiSetDeviceNameFn m2m_wifi_set_device_name + * @ingroup WLANAPI + * Sets the WINC device name. The name string is used as a device name in both (P2P) WiFi-Direct mode as well as DHCP hostname (option 12). + * For P2P devices to communicate a device name must be present. If it is not set through this function a default name is assigned. + * The default name is WINC-XX-YY, where XX and YY are the last 2 octets of the OTP MAC address. If OTP (eFuse) is programmed, + * then the default name is WINC-00-00. + */ + /**@{*/ +/*! +@fn NMI_API sint8 m2m_wifi_set_device_name(uint8 *pu8DeviceName, uint8 u8DeviceNameLength); +@param [in] pu8DeviceName + A Buffer holding the device name. Device name is a null terminated C string. +@param [in] u8DeviceNameLength + The length of the device name. Should not exceed the maximum device name's length @ref M2M_DEVICE_NAME_MAX (including null character). +@warning The function called once after initialization. + Used for the Wi-Fi Direct (P2P) as well as DHCP client hostname option (12). +@warning Device name shall contain only characters allowed in valid internet host name as defined in RFC 952 and 1123. +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_set_device_name(uint8 *pu8DeviceName, uint8 u8DeviceNameLength); +/**@}*/ +/** @defgroup WifiSetLsnIntFn m2m_wifi_set_lsn_int + * @ingroup WLANAPI +* This is one of the two synchronous power-save setting functions that +* allow the host MCU application to tweak the system power consumption. Such tweaking can be done by modifying the +* the Wi-Fi listen interval. The listen interval is how many beacon periods the station can sleep before it wakes up to receive data buffer in AP. +* It is represented in units of AP beacon periods(100ms). +*/ + /**@{*/ +/*! +@fn NMI_API sint8 m2m_wifi_set_lsn_int(tstrM2mLsnInt * pstrM2mLsnInt); + +@param [in] pstrM2mLsnInt + Structure holding the listen interval configurations. +@pre Function @m2m_wifi_set_sleep_mode shall be called first, to set the power saving mode required. +@warning The function should be called once after initialization. +@see tstrM2mLsnInt + m2m_wifi_set_sleep_mode +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + +*/ +NMI_API sint8 m2m_wifi_set_lsn_int(tstrM2mLsnInt *pstrM2mLsnInt); +/**@}*/ +/** @defgroup WifiEnableMonitorModeFn m2m_wifi_enable_monitoring_mode + * @ingroup WLANAPI + * Asynchronous Wi-Fi monitoring mode (Promiscuous mode) enabling function. This function enables the monitoring mode, thus allowing two operations to be performed: + * 1) Transmission of manually configured frames, through using the @ref m2m_wifi_send_wlan_pkt function. + * 2) Reception of frames based on a defined filtering criteria + * When the monitoring mode is enabled, reception of all frames that satisfy the filter criteria passed in as a parameter is allowed, on the current wireless channel \n. + * All packets that meet the filtering criteria are passed to the application layer, to be handled by the assigned monitoring callback function \n. + * The monitoring callback function must be implemented before starting the monitoring mode, in-order to handle the packets received \n. + * Registering of the implemented callback function is through the callback pointer @ref tpfAppMonCb in the @ref tstrWifiInitParam structure\n. + * passed to @ref m2m_wifi_init function at initialization. + * + */ + /**@{*/ +/*! + * @fn NMI_API sint8 m2m_wifi_enable_monitoring_mode(tstrM2MWifiMonitorModeCtrl *, uint8 *, uint16 , uint16); + * @param [in] pstrMtrCtrl + * Pointer to @ref tstrM2MWifiMonitorModeCtrl structure holding the filtering parameters. + * @param [in] pu8PayloadBuffer + * Pointer to a buffer allocated by the application. The buffer SHALL hold the Data field of + * the WIFI RX Packet (Or a part from it). If it is set to NULL, the WIFI data payload will + * be discarded by the monitoring driver. + * @param [in] u16BufferSize + * The total size of the pu8PayloadBuffer in bytes. + * @param [in] u16DataOffset + * Starting offset in the DATA FIELD of the received WIFI packet. The application may be interested + * in reading specific information from the received packet. It must assign the offset to the starting + * position of it relative to the DATA payload start.\n + * \e Example, \e if \e the \e SSID \e is \e needed \e to \e be \e read \e from \e a \e PROBE \e REQ \e packet, \e the \e u16Offset \e MUST \e be \e set \e to \e 0. + * @warning When This mode is enabled, you can not be connected in any mode (Station, Access Point, or P2P).\n + * @see tstrM2MWifiMonitorModeCtrl + tstrM2MWifiRxPacketInfo + tstrWifiInitParam + tenuM2mScanCh + m2m_wifi_disable_monitoring_mode + m2m_wifi_send_wlan_pkt + m2m_wifi_send_ethernet_pkt + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + +*\section Example +* The example demonstrates the main function where-by the monitoring enable function is called after the initialization of the driver and the packets are +* handled in the callback function. +* @code + + #include "m2m_wifi.h" + #include "m2m_types.h" + + //Declare receive buffer + uint8 gmgmt[1600]; + + //Callback functions + void wifi_cb(uint8 u8WiFiEvent, void * pvMsg) + { + ; + } + void wifi_monitoring_cb(tstrM2MWifiRxPacketInfo *pstrWifiRxPacket, uint8 *pu8Payload, uint16 u16PayloadSize) + { + if((NULL != pstrWifiRxPacket) && (0 != u16PayloadSize)) { + if(MANAGEMENT == pstrWifiRxPacket->u8FrameType) { + M2M_INFO("***# MGMT PACKET #***\n"); + } else if(DATA_BASICTYPE == pstrWifiRxPacket->u8FrameType) { + M2M_INFO("***# DATA PACKET #***\n"); + } else if(CONTROL == pstrWifiRxPacket->u8FrameType) { + M2M_INFO("***# CONTROL PACKET #***\n"); + } + } + } + + int main() + { + //Register wifi_monitoring_cb + tstrWifiInitParam param; + param.pfAppWifiCb = wifi_cb; + param.pfAppMonCb = wifi_monitoring_cb; + + nm_bsp_init(); + + if(!m2m_wifi_init(¶m)) { + //Enable Monitor Mode with filter to receive all data frames on channel 1 + tstrM2MWifiMonitorModeCtrl strMonitorCtrl = {0}; + strMonitorCtrl.u8ChannelID = M2M_WIFI_CH_1; + strMonitorCtrl.u8FrameType = DATA_BASICTYPE; + strMonitorCtrl.u8FrameSubtype = M2M_WIFI_FRAME_SUB_TYPE_ANY; //Receive any subtype of data frame + m2m_wifi_enable_monitoring_mode(&strMonitorCtrl, gmgmt, sizeof(gmgmt), 0); + + while(1) { + m2m_wifi_handle_events(NULL); + } + } + return 0; + } + * @endcode + */ +NMI_API sint8 m2m_wifi_enable_monitoring_mode(tstrM2MWifiMonitorModeCtrl *pstrMtrCtrl, uint8 *pu8PayloadBuffer, + uint16 u16BufferSize, uint16 u16DataOffset); +/**@}*/ +/** @defgroup WifiDisableMonitorModeFn m2m_wifi_disable_monitoring_mode + * @ingroup WLANAPI + * Synchronous function to disable Wi-Fi monitoring mode (Promiscuous mode). Expected to be called, if the enable monitoring mode is set, but if it was called without enabling + * no negative impact will reside. + */ + /**@{*/ +/*! + * @fn NMI_API sint8 m2m_wifi_disable_monitoring_mode(void); + * @see m2m_wifi_enable_monitoring_mode + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + */ +NMI_API sint8 m2m_wifi_disable_monitoring_mode(void); + /**@}*/ + /** @defgroup SendWlanPktFn m2m_wifi_send_wlan_pkt + * @ingroup WLANAPI + * Synchronous function to transmit a WIFI RAW packet while the implementation of this packet is left to the application developer. + */ + /**@{*/ +/*! + * @fn NMI_API sint8 m2m_wifi_send_wlan_pkt(uint8 *, uint16, uint16); + + * @param [in] pu8WlanPacket + * Pointer to a buffer holding the whole WIFI frame. + * @param [in] u16WlanHeaderLength + * The size of the WIFI packet header ONLY. + * @param [in] u16WlanPktSize + * The size of the whole bytes in packet. + * @see m2m_wifi_enable_monitoring_mode + m2m_wifi_disable_monitoring_mode + * @pre Enable Monitoring mode first using @ref m2m_wifi_enable_monitoring_mode + * @warning This function available in monitoring mode ONLY.\n + * @note Packets are user's responsibility. + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + */ +NMI_API sint8 m2m_wifi_send_wlan_pkt(uint8 *pu8WlanPacket, uint16 u16WlanHeaderLength, uint16 u16WlanPktSize); +/**@}*/ +/** @defgroup WifiSendEthernetPktFn m2m_wifi_send_ethernet_pkt + * @ingroup WLANAPI + * Synchronous function to transmit an Ethernet packet. Transmit a packet directly in ETHERNET/bypass mode where the TCP/IP stack is disabled and the implementation of this packet is left to the application developer. + * The Ethernet packet composition is left to the application developer. + */ + /**@{*/ +/*! + * @fn NMI_API sint8 m2m_wifi_send_ethernet_pkt(uint8* pu8Packet,uint16 u16PacketSize) + * @param [in] pu8Packet + * Pointer to a buffer holding the whole Ethernet frame. + * @param [in] u16PacketSize + * The size of the whole bytes in packet. + * @warning This function available in ETHERNET/Bypass mode ONLY. Make sure that application defines @ref ETH_MODE.\n + * @note Packets are the user's responsibility. + * @sa m2m_wifi_enable_mac_mcast,m2m_wifi_set_receive_buffer + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + + */ +NMI_API sint8 m2m_wifi_send_ethernet_pkt(uint8* pu8Packet,uint16 u16PacketSize); +/**@}*/ +/** @defgroup WifiEnableSntpFn m2m_wifi_enable_sntp + * @ingroup WLANAPI + * Synchronous function to enable/disable the native Simple Network Time Protocol(SNTP) client in the WINC1500 firmware.\n + * The SNTP is enabled by default at start-up.The SNTP client at firmware is used to synchronize the system clock to the UTC time from the well known time + * servers (e.g. "time-c.nist.gov"). The SNTP client uses a default update cycle of 1 day. + * The UTC is important for checking the expiration date of X509 certificates used while establishing + * TLS (Transport Layer Security) connections. + * It is highly recommended to use it if there is no other means to get the UTC time. If there is a RTC + * on the host MCU, the SNTP could be disabled and the host should set the system time to the firmware + * using the @ref m2m_wifi_set_system_time function. + */ + /**@{*/ +/*! + * @fn NMI_API sint8 m2m_wifi_enable_sntp(uint8); + * @param [in] bEnable +* Enabling/Disabling flag + * '0' :disable SNTP + * '1' :enable SNTP + * @see m2m_wifi_set_sytem_time + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + */ +NMI_API sint8 m2m_wifi_enable_sntp(uint8 bEnable); +/**@}*/ +/** @defgroup WifiSetSystemTime m2m_wifi_set_sytem_time + * @ingroup WLANAPI + * Synchronous function for setting the system time in time/date format (@ref uint32).\n + * The @ref tstrSystemTime structure can be used as a reference to the time values that should be set and pass its value as @ref uint32 + */ + /**@{*/ +/*! + * @fn NMI_API sint8 m2m_wifi_set_sytem_time(uint32); + * @param [in] u32UTCSeconds + * Seconds elapsed since January 1, 1900 (NTP Timestamp). + * @see m2m_wifi_enable_sntp + * tstrSystemTime + * @note If there is an RTC on the host MCU, the SNTP could be disabled and the host should set the system time to the firmware + * using the API @ref m2m_wifi_set_sytem_time. + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + */ +NMI_API sint8 m2m_wifi_set_sytem_time(uint32 u32UTCSeconds); +/**@}*/ +/** @defgroup WifiGetSystemTime m2m_wifi_get_sytem_time + * @ingroup WLANAPI + * Asynchronous function used to retrieve the system time through the use of the response @ref M2M_WIFI_RESP_GET_SYS_TIME. + * Response time retrieved is parsed into the members defined in the structure @ref tstrSystemTime. + */ + /**@{*/ +/*! + * @fn NMI_API sint8 m2m_wifi_get_sytem_time(void); + * @see m2m_wifi_enable_sntp + tstrSystemTime + * @note Get the system time from the SNTP client + * using the API @ref m2m_wifi_get_sytem_time. + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + */ +NMI_API sint8 m2m_wifi_get_sytem_time(void); +/**@}*/ +/** @defgroup WifiSetCustInfoElementFn m2m_wifi_set_cust_InfoElement + * @ingroup WLANAPI + * Synchronous function to Add/Remove user-defined Information Element to the WIFIBeacon and Probe Response frames while chip mode is Access Point Mode.\n + * According to the information element layout shown bellow, if it is required to set new data for the information elements, pass in the buffer with the + * information according to the sizes and ordering defined bellow. However, if it's required to delete these IEs, fill the buffer with zeros. + */ + /**@{*/ +/*! + * @fn NMI_API sint8 m2m_wifi_set_cust_InfoElement(uint8*); + * @param [in] pau8M2mCustInfoElement + * Pointer to Buffer containing the IE to be sent. It is the application developer's responsibility to ensure on the correctness of the information element's ordering passed in. + * @warning - Size of All elements combined must not exceed 255 byte.\n + * - Used in Access Point Mode \n + * @note IEs Format will be follow the following layout:\n + * @verbatim + --------------- ---------- ---------- ------------------- -------- -------- ----------- ---------------------- + | Byte[0] | Byte[1] | Byte[2] | Byte[3:length1+2] | ..... | Byte[n] | Byte[n+1] | Byte[n+2:lengthx+2] | + |---------------|----------|----------|-------------------|-------- --------|-----------|------------------| + | #of all Bytes | IE1 ID | Length1 | Data1(Hex Coded) | ..... | IEx ID | Lengthx | Datax(Hex Coded) | + --------------- ---------- ---------- ------------------- -------- -------- ----------- ---------------------- + * @endverbatim + * @see m2m_wifi_enable_sntp + * tstrSystemTime + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + \section Example + The example demonstrates how the information elements are set using this function. + *@code + * + char elementData[21]; + static char state = 0; // To Add, Append, and Delete + if(0 == state) { //Add 3 IEs + state = 1; + //Total Number of Bytes + elementData[0]=12; + //First IE + elementData[1]=200; elementData[2]=1; elementData[3]='A'; + //Second IE + elementData[4]=201; elementData[5]=2; elementData[6]='B'; elementData[7]='C'; + //Third IE + elementData[8]=202; elementData[9]=3; elementData[10]='D'; elementData[11]=0; elementData[12]='F'; + } else if(1 == state) { + //Append 2 IEs to others, Notice that we keep old data in array starting with\n + //element 13 and total number of bytes increased to 20 + state = 2; + //Total Number of Bytes + elementData[0]=20; + //Fourth IE + elementData[13]=203; elementData[14]=1; elementData[15]='G'; + //Fifth IE + elementData[16]=204; elementData[17]=3; elementData[18]='X'; elementData[19]=5; elementData[20]='Z'; + } else if(2 == state) { //Delete All IEs + state = 0; + //Total Number of Bytes + elementData[0]=0; + } + m2m_wifi_set_cust_InfoElement(elementData); + * @endcode + */ +NMI_API sint8 m2m_wifi_set_cust_InfoElement(uint8* pau8M2mCustInfoElement); + /**@}*/ +/** @defgroup WifiSetPowerProfile m2m_wifi_set_power_profile + * @ingroup WLANAPI + * Change the power profile mode + */ + /**@{*/ +/*! +@fn NMI_API sint8 m2m_wifi_set_power_profile(uint8 u8PwrMode); +@brief +@param [in] u8PwrMode + Change the WINC1500 power profile to different mode based on the enumeration + @ref tenuM2mPwrMode +@pre Must be called after the initializations and before any connection request and can't be changed in run time. +@sa tenuM2mPwrMode + m2m_wifi_init +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +sint8 m2m_wifi_set_power_profile(uint8 u8PwrMode); + /**@}*/ + /** @defgroup WifiSetTxPower m2m_wifi_set_tx_power + * @ingroup WLANAPI + * Set the TX power tenuM2mTxPwrLevel + */ + /**@{*/ +/*! +@fn NMI_API sint8 m2m_wifi_set_tx_power(uint8 u8TxPwrLevel); +@param [in] u8TxPwrLevel + change the TX power based on the enumeration tenuM2mTxPwrLevel +@pre Must be called after the initialization and before any connection request and can't be changed in runtime. +@sa tenuM2mTxPwrLevel + m2m_wifi_init +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +sint8 m2m_wifi_set_tx_power(uint8 u8TxPwrLevel); + /**@}*/ +/** @defgroup WifiEnableFirmware m2m_wifi_enable_firmware_logs +* @ingroup WLANAPI +* Enable or Disable logs in run time (Disabling Firmware logs will +* enhance the firmware start-up time and performance) +*/ + /**@{*/ +/*! +@fn NMI_API sint8 m2m_wifi_enable_firmware_logs(uint8 u8Enable); +@param [in] u8Enable + Set 1 to enable the logs, 0 for disable +@pre Must be called after intialization through the following function @ref m2m_wifi_init +@sa __DISABLE_FIRMWARE_LOGS__ (build option to disable logs from initializations) + m2m_wifi_init +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +sint8 m2m_wifi_enable_firmware_logs(uint8 u8Enable); + /**@}*/ + /** @defgroup WifiSetBatteryVoltage m2m_wifi_set_battery_voltage +* @ingroup WLANAPI +* Set the battery voltage to update the firmware calculations +*/ + /**@{*/ +/*! +@fn NMI_API sint8 m2m_wifi_set_battery_voltage(uint8 u8BattVolt) +@brief Set the battery voltage to update the firmware calculations +@param [in] dbBattVolt + Battery Volt in double +@pre Must be called after intialization through the following function @ref m2m_wifi_init +@sa m2m_wifi_init +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +sint8 m2m_wifi_set_battery_voltage(uint16 u16BattVoltx100); + /**@}*/ + /** @defgroup WifiSetGains m2m_wifi_set_gains +* @ingroup WLANAPI +* Set the chip gains mainly (PPA for 11b/11gn) +*/ + /**@{*/ +/*! +@fn sint8 m2m_wifi_set_gains(tstrM2mWifiGainsParams* pstrM2mGain); +@brief Set the chip PPA gain for 11b/11gn +@param [in] pstrM2mGain + tstrM2mWifiGainsParams contain gain parmaters as implemnted in rf document +@pre Must be called after intialization through the following function @ref m2m_wifi_init +@sa m2m_wifi_init +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +sint8 m2m_wifi_set_gains(tstrM2mWifiGainsParams* pstrM2mGain); + /**@}*/ +/** @defgroup WifiGetFirmwareVersion m2m_wifi_get_firmware_version +* @ingroup WLANAPI +* Get Firmware version info as defined in the structure @ref tstrM2mRev. +*/ + /**@{*/ +/*! +@fn m2m_wifi_get_firmware_version(tstrM2mRev* pstrRev) +@param [out] M2mRev + Pointer to the structure @ref tstrM2mRev that contains the firmware version parameters +@pre Must be called after intialization through the following function @ref m2m_wifi_init +@sa m2m_wifi_init +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +sint8 m2m_wifi_get_firmware_version(tstrM2mRev *pstrRev); +/**@}*/ +#ifdef ETH_MODE +/** @defgroup WifiEnableMacMcastFn m2m_wifi_enable_mac_mcast + * @ingroup WLANAPI + * Synchronous function for filtering received MAC addresses from certain MAC address groups. + * This function allows the addtion/removal of certain MAC addresses, used in the multicast filter. + */ + /**@{*/ +/*! + * @fn NMI_API sint8 m2m_wifi_enable_mac_mcast(uint8 *, uint8); + * @brief + * @param [in] pu8MulticastMacAddress + * Pointer to MAC address + * @param [in] u8AddRemove + * A flag to add or remove the MAC ADDRESS, based on the following values: + * - 0 : remove MAC address + * - 1 : add MAC address + * @warning This function is available in ETHERNET/bypass mode ONLY. Make sure that the application defines @ref ETH_MODE.\n + * @note Maximum number of MAC addresses that could be added is 8. + * @sa m2m_wifi_set_receive_buffer, m2m_wifi_send_ethernet_pkt + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + */ +NMI_API sint8 m2m_wifi_enable_mac_mcast(uint8* pu8MulticastMacAddress, uint8 u8AddRemove); +/**@}*/ +/** @defgroup SetReceiveBufferFn m2m_wifi_set_receive_buffer + * @ingroup WLANAPI + * Synchronous function for setting or modifying the receiver buffer's length. + * In the ETHERNET/bypass mode the application should define a callback of type @ref tpfAppEthCb, through which the application handles the received + * ethernet frames. It is through this callback function that the user can dynamically modify the length of the currently used receiver buffer. + *@{*/ +/*! + * @fn NMI_API sint8 m2m_wifi_set_receive_buffer(void *, uint16); + + * @param [in] pvBuffer + * Pointer to Buffer to receive data. + * NULL pointer causes a negative error @ref M2M_ERR_FAIL. + * + * @param [in] u16BufferLen + * Length of data to be received. Maximum length of data should not exceed the size defined by TCP/IP + * defined as @ref SOCKET_BUFFER_MAX_LENGTH + * + * @warning This function is available in the Ethernet/bypass mode ONLY. Make sure that the application defines @ref ETH_MODE.\n + * @sa m2m_wifi_enable_mac_mcast,m2m_wifi_send_ethernet_pkt + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + */ +NMI_API sint8 m2m_wifi_set_receive_buffer(void* pvBuffer,uint16 u16BufferLen); +/**@}*/ +#endif /* ETH_MODE */ +/** @defgroup GetPrngBytes m2m_wifi_prng_get_random_bytes + * @ingroup WLANAPI + * Asynchronous function for retrieving from the firmware a pseudo-random set of bytes as specifed in the size passed in as a parameter. + * The registered wifi-cb function retrieves the random bytes through the response @ref M2M_WIFI_RESP_GET_PRNG + *@{*/ +/*! + * @fn sint8 m2m_wifi_prng_get_random_bytes(uint8 * pu8PRNGBuff,uint16 u16PRNGSize) + * @param [out] pu8PrngBuff + * Pointer to a buffer to receive data. + * @param [in] u16PrngSize + * Request size in bytes + *@warning Size greater than the maximum specified (@ref M2M_BUFFER_MAX_SIZE - sizeof(tstrPrng)) + * causes a negative error @ref M2M_ERR_FAIL. + *@see tstrPrng + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + */ +sint8 m2m_wifi_prng_get_random_bytes(uint8 * pu8PrngBuff,uint16 u16PrngSize); +/**@}*/ +#ifdef __cplusplus +} +#endif +#endif /* __M2M_WIFI_H__ */ + diff --git a/lib/WiFi101/src/driver/source/m2m_ate_mode.c b/lib/WiFi101/src/driver/source/m2m_ate_mode.c new file mode 100644 index 0000000..beb1af8 --- /dev/null +++ b/lib/WiFi101/src/driver/source/m2m_ate_mode.c @@ -0,0 +1,826 @@ +/** + * + * \file + * + * \brief NMC1500 Peripherials Application Interface. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifdef _M2M_ATE_FW_ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +#include "driver/include/m2m_ate_mode.h" +#include "driver/source/nmasic.h" +#include "driver/source/nmdrv.h" +#include "m2m_hif.h" +#include "driver/source/nmbus.h" +#include "bsp/include/nm_bsp.h" + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +MACROS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +#define rInterrupt_CORTUS_0 (0x10a8) +#define rInterrupt_CORTUS_1 (0x10ac) +#define rInterrupt_CORTUS_2 (0x10b0) + +#define rBurstTx_NMI_TX_RATE (0x161d00) +#define rBurstTx_NMI_NUM_TX_FRAMES (0x161d04) +#define rBurstTx_NMI_TX_FRAME_LEN (0x161d08) +#define rBurstTx_NMI_TX_CW_PARAM (0x161d0c) +#define rBurstTx_NMI_TX_GAIN (0x161d10) +#define rBurstTx_NMI_TX_DPD_CTRL (0x161d14) +#define rBurstTx_NMI_USE_PMU (0x161d18) +#define rBurstTx_NMI_TEST_CH (0x161d1c) +#define rBurstTx_NMI_TX_PHY_CONT (0x161d20) +#define rBurstTx_NMI_TX_CW_MODE (0x161d24) +#define rBurstTx_NMI_TEST_XO_OFF (0x161d28) +#define rBurstTx_NMI_USE_EFUSE_XO_OFF (0x161d2c) + +#define rBurstTx_NMI_MAC_FILTER_ENABLE_DA (0x161d30) +#define rBurstTx_NMI_MAC_ADDR_LO_PEER (0x161d34) +#define rBurstTx_NMI_MAC_ADDR_LO_SELF (0x161d38) +#define rBurstTx_NMI_MAC_ADDR_HI_PEER (0x161d3c) +#define rBurstTx_NMI_MAC_ADDR_HI_SELF (0x161d40) +#define rBurstTx_NMI_RX_PKT_CNT_SUCCESS (0x161d44) +#define rBurstTx_NMI_RX_PKT_CNT_FAIL (0x161d48) +#define rBurstTx_NMI_SET_SELF_MAC_ADDR (0x161d4c) +#define rBurstTx_NMI_MAC_ADDR_LO_SA (0x161d50) +#define rBurstTx_NMI_MAC_ADDR_HI_SA (0x161d54) +#define rBurstTx_NMI_MAC_FILTER_ENABLE_SA (0x161d58) + +#define rBurstRx_NMI_RX_ALL_PKTS_CONT (0x9898) +#define rBurstRx_NMI_RX_ERR_PKTS_CONT (0x988c) + +#define TX_DGAIN_MAX_NUM_REGS (4) +#define TX_DGAIN_REG_BASE_ADDRESS (0x1240) +#define TX_GAIN_CODE_MAX_NUM_REGS (3) +#define TX_GAIN_CODE_BASE_ADDRESS (0x1250) +#define TX_PA_MAX_NUM_REGS (3) +#define TX_PA_BASE_ADDRESS (0x1e58) +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +VARIABLES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +volatile static uint8 gu8AteIsRunning = 0; /*!< ATE firmware status, 1 means ATE is running otherwise stopped */ +volatile static uint8 gu8RxState = 0; /*!< RX status, 1 means Rx is running otherwise stopped */ +volatile static uint8 gu8TxState = 0; /*!< TX status, 1 means Tx is running otherwise stopped */ +volatile static uint32 gaAteFwTxRates[M2M_ATE_MAX_NUM_OF_RATES] = +{ + 0x01, 0x02, 0x05, 0x0B, /*B-Rats*/ + 0x06, 0x09, 0x0C, 0x12, 0x18, 0x24, 0x30, 0x36, /*G-Rats*/ + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 /*N-Rats*/ +}; + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +STATIC FUNCTIONS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +static void m2m_ate_set_rx_status(uint8 u8Value) +{ + gu8RxState = u8Value; +} + +static void m2m_ate_set_tx_status(uint8 u8Value) +{ + gu8TxState = u8Value; +} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +FUNCTION IMPLEMENTATION +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/*! +@fn \ + sint8 m2m_ate_init(void); + +@brief + This function used to download ATE firmware from flash and start it + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +sint8 m2m_ate_init(void) +{ + sint8 s8Ret = M2M_SUCCESS; + uint8 u8WifiMode = M2M_WIFI_MODE_ATE_HIGH; + + s8Ret = nm_drv_init(&u8WifiMode); + + return s8Ret; +} + +/*! +@fn \ + sint8 m2m_ate_init(tstrM2mAteInit *pstrInit); + +@brief + This function used to download ATE firmware from flash and start it + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +sint8 m2m_ate_init_param(tstrM2mAteInit *pstrInit) +{ + sint8 s8Ret = M2M_SUCCESS; + + s8Ret = nm_drv_init((void*)&pstrInit->u8RxPwrMode); + + return s8Ret; +} + +/*! +@fn \ + sint8 m2m_ate_deinit(void); + +@brief + De-Initialization of ATE firmware mode + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +sint8 m2m_ate_deinit(void) +{ + return nm_drv_deinit(NULL); +} + +/*! +@fn \ + sint8 m2m_ate_set_fw_state(uint8); + +@brief + This function used to change ATE firmware status from running to stopped or vice versa. + +@param [in] u8State + Required state of ATE firmware, one of \ref tenuM2mAteFwState enumeration values. +@return + The function SHALL return 0 for success and a negative value otherwise. +\sa + m2m_ate_init +*/ +sint8 m2m_ate_set_fw_state(uint8 u8State) +{ + sint8 s8Ret = M2M_SUCCESS; + uint32_t u32Val = 0; + + if((M2M_ATE_FW_STATE_STOP == u8State) && (M2M_ATE_FW_STATE_STOP != gu8AteIsRunning)) + { + u32Val = nm_read_reg(rNMI_GLB_RESET); + u32Val &= ~(1 << 10); + s8Ret = nm_write_reg(rNMI_GLB_RESET, u32Val); + gu8AteIsRunning = M2M_ATE_FW_STATE_STOP; + } + else if((M2M_ATE_FW_STATE_RUN == u8State) && (M2M_ATE_FW_STATE_RUN != gu8AteIsRunning)) + { + /* 0x1118[0]=0 at power-on-reset: pad-based control. */ + /* Switch cortus reset register to register control. 0x1118[0]=1. */ + u32Val = nm_read_reg(rNMI_BOOT_RESET_MUX); + u32Val |= (1 << 0); + s8Ret = nm_write_reg(rNMI_BOOT_RESET_MUX, u32Val); + if(M2M_SUCCESS != s8Ret) + { + goto __EXIT; + } + /** + Write the firmware download complete magic value 0x10ADD09E at + location 0xFFFF000C (Cortus map) or C000C (AHB map). + This will let the boot-rom code execute from RAM. + **/ + s8Ret = nm_write_reg(0xc0000, 0x71); + if(M2M_SUCCESS != s8Ret) + { + goto __EXIT; + } + + u32Val = nm_read_reg(rNMI_GLB_RESET); + if((u32Val & (1ul << 10)) == (1ul << 10)) + { + u32Val &= ~(1ul << 10); + s8Ret = nm_write_reg(rNMI_GLB_RESET, u32Val); + if(M2M_SUCCESS != s8Ret) + { + goto __EXIT; + } + } + + u32Val |= (1ul << 10); + s8Ret = nm_write_reg(rNMI_GLB_RESET, u32Val); + if(M2M_SUCCESS != s8Ret) + { + goto __EXIT; + } + gu8AteIsRunning = M2M_ATE_FW_STATE_RUN; + } + else + { + s8Ret = M2M_ATE_ERR_UNHANDLED_CASE; + } + +__EXIT: + if((M2M_SUCCESS == s8Ret) && (M2M_ATE_FW_STATE_RUN == gu8AteIsRunning)) + { + nm_bsp_sleep(500); /*wait for ATE firmware start up*/ + } + return s8Ret; +} + +/*! +@fn \ + sint8 m2m_ate_get_fw_state(uint8); + +@brief + This function used to return status of ATE firmware. + +@return + The function SHALL return status of ATE firmware, one of \ref tenuM2mAteFwState enumeration values. +\sa + m2m_ate_init, m2m_ate_set_fw_state +*/ +sint8 m2m_ate_get_fw_state(void) +{ + return gu8AteIsRunning; +} + +/*! +@fn \ + uint32 m2m_ate_get_tx_rate(uint8); + +@brief + This function used to return value of TX rate required by application developer. + +@param [in] u8Index + Index of required rate , one of \ref tenuM2mAteTxIndexOfRates enumeration values. +@return + The function SHALL return 0 for in case of failure otherwise selected rate value. +\sa + tenuM2mAteTxIndexOfRates +*/ +uint32 m2m_ate_get_tx_rate(uint8 u8Index) +{ + if(M2M_ATE_MAX_NUM_OF_RATES <= u8Index) + { + return 0; + } + return gaAteFwTxRates[u8Index]; +} + +/*! +@fn \ + sint8 m2m_ate_get_tx_status(void); + +@brief + This function used to return status of TX test case either running or stopped. + +@return + The function SHALL return status of ATE firmware, 1 if TX is running otherwise 0. +\sa + m2m_ate_start_tx, m2m_ate_stop_tx +*/ +sint8 m2m_ate_get_tx_status(void) +{ + return gu8TxState; +} + +/*! +@fn \ + sint8 m2m_ate_start_tx(tstrM2mAteTx *) + +@brief + This function used to start TX test case. + +@param [in] strM2mAteTx + Type of \ref tstrM2mAteTx, with the values required to enable TX test case. You must use \ref m2m_ate_init first. +@return + The function SHALL return 0 for success and a negative value otherwise. +\sa + m2m_ate_init, m2m_ate_stop_tx, m2m_ate_get_tx_status +*/ +sint8 m2m_ate_start_tx(tstrM2mAteTx * strM2mAteTx) +{ + sint8 s8Ret = M2M_SUCCESS; + uint8 u8LoopCntr = 0; + uint32_t val32; + + + if(NULL == strM2mAteTx) + { + s8Ret = M2M_ATE_ERR_VALIDATE; + goto __EXIT; + } + + if(0 != m2m_ate_get_tx_status()) + { + s8Ret = M2M_ATE_ERR_TX_ALREADY_RUNNING; + goto __EXIT; + } + + if(0 != m2m_ate_get_rx_status()) + { + s8Ret = M2M_ATE_ERR_RX_ALREADY_RUNNING; + goto __EXIT; + } + + if( (strM2mAteTx->channel_num < M2M_ATE_CHANNEL_1) || + (strM2mAteTx->channel_num > M2M_ATE_CHANNEL_14) || + (strM2mAteTx->tx_gain_sel < M2M_ATE_TX_GAIN_DYNAMIC) || + (strM2mAteTx->tx_gain_sel > M2M_ATE_TX_GAIN_TELEC) || + (strM2mAteTx->frame_len > M2M_ATE_MAX_FRAME_LENGTH) || + (strM2mAteTx->frame_len < M2M_ATE_MIN_FRAME_LENGTH) + ) + { + s8Ret = M2M_ATE_ERR_VALIDATE; + goto __EXIT; + } + + if( (strM2mAteTx->duty_cycle < M2M_ATE_TX_DUTY_MAX_VALUE /*1*/) || + (strM2mAteTx->duty_cycle > M2M_ATE_TX_DUTY_MIN_VALUE /*10*/ ) || + (strM2mAteTx->dpd_ctrl < M2M_ATE_TX_DPD_DYNAMIC) || + (strM2mAteTx->dpd_ctrl > M2M_ATE_TX_DPD_ENABLED) || + (strM2mAteTx->use_pmu > M2M_ATE_PMU_ENABLE) || + (strM2mAteTx->phy_burst_tx < M2M_ATE_TX_SRC_MAC) || + (strM2mAteTx->phy_burst_tx > M2M_ATE_TX_SRC_PHY) || + (strM2mAteTx->cw_tx < M2M_ATE_TX_MODE_NORM) || + (strM2mAteTx->cw_tx > M2M_ATE_TX_MODE_CW) + ) + { + s8Ret = M2M_ATE_ERR_VALIDATE; + goto __EXIT; + } + + for(u8LoopCntr=0; u8LoopCntrdata_rate) + { + break; + } + } + + if(M2M_ATE_MAX_NUM_OF_RATES == u8LoopCntr) + { + s8Ret = M2M_ATE_ERR_VALIDATE; + goto __EXIT; + } + + + + s8Ret += nm_write_reg(rBurstTx_NMI_USE_PMU, strM2mAteTx->use_pmu); + s8Ret += nm_write_reg(rBurstTx_NMI_TX_PHY_CONT, strM2mAteTx->phy_burst_tx); + s8Ret += nm_write_reg(rBurstTx_NMI_NUM_TX_FRAMES, strM2mAteTx->num_frames); + s8Ret += nm_write_reg(rBurstTx_NMI_TX_GAIN, strM2mAteTx->tx_gain_sel); + s8Ret += nm_write_reg(rBurstTx_NMI_TEST_CH, strM2mAteTx->channel_num); + s8Ret += nm_write_reg(rBurstTx_NMI_TX_FRAME_LEN, strM2mAteTx->frame_len); + s8Ret += nm_write_reg(rBurstTx_NMI_TX_CW_PARAM, strM2mAteTx->duty_cycle); + s8Ret += nm_write_reg(rBurstTx_NMI_TX_DPD_CTRL, strM2mAteTx->dpd_ctrl); + s8Ret += nm_write_reg(rBurstTx_NMI_TX_RATE, strM2mAteTx->data_rate); + s8Ret += nm_write_reg(rBurstTx_NMI_TX_CW_MODE, strM2mAteTx->cw_tx); + s8Ret += nm_write_reg(rBurstTx_NMI_TEST_XO_OFF, strM2mAteTx->xo_offset_x1000); + s8Ret += nm_write_reg(rBurstTx_NMI_USE_EFUSE_XO_OFF, strM2mAteTx->use_efuse_xo_offset); + + val32 = strM2mAteTx->peer_mac_addr[5] << 0; + val32 |= strM2mAteTx->peer_mac_addr[4] << 8; + val32 |= strM2mAteTx->peer_mac_addr[3] << 16; + nm_write_reg(rBurstTx_NMI_MAC_ADDR_LO_PEER, val32 ); + + val32 = strM2mAteTx->peer_mac_addr[2] << 0; + val32 |= strM2mAteTx->peer_mac_addr[1] << 8; + val32 |= strM2mAteTx->peer_mac_addr[0] << 16; + nm_write_reg(rBurstTx_NMI_MAC_ADDR_HI_PEER, val32 ); + + if(M2M_SUCCESS == s8Ret) + { + s8Ret += nm_write_reg(rInterrupt_CORTUS_0, 1); /*Interrupt Cortus*/ + m2m_ate_set_tx_status(1); + nm_bsp_sleep(200); /*Recommended*/ + } + +__EXIT: + return s8Ret; +} + +/*! +@fn \ + sint8 m2m_ate_stop_tx(void) + +@brief + This function used to stop TX test case. + +@return + The function SHALL return 0 for success and a negative value otherwise. +\sa + m2m_ate_init, m2m_ate_start_tx, m2m_ate_get_tx_status +*/ +sint8 m2m_ate_stop_tx(void) +{ + sint8 s8Ret = M2M_SUCCESS; + + s8Ret = nm_write_reg(rInterrupt_CORTUS_1, 1); + if(M2M_SUCCESS == s8Ret) + { + m2m_ate_set_tx_status(0); + } + + return s8Ret; +} + +/*! +@fn \ + sint8 m2m_ate_get_rx_status(uint8); + +@brief + This function used to return status of RX test case either running or stopped. + +@return + The function SHALL return status of ATE firmware, 1 if RX is running otherwise 0. +\sa + m2m_ate_start_rx, m2m_ate_stop_rx +*/ +sint8 m2m_ate_get_rx_status(void) +{ + return gu8RxState; +} + +/*! +@fn \ + sint8 m2m_ate_start_rx(tstrM2mAteRx *) + +@brief + This function used to start RX test case. + +@param [in] strM2mAteRx + Type of \ref tstrM2mAteRx, with the values required to enable RX test case. You must use \ref m2m_ate_init first. +@return + The function SHALL return 0 for success and a negative value otherwise. +\sa + m2m_ate_init, m2m_ate_stop_rx, m2m_ate_get_rx_status +*/ +sint8 m2m_ate_start_rx(tstrM2mAteRx * strM2mAteRxStr) +{ + sint8 s8Ret = M2M_SUCCESS; + uint32 val32; + if(NULL == strM2mAteRxStr) + { + s8Ret = M2M_ATE_ERR_VALIDATE; + goto __EXIT; + } + + if(0 != m2m_ate_get_tx_status()) + { + s8Ret = M2M_ATE_ERR_TX_ALREADY_RUNNING; + goto __EXIT; + } + + if(0 != m2m_ate_get_rx_status()) + { + s8Ret = M2M_ATE_ERR_RX_ALREADY_RUNNING; + goto __EXIT; + } + + if( (strM2mAteRxStr->channel_num < M2M_ATE_CHANNEL_1) || + (strM2mAteRxStr->channel_num > M2M_ATE_CHANNEL_14)|| + (strM2mAteRxStr->use_pmu > M2M_ATE_PMU_ENABLE) + ) + { + s8Ret = M2M_ATE_ERR_VALIDATE; + goto __EXIT; + } + + s8Ret += nm_write_reg(rBurstTx_NMI_TEST_CH, strM2mAteRxStr->channel_num); + s8Ret += nm_write_reg(rBurstTx_NMI_USE_PMU, strM2mAteRxStr->use_pmu); + s8Ret += nm_write_reg(rBurstTx_NMI_TEST_XO_OFF, strM2mAteRxStr->xo_offset_x1000); + s8Ret += nm_write_reg(rBurstTx_NMI_USE_EFUSE_XO_OFF, strM2mAteRxStr->use_efuse_xo_offset); + + if(strM2mAteRxStr->override_self_mac_addr) + { + val32 = strM2mAteRxStr->self_mac_addr[5] << 0; + val32 |= strM2mAteRxStr->self_mac_addr[4] << 8; + val32 |= strM2mAteRxStr->self_mac_addr[3] << 16; + nm_write_reg(rBurstTx_NMI_MAC_ADDR_LO_SELF, val32 ); + + val32 = strM2mAteRxStr->self_mac_addr[2] << 0; + val32 |= strM2mAteRxStr->self_mac_addr[1] << 8; + val32 |= strM2mAteRxStr->self_mac_addr[0] << 16; + nm_write_reg(rBurstTx_NMI_MAC_ADDR_HI_SELF, val32 ); + } + + if(strM2mAteRxStr->mac_filter_en_sa) + { + val32 = strM2mAteRxStr->peer_mac_addr[5] << 0; + val32 |= strM2mAteRxStr->peer_mac_addr[4] << 8; + val32 |= strM2mAteRxStr->peer_mac_addr[3] << 16; + nm_write_reg(rBurstTx_NMI_MAC_ADDR_LO_SA, val32 ); + + val32 = strM2mAteRxStr->peer_mac_addr[2] << 0; + val32 |= strM2mAteRxStr->peer_mac_addr[1] << 8; + val32 |= strM2mAteRxStr->peer_mac_addr[0] << 16; + nm_write_reg(rBurstTx_NMI_MAC_ADDR_HI_SA, val32 ); + } + + nm_write_reg(rBurstTx_NMI_MAC_FILTER_ENABLE_DA, strM2mAteRxStr->mac_filter_en_da); + nm_write_reg(rBurstTx_NMI_MAC_FILTER_ENABLE_SA, strM2mAteRxStr->mac_filter_en_sa); + nm_write_reg(rBurstTx_NMI_SET_SELF_MAC_ADDR, strM2mAteRxStr->override_self_mac_addr); + + if(M2M_SUCCESS == s8Ret) + { + s8Ret += nm_write_reg(rInterrupt_CORTUS_2, 1); /*Interrupt Cortus*/ + m2m_ate_set_rx_status(1); + nm_bsp_sleep(10); /*Recommended*/ + } + +__EXIT: + return s8Ret; +} + +/*! +@fn \ + sint8 m2m_ate_stop_rx(void) + +@brief + This function used to stop RX test case. + +@return + The function SHALL return 0 for success and a negative value otherwise. +\sa + m2m_ate_init, m2m_ate_start_rx, m2m_ate_get_rx_status +*/ +sint8 m2m_ate_stop_rx(void) +{ + m2m_ate_set_rx_status(0); + nm_bsp_sleep(200); /*Recommended*/ + return M2M_SUCCESS; +} + +/*! +@fn \ + sint8 m2m_ate_read_rx_status(tstrM2mAteRxStatus *) + +@brief + This function used to read RX statistics from ATE firmware. + +@param [out] strM2mAteRxStatus + Type of \ref tstrM2mAteRxStatus used to save statistics of RX test case. You must use \ref m2m_ate_start_rx first. +@return + The function SHALL return 0 for success and a negative value otherwise. +\sa + m2m_ate_init, m2m_ate_start_rx +*/ +sint8 m2m_ate_read_rx_status(tstrM2mAteRxStatus *strM2mAteRxStatus) +{ + sint8 s8Ret = M2M_SUCCESS; + + if(NULL == strM2mAteRxStatus) + { + s8Ret = M2M_ATE_ERR_VALIDATE; + goto __EXIT; + } + + if(0 != m2m_ate_get_tx_status()) + { + s8Ret = M2M_ATE_ERR_TX_ALREADY_RUNNING; + goto __EXIT; + } + + if (nm_read_reg(rBurstTx_NMI_MAC_FILTER_ENABLE_DA) || nm_read_reg(rBurstTx_NMI_MAC_FILTER_ENABLE_SA)) + { + strM2mAteRxStatus->num_rx_pkts = nm_read_reg(rBurstTx_NMI_RX_PKT_CNT_SUCCESS) + nm_read_reg(rBurstTx_NMI_RX_PKT_CNT_FAIL); + strM2mAteRxStatus->num_good_pkts = nm_read_reg(rBurstTx_NMI_RX_PKT_CNT_SUCCESS); + strM2mAteRxStatus->num_err_pkts = nm_read_reg(rBurstTx_NMI_RX_PKT_CNT_FAIL); + } + else + { + strM2mAteRxStatus->num_rx_pkts = nm_read_reg(rBurstRx_NMI_RX_ALL_PKTS_CONT) + nm_read_reg(0x989c); + strM2mAteRxStatus->num_err_pkts = nm_read_reg(rBurstRx_NMI_RX_ERR_PKTS_CONT); + strM2mAteRxStatus->num_good_pkts = strM2mAteRxStatus->num_rx_pkts - strM2mAteRxStatus->num_err_pkts; + } + +__EXIT: + return s8Ret; +} +/*! +@fn \ + sint8 m2m_ate_set_dig_gain(double dGaindB) + +@brief + This function is used to set the digital gain + +@param [in] double dGaindB + The digital gain value required to be set. +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +sint8 m2m_ate_set_dig_gain(double dGaindB) +{ + uint32_t dGain, val32; + dGain = (uint32_t)(pow(10, dGaindB/20.0) * 1024.0); + + val32 = nm_read_reg(0x160cd0); + val32 &= ~(0x1ffful << 0); + val32 |= (((uint32_t)dGain) << 0); + nm_write_reg(0x160cd0, val32); + return M2M_SUCCESS; +} +/*! +@fn \ + sint8 m2m_ate_get_dig_gain(double * dGaindB) + +@brief + This function is used to get the digital gain + +@param [out] double * dGaindB + The retrieved digital gain value obtained from HW registers in dB. +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +sint8 m2m_ate_get_dig_gain(double * dGaindB) +{ + uint32 dGain, val32; + + if(!dGaindB) return M2M_ERR_INVALID_ARG; + + val32 = nm_read_reg(0x160cd0); + + dGain = (val32 >> 0) & 0x1ffful; + *dGaindB = 20.0*log10((double)dGain / 1024.0); + + return M2M_SUCCESS; +} +/*! +@fn \ + void m2m_ate_set_pa_gain(uint8 gain_db) + +@brief + This function is used to set the PA gain (18/15/12/9/6/3/0 only) + +@param [in] uint8 gain_db + PA gain level allowed (18/15/12/9/6/3/0 only) + +*/ +void m2m_ate_set_pa_gain(uint8 gain_db) +{ + uint32 PA_1e9c; + uint8 aGain[] = { + /* "0 dB" */ 0x00, + /* "3 dB" */ 0x01, + /* "6 dB" */ 0x03, + /* "9 dB" */ 0x07, + /* "12 dB" */ 0x0f, + /* "15 dB" */ 0x1f, + /* "18 dB" */ 0x3f }; + /* The variable PA gain is valid only for High power mode */ + PA_1e9c = nm_read_reg(0x1e9c); + /* TX bank 0. */ + PA_1e9c &= ~(0x3ful << 8); + PA_1e9c |= (((uint32)aGain[gain_db/3] & 0x3f) << 8); + nm_write_reg(0x1e9c, PA_1e9c); +} +/*! +@fn \ + sint8 m2m_ate_get_pa_gain(double *paGaindB) + +@brief + This function is used to get the PA gain + +@param [out] double *paGaindB + The retrieved PA gain value obtained from HW registers in dB. +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +sint8 m2m_ate_get_pa_gain(double *paGaindB) +{ + uint32 val32, paGain; + uint32 m_cmbPAGainStep; + + if(!paGaindB) + return M2M_ERR_INVALID_ARG; + + val32 = nm_read_reg(0x1e9c); + + paGain = (val32 >> 8) & 0x3f; + + switch(paGain){ + case 0x1: + m_cmbPAGainStep = 5; + break; + case 0x3: + m_cmbPAGainStep = 4; + break; + case 0x7: + m_cmbPAGainStep = 3; + break; + case 0xf: + m_cmbPAGainStep = 2; + break; + case 0x1f: + m_cmbPAGainStep = 1; + break; + case 0x3f: + m_cmbPAGainStep = 0; + break; + default: + m_cmbPAGainStep = 0; + break; + } + + *paGaindB = 18 - m_cmbPAGainStep*3; + + return M2M_SUCCESS; +} +/*! +@fn \ + sint8 m2m_ate_get_ppa_gain(double * ppaGaindB) + +@brief + This function is used to get the PPA gain + +@param [out] uint32 * ppaGaindB + The retrieved PPA gain value obtained from HW registers in dB. +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +sint8 m2m_ate_get_ppa_gain(double * ppaGaindB) +{ + uint32 val32, ppaGain, m_cmbPPAGainStep; + + if(!ppaGaindB) return M2M_ERR_INVALID_ARG; + + val32 = nm_read_reg(0x1ea0); + + ppaGain = (val32 >> 5) & 0x7; + + switch(ppaGain){ + case 0x1: + m_cmbPPAGainStep = 2; + break; + case 0x3: + m_cmbPPAGainStep = 1; + break; + case 0x7: + m_cmbPPAGainStep = 0; + break; + default: + m_cmbPPAGainStep = 3; + break; + } + + *ppaGaindB = 9 - m_cmbPPAGainStep*3; + + + return M2M_SUCCESS; +} +/*! +@fn \ + sint8 m2m_ate_get_tot_gain(double * totGaindB) + +@brief + This function is used to calculate the total gain + +@param [out] double * totGaindB + The retrieved total gain value obtained from calculations made based on the digital gain, PA and PPA gain values. +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +sint8 m2m_ate_get_tot_gain(double * totGaindB) +{ + double dGaindB, paGaindB, ppaGaindB; + + if(!totGaindB) return M2M_ERR_INVALID_ARG; + + m2m_ate_get_pa_gain(&paGaindB); + m2m_ate_get_ppa_gain(&ppaGaindB); + m2m_ate_get_dig_gain(&dGaindB); + + *totGaindB = dGaindB + paGaindB + ppaGaindB; + + return M2M_SUCCESS; +} + +#endif //_M2M_ATE_FW_ \ No newline at end of file diff --git a/lib/WiFi101/src/driver/source/m2m_crypto.c b/lib/WiFi101/src/driver/source/m2m_crypto.c new file mode 100644 index 0000000..9ac7711 --- /dev/null +++ b/lib/WiFi101/src/driver/source/m2m_crypto.c @@ -0,0 +1,1010 @@ +/** + * + * \file + * + * \brief WINC Crypto module. + * + * Copyright (c) 2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +#include "driver/include/m2m_crypto.h" +#include "driver/source/nmbus.h" +#include "driver/source/nmasic.h" + +#ifdef CONF_CRYPTO_HW + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +MACROS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*======*======*======*======*======*=======* +* WINC SHA256 HW Engine Register Definition * +*======*======*======*======*======*========*/ + +#define SHA_BLOCK_SIZE (64) + +#define SHARED_MEM_BASE (0xd0000) + + +#define SHA256_MEM_BASE (0x180000UL) +#define SHA256_ENGINE_ADDR (0x180000ul) + +/* SHA256 Registers */ +#define SHA256_CTRL (SHA256_MEM_BASE+0x00) +#define SHA256_CTRL_START_CALC_MASK (NBIT0) +#define SHA256_CTRL_START_CALC_SHIFT (0) +#define SHA256_CTRL_PREPROCESS_MASK (NBIT1) +#define SHA256_CTRL_PREPROCESS_SHIFT (1) +#define SHA256_CTRL_HASH_HASH_MASK (NBIT2) +#define SHA256_CTRL_HASH_HASH_SHIFT (2) +#define SHA256_CTRL_INIT_SHA256_STATE_MASK (NBIT3) +#define SHA256_CTRL_INIT_SHA256_STATE_SHIFT (3) +#define SHA256_CTRL_WR_BACK_HASH_VALUE_MASK (NBIT4) +#define SHA256_CTRL_WR_BACK_HASH_VALUE_SHIFT (4) +#define SHA256_CTRL_FORCE_SHA256_QUIT_MASK (NBIT5) +#define SHA256_CTRL_FORCE_SHA256_QUIT_SHIFT (5) + +#define SHA256_REGS_SHA256_CTRL_AHB_BYTE_REV_EN (NBIT6) +#define SHA256_REGS_SHA256_CTRL_RESERVED (NBIT7) +#define SHA256_REGS_SHA256_CTRL_CORE_TO_AHB_CLK_RATIO (NBIT8+ NBIT9+ NBIT10) +#define SHA256_REGS_SHA256_CTRL_CORE_TO_AHB_CLK_RATIO_MASK (NBIT2+ NBIT1+ NBIT0) +#define SHA256_REGS_SHA256_CTRL_CORE_TO_AHB_CLK_RATIO_SHIFT (8) +#define SHA256_REGS_SHA256_CTRL_RESERVED_11 (NBIT11) +#define SHA256_REGS_SHA256_CTRL_SHA1_CALC (NBIT12) +#define SHA256_REGS_SHA256_CTRL_PBKDF2_SHA1_CALC (NBIT13) + + +#define SHA256_START_RD_ADDR (SHA256_MEM_BASE+0x04UL) +#define SHA256_DATA_LENGTH (SHA256_MEM_BASE+0x08UL) +#define SHA256_START_WR_ADDR (SHA256_MEM_BASE+0x0cUL) +#define SHA256_COND_CHK_CTRL (SHA256_MEM_BASE+0x10) +#define SHA256_COND_CHK_CTRL_HASH_VAL_COND_CHK_MASK (NBIT1 | NBIT0) +#define SHA256_COND_CHK_CTRL_HASH_VAL_COND_CHK_SHIFT (0) +#define SHA256_COND_CHK_CTRL_STEP_VAL_MASK (NBIT6 | NBIT5 | NBIT4 | NBIT3 | NBIT2) +#define SHA256_COND_CHK_CTRL_STEP_VAL_SHIFT (2) +#define SHA256_COND_CHK_CTRL_COND_CHK_RESULT_MASK (NBIT7) +#define SHA256_COND_CHK_CTRL_COND_CHK_RESULT_SHIFT (7) + +#define SHA256_MOD_DATA_RANGE (SHA256_MEM_BASE+0x14) +#define SHA256_MOD_DATA_RANGE_ST_BYTE_2_ADD_STP_MASK (NBIT24-1) +#define SHA256_MOD_DATA_RANGE_ST_BYTE_2_ADD_STP_SHIFT (0) +#define SHA256_MOD_DATA_RANGE_MOD_DATA_LEN_MASK (NBIT24 | NBIT25| NBIT26) +#define SHA256_MOD_DATA_RANGE_MOD_DATA_LEN_SHIFT (24) + + +#define SHA256_COND_CHK_STS_1 (SHA256_MEM_BASE+0x18) +#define SHA256_COND_CHK_STS_2 (SHA256_MEM_BASE+0x1c) +#define SHA256_DONE_INTR_ENABLE (SHA256_MEM_BASE+0x20) +#define SHA256_DONE_INTR_STS (SHA256_MEM_BASE+0x24) +#define SHA256_TARGET_HASH_H1 (SHA256_MEM_BASE+0x28) +#define SHA256_TARGET_HASH_H2 (SHA256_MEM_BASE+0x2c) +#define SHA256_TARGET_HASH_H3 (SHA256_MEM_BASE+0x30) +#define SHA256_TARGET_HASH_H4 (SHA256_MEM_BASE+0x34) +#define SHA256_TARGET_HASH_H5 (SHA256_MEM_BASE+0x38) +#define SHA256_TARGET_HASH_H6 (SHA256_MEM_BASE+0x3c) +#define SHA256_TARGET_HASH_H7 (SHA256_MEM_BASE+0x40) +#define SHA256_TARGET_HASH_H8 (SHA256_MEM_BASE+0x44) + +/*======*======*======*======*======*=======* +* WINC BIGINT HW Engine Register Definition * +*======*======*======*======*======*========*/ + + +#define BIGINT_ENGINE_ADDR (0x180080ul) +#define BIGINT_VERSION (BIGINT_ENGINE_ADDR + 0x00) + +#define BIGINT_MISC_CTRL (BIGINT_ENGINE_ADDR + 0x04) +#define BIGINT_MISC_CTRL_CTL_START (NBIT0) +#define BIGINT_MISC_CTRL_CTL_RESET (NBIT1) +#define BIGINT_MISC_CTRL_CTL_MSW_FIRST (NBIT2) +#define BIGINT_MISC_CTRL_CTL_SWAP_BYTE_ORDER (NBIT3) +#define BIGINT_MISC_CTRL_CTL_FORCE_BARRETT (NBIT4) +#define BIGINT_MISC_CTRL_CTL_M_PRIME_VALID (NBIT5) + +#define BIGINT_M_PRIME (BIGINT_ENGINE_ADDR + 0x08) + +#define BIGINT_STATUS (BIGINT_ENGINE_ADDR + 0x0C) +#define BIGINT_STATUS_STS_DONE (NBIT0) + +#define BIGINT_CLK_COUNT (BIGINT_ENGINE_ADDR + 0x10) +#define BIGINT_ADDR_X (BIGINT_ENGINE_ADDR + 0x14) +#define BIGINT_ADDR_E (BIGINT_ENGINE_ADDR + 0x18) +#define BIGINT_ADDR_M (BIGINT_ENGINE_ADDR + 0x1C) +#define BIGINT_ADDR_R (BIGINT_ENGINE_ADDR + 0x20) +#define BIGINT_LENGTH (BIGINT_ENGINE_ADDR + 0x24) + +#define BIGINT_IRQ_STS (BIGINT_ENGINE_ADDR + 0x28) +#define BIGINT_IRQ_STS_DONE (NBIT0) +#define BIGINT_IRQ_STS_CHOOSE_MONT (NBIT1) +#define BIGINT_IRQ_STS_M_READ (NBIT2) +#define BIGINT_IRQ_STS_X_READ (NBIT3) +#define BIGINT_IRQ_STS_START (NBIT4) +#define BIGINT_IRQ_STS_PRECOMP_FINISH (NBIT5) + +#define BIGINT_IRQ_MASK (BIGINT_ENGINE_ADDR + 0x2C) +#define BIGINT_IRQ_MASK_CTL_IRQ_MASK_START (NBIT4) + +#define ENABLE_FLIPPING 1 + + + + +#define GET_UINT32(BUF,OFFSET) (((uint32)((BUF)[OFFSET])) | ((uint32)(((BUF)[OFFSET + 1]) << 8)) | \ +((uint32)(((BUF)[OFFSET + 2]) << 16)) | ((uint32)(((BUF)[OFFSET + 3]) << 24))) + +#define PUTU32(VAL32,BUF,OFFSET) \ +do \ +{ \ + (BUF)[OFFSET ] = BYTE_3((VAL32)); \ + (BUF)[OFFSET +1 ] = BYTE_2((VAL32)); \ + (BUF)[OFFSET +2 ] = BYTE_1((VAL32)); \ + (BUF)[OFFSET +3 ] = BYTE_0((VAL32)); \ +}while(0) + + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +DATA TYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*! +@struct \ + tstrHashContext + +@brief +*/ +typedef struct{ + uint32 au32HashState[M2M_SHA256_DIGEST_LEN/4]; + uint8 au8CurrentBlock[64]; + uint32 u32TotalLength; + uint8 u8InitHashFlag; +}tstrSHA256HashCtxt; + + + +/*======*======*======*======*======*=======* +* SHA256 IMPLEMENTATION * +*======*======*======*======*======*========*/ + +sint8 m2m_crypto_sha256_hash_init(tstrM2mSha256Ctxt *pstrSha256Ctxt) +{ + tstrSHA256HashCtxt *pstrSHA256 = (tstrSHA256HashCtxt*)pstrSha256Ctxt; + if(pstrSHA256 != NULL) + { + m2m_memset((uint8*)pstrSha256Ctxt, 0, sizeof(tstrM2mSha256Ctxt)); + pstrSHA256->u8InitHashFlag = 1; + } + return 0; +} + +sint8 m2m_crypto_sha256_hash_update(tstrM2mSha256Ctxt *pstrSha256Ctxt, uint8 *pu8Data, uint16 u16DataLength) +{ + sint8 s8Ret = M2M_ERR_FAIL; + tstrSHA256HashCtxt *pstrSHA256 = (tstrSHA256HashCtxt*)pstrSha256Ctxt; + if(pstrSHA256 != NULL) + { + uint32 u32ReadAddr; + uint32 u32WriteAddr = SHARED_MEM_BASE; + uint32 u32Addr = u32WriteAddr; + uint32 u32ResidualBytes; + uint32 u32NBlocks; + uint32 u32Offset; + uint32 u32CurrentBlock = 0; + uint8 u8IsDone = 0; + + /* Get the remaining bytes from the previous update (if the length is not block aligned). */ + u32ResidualBytes = pstrSHA256->u32TotalLength % SHA_BLOCK_SIZE; + + /* Update the total data length. */ + pstrSHA256->u32TotalLength += u16DataLength; + + if(u32ResidualBytes != 0) + { + if((u32ResidualBytes + u16DataLength) >= SHA_BLOCK_SIZE) + { + u32Offset = SHA_BLOCK_SIZE - u32ResidualBytes; + m2m_memcpy(&pstrSHA256->au8CurrentBlock[u32ResidualBytes], pu8Data, u32Offset); + pu8Data += u32Offset; + u16DataLength -= u32Offset; + + nm_write_block(u32Addr, pstrSHA256->au8CurrentBlock, SHA_BLOCK_SIZE); + u32Addr += SHA_BLOCK_SIZE; + u32CurrentBlock = 1; + } + else + { + m2m_memcpy(&pstrSHA256->au8CurrentBlock[u32ResidualBytes], pu8Data, u16DataLength); + u16DataLength = 0; + } + } + + /* Get the number of HASH BLOCKs and the residual bytes. */ + u32NBlocks = u16DataLength / SHA_BLOCK_SIZE; + u32ResidualBytes = u16DataLength % SHA_BLOCK_SIZE; + + if(u32NBlocks != 0) + { + nm_write_block(u32Addr, pu8Data, (uint16)(u32NBlocks * SHA_BLOCK_SIZE)); + pu8Data += (u32NBlocks * SHA_BLOCK_SIZE); + } + + u32NBlocks += u32CurrentBlock; + if(u32NBlocks != 0) + { + uint32 u32RegVal = 0; + + nm_write_reg(SHA256_CTRL, u32RegVal); + u32RegVal |= SHA256_CTRL_FORCE_SHA256_QUIT_MASK; + nm_write_reg(SHA256_CTRL, u32RegVal); + + if(pstrSHA256->u8InitHashFlag) + { + pstrSHA256->u8InitHashFlag = 0; + u32RegVal |= SHA256_CTRL_INIT_SHA256_STATE_MASK; + } + + u32ReadAddr = u32WriteAddr + (u32NBlocks * SHA_BLOCK_SIZE); + nm_write_reg(SHA256_DATA_LENGTH, (u32NBlocks * SHA_BLOCK_SIZE)); + nm_write_reg(SHA256_START_RD_ADDR, u32WriteAddr); + nm_write_reg(SHA256_START_WR_ADDR, u32ReadAddr); + + u32RegVal |= SHA256_CTRL_START_CALC_MASK; + + u32RegVal &= ~(0x7 << 8); + u32RegVal |= (2 << 8); + + nm_write_reg(SHA256_CTRL, u32RegVal); + + /* 5. Wait for done_intr */ + while(!u8IsDone) + { + u32RegVal = nm_read_reg(SHA256_DONE_INTR_STS); + u8IsDone = u32RegVal & NBIT0; + } + } + if(u32ResidualBytes != 0) + { + m2m_memcpy(pstrSHA256->au8CurrentBlock, pu8Data, u32ResidualBytes); + } + s8Ret = M2M_SUCCESS; + } + return s8Ret; +} + + +sint8 m2m_crypto_sha256_hash_finish(tstrM2mSha256Ctxt *pstrSha256Ctxt, uint8 *pu8Sha256Digest) +{ + sint8 s8Ret = M2M_ERR_FAIL; + tstrSHA256HashCtxt *pstrSHA256 = (tstrSHA256HashCtxt*)pstrSha256Ctxt; + if(pstrSHA256 != NULL) + { + uint32 u32ReadAddr; + uint32 u32WriteAddr = SHARED_MEM_BASE; + uint32 u32Addr = u32WriteAddr; + uint16 u16Offset; + uint16 u16PaddingLength; + uint16 u16NBlocks = 1; + uint32 u32RegVal = 0; + uint32 u32Idx,u32ByteIdx; + uint32 au32Digest[M2M_SHA256_DIGEST_LEN / 4]; + uint8 u8IsDone = 0; + + nm_write_reg(SHA256_CTRL,u32RegVal); + u32RegVal |= SHA256_CTRL_FORCE_SHA256_QUIT_MASK; + nm_write_reg(SHA256_CTRL,u32RegVal); + + if(pstrSHA256->u8InitHashFlag) + { + pstrSHA256->u8InitHashFlag = 0; + u32RegVal |= SHA256_CTRL_INIT_SHA256_STATE_MASK; + } + + /* Calculate the offset of the last data byte in the current block. */ + u16Offset = (uint16)(pstrSHA256->u32TotalLength % SHA_BLOCK_SIZE); + + /* Add the padding byte 0x80. */ + pstrSHA256->au8CurrentBlock[u16Offset ++] = 0x80; + + /* Calculate the required padding to complete + one Hash Block Size. + */ + u16PaddingLength = SHA_BLOCK_SIZE - u16Offset; + m2m_memset(&pstrSHA256->au8CurrentBlock[u16Offset], 0, u16PaddingLength); + + /* If the padding count is not enough to hold 64-bit representation of + the total input message length, one padding block is required. + */ + if(u16PaddingLength < 8) + { + nm_write_block(u32Addr, pstrSHA256->au8CurrentBlock, SHA_BLOCK_SIZE); + u32Addr += SHA_BLOCK_SIZE; + m2m_memset(pstrSHA256->au8CurrentBlock, 0, SHA_BLOCK_SIZE); + u16NBlocks ++; + } + + /* pack the length at the end of the padding block */ + PUTU32(pstrSHA256->u32TotalLength << 3, pstrSHA256->au8CurrentBlock, (SHA_BLOCK_SIZE - 4)); + + u32ReadAddr = u32WriteAddr + (u16NBlocks * SHA_BLOCK_SIZE); + nm_write_block(u32Addr, pstrSHA256->au8CurrentBlock, SHA_BLOCK_SIZE); + nm_write_reg(SHA256_DATA_LENGTH, (u16NBlocks * SHA_BLOCK_SIZE)); + nm_write_reg(SHA256_START_RD_ADDR, u32WriteAddr); + nm_write_reg(SHA256_START_WR_ADDR, u32ReadAddr); + + u32RegVal |= SHA256_CTRL_START_CALC_MASK; + u32RegVal |= SHA256_CTRL_WR_BACK_HASH_VALUE_MASK; + u32RegVal &= ~(0x7UL << 8); + u32RegVal |= (0x2UL << 8); + + nm_write_reg(SHA256_CTRL,u32RegVal); + + + /* 5. Wait for done_intr */ + while(!u8IsDone) + { + u32RegVal = nm_read_reg(SHA256_DONE_INTR_STS); + u8IsDone = u32RegVal & NBIT0; + } + nm_read_block(u32ReadAddr, (uint8*)au32Digest, 32); + + /* Convert the output words to an array of bytes. + */ + u32ByteIdx = 0; + for(u32Idx = 0; u32Idx < (M2M_SHA256_DIGEST_LEN / 4); u32Idx ++) + { + pu8Sha256Digest[u32ByteIdx ++] = BYTE_3(au32Digest[u32Idx]); + pu8Sha256Digest[u32ByteIdx ++] = BYTE_2(au32Digest[u32Idx]); + pu8Sha256Digest[u32ByteIdx ++] = BYTE_1(au32Digest[u32Idx]); + pu8Sha256Digest[u32ByteIdx ++] = BYTE_0(au32Digest[u32Idx]); + } + s8Ret = M2M_SUCCESS; + } + return s8Ret; +} + + +/*======*======*======*======*======*=======* +* RSA IMPLEMENTATION * +*======*======*======*======*======*========*/ + +static void FlipBuffer(uint8 *pu8InBuffer, uint8 *pu8OutBuffer, uint16 u16BufferSize) +{ + uint16 u16Idx; + for(u16Idx = 0; u16Idx < u16BufferSize; u16Idx ++) + { +#if ENABLE_FLIPPING == 1 + pu8OutBuffer[u16Idx] = pu8InBuffer[u16BufferSize - u16Idx - 1]; +#else + pu8OutBuffer[u16Idx] = pu8InBuffer[u16Idx]; +#endif + } +} + +void BigInt_ModExp +( + uint8 *pu8X, uint16 u16XSize, + uint8 *pu8E, uint16 u16ESize, + uint8 *pu8M, uint16 u16MSize, + uint8 *pu8R, uint16 u16RSize + ) +{ + uint32 u32Reg; + uint8 au8Tmp[780] = {0}; + uint32 u32XAddr = SHARED_MEM_BASE; + uint32 u32MAddr; + uint32 u32EAddr; + uint32 u32RAddr; + uint8 u8EMswBits = 32; + uint32 u32Mprime = 0x7F; + uint16 u16XSizeWords,u16ESizeWords; + uint32 u32Exponent; + + u16XSizeWords = (u16XSize + 3) / 4; + u16ESizeWords = (u16ESize + 3) / 4; + + u32MAddr = u32XAddr + (u16XSizeWords * 4); + u32EAddr = u32MAddr + (u16XSizeWords * 4); + u32RAddr = u32EAddr + (u16ESizeWords * 4); + + /* Reset the core. + */ + u32Reg = 0; + u32Reg |= BIGINT_MISC_CTRL_CTL_RESET; + u32Reg = nm_read_reg(BIGINT_MISC_CTRL); + u32Reg &= ~BIGINT_MISC_CTRL_CTL_RESET; + u32Reg = nm_read_reg(BIGINT_MISC_CTRL); + + nm_write_block(u32RAddr,au8Tmp, u16RSize); + + /* Write Input Operands to Chip Memory. + */ + /*------- X -------*/ + FlipBuffer(pu8X,au8Tmp,u16XSize); + nm_write_block(u32XAddr,au8Tmp,u16XSizeWords * 4); + + /*------- E -------*/ + m2m_memset(au8Tmp, 0, sizeof(au8Tmp)); + FlipBuffer(pu8E, au8Tmp, u16ESize); + nm_write_block(u32EAddr, au8Tmp, u16ESizeWords * 4); + u32Exponent = GET_UINT32(au8Tmp, (u16ESizeWords * 4) - 4); + while((u32Exponent & NBIT31)== 0) + { + u32Exponent <<= 1; + u8EMswBits --; + } + + /*------- M -------*/ + m2m_memset(au8Tmp, 0, sizeof(au8Tmp)); + FlipBuffer(pu8M, au8Tmp, u16XSize); + nm_write_block(u32MAddr, au8Tmp, u16XSizeWords * 4); + + /* Program the addresses of the input operands. + */ + nm_write_reg(BIGINT_ADDR_X, u32XAddr); + nm_write_reg(BIGINT_ADDR_E, u32EAddr); + nm_write_reg(BIGINT_ADDR_M, u32MAddr); + nm_write_reg(BIGINT_ADDR_R, u32RAddr); + + /* Mprime. + */ + nm_write_reg(BIGINT_M_PRIME,u32Mprime); + + /* Length. + */ + u32Reg = (u16XSizeWords & 0xFF); + u32Reg += ((u16ESizeWords & 0xFF) << 8); + u32Reg += (u8EMswBits << 16); + nm_write_reg(BIGINT_LENGTH,u32Reg); + + /* CTRL Register. + */ + u32Reg = nm_read_reg(BIGINT_MISC_CTRL); + u32Reg ^= BIGINT_MISC_CTRL_CTL_START; + u32Reg |= BIGINT_MISC_CTRL_CTL_FORCE_BARRETT; + //u32Reg |= BIGINT_MISC_CTRL_CTL_M_PRIME_VALID; +#if ENABLE_FLIPPING == 0 + u32Reg |= BIGINT_MISC_CTRL_CTL_MSW_FIRST; +#endif + nm_write_reg(BIGINT_MISC_CTRL,u32Reg); + + /* Wait for computation to complete. */ + while(1) + { + u32Reg = nm_read_reg(BIGINT_IRQ_STS); + if(u32Reg & BIGINT_IRQ_STS_DONE) + { + break; + } + } + nm_write_reg(BIGINT_IRQ_STS,0); + m2m_memset(au8Tmp, 0, sizeof(au8Tmp)); + nm_read_block(u32RAddr, au8Tmp, u16RSize); + FlipBuffer(au8Tmp, pu8R, u16RSize); +} + + + +#define MD5_DIGEST_SIZE (16) +#define SHA1_DIGEST_SIZE (20) + +static const uint8 au8TEncodingMD5[] = +{ + 0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, + 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, + 0x04 +}; +/*!< Fixed part of the Encoding T for the MD5 hash algorithm. +*/ + + +static const uint8 au8TEncodingSHA1[] = +{ + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, + 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04 +}; +/*!< Fixed part of the Encoding T for the SHA-1 hash algorithm. +*/ + + +static const uint8 au8TEncodingSHA2[] = +{ + 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, + 0x00, 0x04 +}; +/*!< Fixed part of the Encoding T for the SHA-2 hash algorithm. +*/ + + +sint8 m2m_crypto_rsa_sign_verify(uint8 *pu8N, uint16 u16NSize, uint8 *pu8E, uint16 u16ESize, uint8 *pu8SignedMsgHash, + uint16 u16HashLength, uint8 *pu8RsaSignature) +{ + sint8 s8Ret = M2M_RSA_SIGN_FAIL; + + if((pu8N != NULL) && (pu8E != NULL) && (pu8RsaSignature != NULL) && (pu8SignedMsgHash != NULL)) + { + uint16 u16TLength, u16TEncodingLength; + uint8 *pu8T; + uint8 au8EM[512]; + + /* Selection of correct T Encoding based on the hash size. + */ + if(u16HashLength == MD5_DIGEST_SIZE) + { + pu8T = (uint8*)au8TEncodingMD5; + u16TEncodingLength = sizeof(au8TEncodingMD5); + } + else if(u16HashLength == SHA1_DIGEST_SIZE) + { + pu8T = (uint8*)au8TEncodingSHA1; + u16TEncodingLength = sizeof(au8TEncodingSHA1); + } + else + { + pu8T = (uint8*)au8TEncodingSHA2; + u16TEncodingLength = sizeof(au8TEncodingSHA2); + } + u16TLength = u16TEncodingLength + 1 + u16HashLength; + + /* If emLen < tLen + 11. + */ + if(u16NSize >= (u16TLength + 11)) + { + uint32 u32PSLength,u32Idx = 0; + + /* + RSA verification + */ + BigInt_ModExp(pu8RsaSignature, u16NSize, pu8E, u16ESize, pu8N, u16NSize, au8EM, u16NSize); + + u32PSLength = u16NSize - u16TLength - 3; + + /* + The calculated EM must match the following pattern. + *======*======*======*======*======* + * 0x00 || 0x01 || PS || 0x00 || T * + *======*======*======*======*======* + Where PS is all 0xFF + T is defined based on the hash algorithm. + */ + if((au8EM[0] == 0x00) && (au8EM[1] == 0x01)) + { + for(u32Idx = 2; au8EM[u32Idx] == 0xFF; u32Idx ++); + if(u32Idx == (u32PSLength + 2)) + { + if(au8EM[u32Idx ++] == 0x00) + { + if(!m2m_memcmp(&au8EM[u32Idx], pu8T, u16TEncodingLength)) + { + u32Idx += u16TEncodingLength; + if(au8EM[u32Idx ++] == u16HashLength) + s8Ret = m2m_memcmp(&au8EM[u32Idx], pu8SignedMsgHash, u16HashLength); + } + } + } + } + } + } + return s8Ret; +} + + +sint8 m2m_crypto_rsa_sign_gen(uint8 *pu8N, uint16 u16NSize, uint8 *pu8d, uint16 u16dSize, uint8 *pu8SignedMsgHash, + uint16 u16HashLength, uint8 *pu8RsaSignature) +{ + sint8 s8Ret = M2M_RSA_SIGN_FAIL; + + if((pu8N != NULL) && (pu8d != NULL) && (pu8RsaSignature != NULL) && (pu8SignedMsgHash != NULL)) + { + uint16 u16TLength, u16TEncodingLength; + uint8 *pu8T; + uint8 au8EM[512]; + + /* Selection of correct T Encoding based on the hash size. + */ + if(u16HashLength == MD5_DIGEST_SIZE) + { + pu8T = (uint8*)au8TEncodingMD5; + u16TEncodingLength = sizeof(au8TEncodingMD5); + } + else if(u16HashLength == SHA1_DIGEST_SIZE) + { + pu8T = (uint8*)au8TEncodingSHA1; + u16TEncodingLength = sizeof(au8TEncodingSHA1); + } + else + { + pu8T = (uint8*)au8TEncodingSHA2; + u16TEncodingLength = sizeof(au8TEncodingSHA2); + } + u16TLength = u16TEncodingLength + 1 + u16HashLength; + + /* If emLen < tLen + 11. + */ + if(u16NSize >= (u16TLength + 11)) + { + uint16 u16PSLength = 0; + uint16 u16Offset = 0; + + /* + The calculated EM must match the following pattern. + *======*======*======*======*======* + * 0x00 || 0x01 || PS || 0x00 || T * + *======*======*======*======*======* + Where PS is all 0xFF + T is defined based on the hash algorithm. + */ + au8EM[u16Offset ++] = 0; + au8EM[u16Offset ++] = 1; + u16PSLength = u16NSize - u16TLength - 3; + m2m_memset(&au8EM[u16Offset], 0xFF, u16PSLength); + u16Offset += u16PSLength; + au8EM[u16Offset ++] = 0; + m2m_memcpy(&au8EM[u16Offset], pu8T, u16TEncodingLength); + u16Offset += u16TEncodingLength; + au8EM[u16Offset ++] = u16HashLength; + m2m_memcpy(&au8EM[u16Offset], pu8SignedMsgHash, u16HashLength); + + /* + RSA Signature Generation + */ + BigInt_ModExp(au8EM, u16NSize, pu8d, u16dSize, pu8N, u16NSize, pu8RsaSignature, u16NSize); + s8Ret = M2M_RSA_SIGN_OK; + } + } + return s8Ret; +} + +#endif /* CONF_CRYPTO */ + +#ifdef CONF_CRYPTO_SOFT + +typedef struct { + tpfAppCryproCb pfAppCryptoCb; + uint8 * pu8Digest; + uint8 * pu8Rsa; + uint8 u8CryptoBusy; +}tstrCryptoCtxt; + +typedef struct { + uint8 au8N[M2M_MAX_RSA_LEN]; + uint8 au8E[M2M_MAX_RSA_LEN]; + uint8 au8Hash[M2M_SHA256_DIGEST_LEN]; + uint16 u16Nsz; + uint16 u16Esz; + uint16 u16Hsz; + uint8 _pad16_[2]; +}tstrRsaPayload; + +static tstrCryptoCtxt gstrCryptoCtxt; + + +/** +* @fn m2m_crypto_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr) +* @brief WiFi call back function +* @param [in] u8OpCode +* HIF Opcode type. +* @param [in] u16DataSize +* HIF data length. +* @param [in] u32Addr +* HIF address. +* @author +* @date +* @version 1.0 +*/ +static void m2m_crypto_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr) +{ + sint8 ret = M2M_SUCCESS; + gstrCryptoCtxt.u8CryptoBusy = 0; + if(u8OpCode == M2M_CRYPTO_RESP_SHA256_INIT) + { + tstrM2mSha256Ctxt strCtxt; + if (hif_receive(u32Addr, (uint8*) &strCtxt,sizeof(tstrM2mSha256Ctxt), 0) == M2M_SUCCESS) + { + tstrCyptoResp strResp; + if(hif_receive(u32Addr + sizeof(tstrM2mSha256Ctxt), (uint8*) &strResp,sizeof(tstrCyptoResp), 1) == M2M_SUCCESS) + { + if (gstrCryptoCtxt.pfAppCryptoCb) + gstrCryptoCtxt.pfAppCryptoCb(u8OpCode,&strResp,&strCtxt); + } + } + } + else if(u8OpCode == M2M_CRYPTO_RESP_SHA256_UPDATE) + { + tstrM2mSha256Ctxt strCtxt; + if (hif_receive(u32Addr, (uint8*) &strCtxt,sizeof(tstrM2mSha256Ctxt), 0) == M2M_SUCCESS) + { + tstrCyptoResp strResp; + if (hif_receive(u32Addr + sizeof(tstrM2mSha256Ctxt), (uint8*) &strResp,sizeof(tstrCyptoResp), 1) == M2M_SUCCESS) + { + if (gstrCryptoCtxt.pfAppCryptoCb) + gstrCryptoCtxt.pfAppCryptoCb(u8OpCode,&strResp,&strCtxt); + } + } + + } + else if(u8OpCode == M2M_CRYPTO_RESP_SHA256_FINSIH) + { + tstrCyptoResp strResp; + if (hif_receive(u32Addr + sizeof(tstrM2mSha256Ctxt), (uint8*) &strResp,sizeof(tstrCyptoResp), 0) == M2M_SUCCESS) + { + if (hif_receive(u32Addr + sizeof(tstrM2mSha256Ctxt) + sizeof(tstrCyptoResp), (uint8*)gstrCryptoCtxt.pu8Digest,M2M_SHA256_DIGEST_LEN, 1) == M2M_SUCCESS) + { + if (gstrCryptoCtxt.pfAppCryptoCb) + gstrCryptoCtxt.pfAppCryptoCb(u8OpCode,&strResp,gstrCryptoCtxt.pu8Digest); + + } + } + } + else if(u8OpCode == M2M_CRYPTO_RESP_RSA_SIGN_GEN) + { + tstrCyptoResp strResp; + if (hif_receive(u32Addr + sizeof(tstrRsaPayload), (uint8*)&strResp,sizeof(tstrCyptoResp), 0) == M2M_SUCCESS) + { + if (hif_receive(u32Addr + sizeof(tstrRsaPayload) + sizeof(tstrCyptoResp), (uint8*)gstrCryptoCtxt.pu8Rsa,M2M_MAX_RSA_LEN, 0) == M2M_SUCCESS) + { + if (gstrCryptoCtxt.pfAppCryptoCb) + gstrCryptoCtxt.pfAppCryptoCb(u8OpCode,&strResp,gstrCryptoCtxt.pu8Rsa); + } + } + } + else if(u8OpCode == M2M_CRYPTO_RESP_RSA_SIGN_VERIFY) + { + tstrCyptoResp strResp; + if (hif_receive(u32Addr + sizeof(tstrRsaPayload), (uint8*)&strResp,sizeof(tstrCyptoResp), 1) == M2M_SUCCESS) + { + if (gstrCryptoCtxt.pfAppCryptoCb) + gstrCryptoCtxt.pfAppCryptoCb(u8OpCode,&strResp,NULL); + } + } + else + { + M2M_ERR("u8Code %d ??\n",u8OpCode); + } + +} +/*! +@fn \ + sint8 m2m_crypto_init(); + +@brief crypto initialization + +@param[in] pfAppCryproCb + +*/ +sint8 m2m_crypto_init(tpfAppCryproCb pfAppCryproCb) +{ + sint8 ret = M2M_ERR_FAIL; + m2m_memset((uint8*)&gstrCryptoCtxt,0,sizeof(tstrCryptoCtxt)); + if(pfAppCryproCb != NULL) + { + gstrCryptoCtxt.pfAppCryptoCb = pfAppCryproCb; + ret = hif_register_cb(M2M_REQ_GROUP_CRYPTO,m2m_crypto_cb); + } + return ret; +} +/*! +@fn \ + sint8 m2m_sha256_hash_init(tstrM2mSha256Ctxt *psha256Ctxt); + +@brief SHA256 hash initialization + +@param[in] psha256Ctxt + Pointer to a sha256 context allocated by the caller. +*/ +sint8 m2m_crypto_sha256_hash_init(tstrM2mSha256Ctxt *psha256Ctxt) +{ + sint8 ret = M2M_ERR_FAIL; + if((psha256Ctxt != NULL)&&(!gstrCryptoCtxt.u8CryptoBusy)) + { + ret = hif_send(M2M_REQ_GROUP_CRYPTO,M2M_CRYPTO_REQ_SHA256_INIT|M2M_REQ_DATA_PKT,(uint8*)psha256Ctxt,sizeof(tstrM2mSha256Ctxt),NULL,0,0); + } + return ret; +} + + +/*! +@fn \ + sint8 m2m_sha256_hash_update(tstrM2mSha256Ctxt *psha256Ctxt, uint8 *pu8Data, uint16 u16DataLength); + +@brief SHA256 hash update + +@param [in] psha256Ctxt + Pointer to the sha256 context. + +@param [in] pu8Data + Buffer holding the data submitted to the hash. + +@param [in] u16DataLength + Size of the data bufefr in bytes. +*/ +sint8 m2m_crypto_sha256_hash_update(tstrM2mSha256Ctxt *psha256Ctxt, uint8 *pu8Data, uint16 u16DataLength) +{ + sint8 ret = M2M_ERR_FAIL; + if((!gstrCryptoCtxt.u8CryptoBusy) && (psha256Ctxt != NULL) && (pu8Data != NULL) && (u16DataLength < M2M_SHA256_MAX_DATA)) + { + ret = hif_send(M2M_REQ_GROUP_CRYPTO,M2M_CRYPTO_REQ_SHA256_UPDATE|M2M_REQ_DATA_PKT,(uint8*)psha256Ctxt,sizeof(tstrM2mSha256Ctxt),pu8Data,u16DataLength,sizeof(tstrM2mSha256Ctxt) + sizeof(tstrCyptoResp)); + } + return ret; + +} + + +/*! +@fn \ + sint8 m2m_sha256_hash_finish(tstrM2mSha256Ctxt *psha256Ctxt, uint8 *pu8Sha256Digest); + +@brief SHA256 hash finalization + +@param[in] psha256Ctxt + Pointer to a sha256 context allocated by the caller. + +@param [in] pu8Sha256Digest + Buffer allocated by the caller which will hold the resultant SHA256 Digest. It must be allocated no less than M2M_SHA256_DIGEST_LEN. +*/ +sint8 m2m_crypto_sha256_hash_finish(tstrM2mSha256Ctxt *psha256Ctxt, uint8 *pu8Sha256Digest) +{ + sint8 ret = M2M_ERR_FAIL; + if((!gstrCryptoCtxt.u8CryptoBusy) && (psha256Ctxt != NULL) && (pu8Sha256Digest != NULL)) + { + gstrCryptoCtxt.pu8Digest = pu8Sha256Digest; + ret = hif_send(M2M_REQ_GROUP_CRYPTO,M2M_CRYPTO_REQ_SHA256_FINSIH|M2M_REQ_DATA_PKT,(uint8*)psha256Ctxt,sizeof(tstrM2mSha256Ctxt),NULL,0,0); + } + return ret; +} + + + + +/*! +@fn \ + sint8 m2m_rsa_sign_verify(uint8 *pu8N, uint16 u16NSize, uint8 *pu8E, uint16 u16ESize, uint8 *pu8SignedMsgHash, \ + uint16 u16HashLength, uint8 *pu8RsaSignature); + +@brief RSA Signature Verification + + The function shall request the RSA Signature verification from the WINC Firmware for the given message. The signed message shall be + compressed to the corresponding hash algorithm before calling this function. + The hash type is identified by the given hash length. For example, if the hash length is 32 bytes, then it is SHA256. + +@param[in] pu8N + RSA Key modulus n. + +@param[in] u16NSize + Size of the RSA modulus n in bytes. + +@param[in] pu8E + RSA public exponent. + +@param[in] u16ESize + Size of the RSA public exponent in bytes. + +@param[in] pu8SignedMsgHash + The hash digest of the signed message. + +@param[in] u16HashLength + The length of the hash digest. + +@param[out] pu8RsaSignature + Signature value to be verified. +*/ + + +sint8 m2m_crypto_rsa_sign_verify(uint8 *pu8N, uint16 u16NSize, uint8 *pu8E, uint16 u16ESize, uint8 *pu8SignedMsgHash, + uint16 u16HashLength, uint8 *pu8RsaSignature) +{ + sint8 ret = M2M_ERR_FAIL; + if((!gstrCryptoCtxt.u8CryptoBusy) && (pu8N != NULL) && (pu8E != NULL) && (pu8RsaSignature != NULL) && (pu8SignedMsgHash != NULL) + && (u16NSize != 0) && (u16ESize != 0) && (u16HashLength != 0) && (pu8RsaSignature != NULL) ) + + { + tstrRsaPayload strRsa = {0}; + + m2m_memcpy(strRsa.au8N,pu8N,u16NSize); + m2m_memcpy(strRsa.au8E,pu8E,u16ESize); + m2m_memcpy(strRsa.au8Hash,pu8SignedMsgHash,u16HashLength); + + strRsa.u16Esz = u16ESize; + strRsa.u16Hsz = u16HashLength; + strRsa.u16Nsz = u16NSize; + + ret = hif_send(M2M_REQ_GROUP_CRYPTO,M2M_CRYPTO_REQ_RSA_SIGN_VERIFY|M2M_REQ_DATA_PKT,(uint8*)&strRsa,sizeof(tstrRsaPayload),NULL,0,0); + + } + return ret; +} + + +/*! +@fn \ + sint8 m2m_rsa_sign_gen(uint8 *pu8N, uint16 u16NSize, uint8 *pu8d, uint16 u16dSize, uint8 *pu8SignedMsgHash, \ + uint16 u16HashLength, uint8 *pu8RsaSignature); + +@brief RSA Signature Generation + + The function shall request the RSA Signature generation from the WINC Firmware for the given message. The signed message shall be + compressed to the corresponding hash algorithm before calling this function. + The hash type is identified by the given hash length. For example, if the hash length is 32 bytes, then it is SHA256. + +@param[in] pu8N + RSA Key modulus n. + +@param[in] u16NSize + Size of the RSA modulus n in bytes. + +@param[in] pu8d + RSA private exponent. + +@param[in] u16dSize + Size of the RSA private exponent in bytes. + +@param[in] pu8SignedMsgHash + The hash digest of the signed message. + +@param[in] u16HashLength + The length of the hash digest. + +@param[out] pu8RsaSignature + Pointer to a user buffer allocated by teh caller shall hold the generated signature. +*/ +sint8 m2m_crypto_rsa_sign_gen(uint8 *pu8N, uint16 u16NSize, uint8 *pu8d, uint16 u16dSize, uint8 *pu8SignedMsgHash, + uint16 u16HashLength, uint8 *pu8RsaSignature) +{ + sint8 ret = M2M_ERR_FAIL; + if((!gstrCryptoCtxt.u8CryptoBusy) && (pu8N != NULL) && (pu8d != NULL) && (pu8RsaSignature != NULL) && (pu8SignedMsgHash != NULL) + && (u16NSize != 0) && (u16dSize != 0) && (u16HashLength != 0) && (pu8RsaSignature != NULL)) + + { + tstrRsaPayload strRsa = {0}; + + m2m_memcpy(strRsa.au8N,pu8N,u16NSize); + m2m_memcpy(strRsa.au8E,pu8d,u16dSize); + m2m_memcpy(strRsa.au8Hash,pu8SignedMsgHash,u16HashLength); + + strRsa.u16Esz = u16dSize; + strRsa.u16Hsz = u16HashLength; + strRsa.u16Nsz = u16NSize; + + gstrCryptoCtxt.pu8Rsa = pu8RsaSignature; + ret = hif_send(M2M_REQ_GROUP_CRYPTO,M2M_CRYPTO_REQ_RSA_SIGN_GEN|M2M_REQ_DATA_PKT,(uint8*)&strRsa,sizeof(tstrRsaPayload),NULL,0,0); + + } + return ret; +} + +#endif \ No newline at end of file diff --git a/lib/WiFi101/src/driver/source/m2m_hif.c b/lib/WiFi101/src/driver/source/m2m_hif.c new file mode 100644 index 0000000..95ca997 --- /dev/null +++ b/lib/WiFi101/src/driver/source/m2m_hif.c @@ -0,0 +1,766 @@ +/** + * + * \file + * + * \brief This module contains M2M host interface APIs implementation. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include "common/include/nm_common.h" +#include "driver/source/nmbus.h" +#include "bsp/include/nm_bsp.h" +#include "m2m_hif.h" +#include "driver/include/m2m_types.h" +#include "driver/source/nmasic.h" +#include "driver/include/m2m_periph.h" + +#if (defined NM_EDGE_INTERRUPT)&&(defined NM_LEVEL_INTERRUPT) +#error "only one type of interrupt NM_EDGE_INTERRUPT,NM_LEVEL_INTERRUPT" +#endif + +#if !((defined NM_EDGE_INTERRUPT)||(defined NM_LEVEL_INTERRUPT)) +#error "define interrupt type NM_EDGE_INTERRUPT,NM_LEVEL_INTERRUPT" +#endif + +#ifndef CORTUS_APP +#define NMI_AHB_DATA_MEM_BASE 0x30000 +#define NMI_AHB_SHARE_MEM_BASE 0xd0000 + +#define WIFI_HOST_RCV_CTRL_0 (0x1070) +#define WIFI_HOST_RCV_CTRL_1 (0x1084) +#define WIFI_HOST_RCV_CTRL_2 (0x1078) +#define WIFI_HOST_RCV_CTRL_3 (0x106c) +#define WIFI_HOST_RCV_CTRL_4 (0x150400) +#define WIFI_HOST_RCV_CTRL_5 (0x1088) + +typedef struct { + uint8 u8ChipMode; + uint8 u8ChipSleep; + uint8 u8HifRXDone; + uint8 u8Interrupt; + uint32 u32RxAddr; + uint32 u32RxSize; + tpfHifCallBack pfWifiCb; + tpfHifCallBack pfIpCb; + tpfHifCallBack pfOtaCb; + tpfHifCallBack pfSigmaCb; + tpfHifCallBack pfHifCb; + tpfHifCallBack pfCryptoCb; + tpfHifCallBack pfSslCb; +}tstrHifContext; + +volatile tstrHifContext gstrHifCxt; +#ifdef ARDUINO +volatile uint8 hif_receive_blocked = 0; +#endif + +static void isr(void) +{ + gstrHifCxt.u8Interrupt++; +#ifdef NM_LEVEL_INTERRUPT + nm_bsp_interrupt_ctrl(0); +#endif +} +static sint8 hif_set_rx_done(void) +{ + uint32 reg; + sint8 ret = M2M_SUCCESS; + +#ifdef ARDUINO + hif_receive_blocked = 0; +#endif + gstrHifCxt.u8HifRXDone = 0; +#ifdef NM_EDGE_INTERRUPT + nm_bsp_interrupt_ctrl(1); +#endif + ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_0,®); + if(ret != M2M_SUCCESS)goto ERR1; + /* Set RX Done */ + reg |= NBIT1; + ret = nm_write_reg(WIFI_HOST_RCV_CTRL_0,reg); + if(ret != M2M_SUCCESS)goto ERR1; +#ifdef NM_LEVEL_INTERRUPT + nm_bsp_interrupt_ctrl(1); +#endif +ERR1: + return ret; + +} +/** +* @fn static void m2m_hif_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr) +* @brief WiFi call back function +* @param [in] u8OpCode +* HIF Opcode type. +* @param [in] u16DataSize +* HIF data length. +* @param [in] u32Addr +* HIF address. +* @param [in] grp +* HIF group type. +* @author +* @date +* @version 1.0 +*/ +static void m2m_hif_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr) +{ +#ifdef ARDUINO + // Silence "unused" warning + (void)u8OpCode; + (void)u16DataSize; + (void)u32Addr; +#endif +} +/** +* @fn NMI_API sint8 hif_chip_wake(void); +* @brief To Wakeup the chip. +* @return The function shall return ZERO for successful operation and a negative value otherwise. +*/ + +sint8 hif_chip_wake(void) +{ + sint8 ret = M2M_SUCCESS; + if(gstrHifCxt.u8HifRXDone) + { + /*chip already wake for the rx not done no need to send wake request*/ + return ret; + } + if(gstrHifCxt.u8ChipSleep == 0) + { + if(gstrHifCxt.u8ChipMode != M2M_NO_PS) + { + ret = chip_wake(); + if(ret != M2M_SUCCESS)goto ERR1; + } + else + { + } + } + gstrHifCxt.u8ChipSleep++; +ERR1: + return ret; +} +/*! +@fn \ + NMI_API void hif_set_sleep_mode(uint8 u8Pstype); + +@brief + Set the sleep mode of the HIF layer. + +@param [in] u8Pstype + Sleep mode. + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ + +void hif_set_sleep_mode(uint8 u8Pstype) +{ + gstrHifCxt.u8ChipMode = u8Pstype; +} +/*! +@fn \ + NMI_API uint8 hif_get_sleep_mode(void); + +@brief + Get the sleep mode of the HIF layer. + +@return + The function SHALL return the sleep mode of the HIF layer. +*/ + +uint8 hif_get_sleep_mode(void) +{ + return gstrHifCxt.u8ChipMode; +} + +/** +* @fn NMI_API sint8 hif_chip_sleep_sc(void); +* @brief To clear the chip sleep but keep the chip sleep +* @return The function shall return ZERO for successful operation and a negative value otherwise. +*/ + +sint8 hif_chip_sleep_sc(void) +{ + if(gstrHifCxt.u8ChipSleep >= 1) + { + gstrHifCxt.u8ChipSleep--; + } + return M2M_SUCCESS; +} +/** +* @fn NMI_API sint8 hif_chip_sleep(void); +* @brief To make the chip sleep. +* @return The function shall return ZERO for successful operation and a negative value otherwise. +*/ + +sint8 hif_chip_sleep(void) +{ + sint8 ret = M2M_SUCCESS; + + if(gstrHifCxt.u8ChipSleep >= 1) + { + gstrHifCxt.u8ChipSleep--; + } + + if(gstrHifCxt.u8ChipSleep == 0) + { + if(gstrHifCxt.u8ChipMode != M2M_NO_PS) + { + ret = chip_sleep(); + if(ret != M2M_SUCCESS)goto ERR1; + + } + else + { + } + } +ERR1: + return ret; +} +/** +* @fn NMI_API sint8 hif_init(void * arg); +* @brief To initialize HIF layer. +* @param [in] arg +* Pointer to the arguments. +* @return The function shall return ZERO for successful operation and a negative value otherwise. +*/ + +sint8 hif_init(void * arg) +{ +#ifdef ARDUINO + (void)arg; // Silence "unused" warning +#endif + m2m_memset((uint8*)&gstrHifCxt,0,sizeof(tstrHifContext)); + nm_bsp_register_isr(isr); + hif_register_cb(M2M_REQ_GROUP_HIF,m2m_hif_cb); + return M2M_SUCCESS; +} +/** +* @fn NMI_API sint8 hif_deinit(void * arg); +* @brief To De-initialize HIF layer. +* @param [in] arg +* Pointer to the arguments. +* @return The function shall return ZERO for successful operation and a negative value otherwise. +*/ +sint8 hif_deinit(void * arg) +{ +#ifdef ARDUINO + (void)arg; // Silence "unused" warning +#endif + sint8 ret = M2M_SUCCESS; + ret = hif_chip_wake(); + m2m_memset((uint8*)&gstrHifCxt,0,sizeof(tstrHifContext)); + return ret; +} +/** +* @fn NMI_API sint8 hif_send(uint8 u8Gid,uint8 u8Opcode,uint8 *pu8CtrlBuf,uint16 u16CtrlBufSize, + uint8 *pu8DataBuf,uint16 u16DataSize, uint16 u16DataOffset) +* @brief Send packet using host interface. + +* @param [in] u8Gid +* Group ID. +* @param [in] u8Opcode +* Operation ID. +* @param [in] pu8CtrlBuf +* Pointer to the Control buffer. +* @param [in] u16CtrlBufSize + Control buffer size. +* @param [in] u16DataOffset + Packet Data offset. +* @param [in] pu8DataBuf +* Packet buffer Allocated by the caller. +* @param [in] u16DataSize + Packet buffer size (including the HIF header). +* @return The function shall return ZERO for successful operation and a negative value otherwise. +*/ + +sint8 hif_send(uint8 u8Gid,uint8 u8Opcode,uint8 *pu8CtrlBuf,uint16 u16CtrlBufSize, + uint8 *pu8DataBuf,uint16 u16DataSize, uint16 u16DataOffset) +{ + sint8 ret = M2M_ERR_SEND; + volatile tstrHifHdr strHif; + + strHif.u8Opcode = u8Opcode&(~NBIT7); + strHif.u8Gid = u8Gid; + strHif.u16Length = M2M_HIF_HDR_OFFSET; + if(pu8DataBuf != NULL) + { + strHif.u16Length += u16DataOffset + u16DataSize; + } + else + { + strHif.u16Length += u16CtrlBufSize; + } + ret = hif_chip_wake(); + if(ret == M2M_SUCCESS) + { + volatile uint32 reg, dma_addr = 0; + volatile uint16 cnt = 0; +//#define OPTIMIZE_BUS +/*please define in firmware also*/ +#ifndef OPTIMIZE_BUS + reg = 0UL; + reg |= (uint32)u8Gid; + reg |= ((uint32)u8Opcode<<8); + reg |= ((uint32)strHif.u16Length<<16); + ret = nm_write_reg(NMI_STATE_REG,reg); + if(M2M_SUCCESS != ret) goto ERR1; + + reg = 0UL; + reg |= NBIT1; + ret = nm_write_reg(WIFI_HOST_RCV_CTRL_2, reg); + if(M2M_SUCCESS != ret) goto ERR1; +#else + reg = 0UL; + reg |= NBIT1; + reg |= ((u8Opcode & NBIT7) ? (NBIT2):(0)); /*Data = 1 or config*/ + reg |= (u8Gid == M2M_REQ_GROUP_IP) ? (NBIT3):(0); /*IP = 1 or non IP*/ + reg |= ((uint32)strHif.u16Length << 4); /*length of pkt max = 4096*/ + ret = nm_write_reg(WIFI_HOST_RCV_CTRL_2, reg); + if(M2M_SUCCESS != ret) goto ERR1; +#endif + dma_addr = 0; + + for(cnt = 0; cnt < 1000; cnt ++) + { + ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_2,(uint32 *)®); + if(ret != M2M_SUCCESS) break; + /* + * If it takes too long to get a response, the slow down to + * avoid back-to-back register read operations. + */ + if(cnt >= 500) { + if(cnt < 501) { + M2M_INFO("Slowing down...\n"); + } + nm_bsp_sleep(1); + } + if (!(reg & NBIT1)) + { + ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_4,(uint32 *)&dma_addr); + if(ret != M2M_SUCCESS) { + /*in case of read error clear the DMA address and return error*/ + dma_addr = 0; + goto ERR1; + } + /*in case of success break */ + break; + } + } + + if (dma_addr != 0) + { + volatile uint32 u32CurrAddr; + u32CurrAddr = dma_addr; + strHif.u16Length=NM_BSP_B_L_16(strHif.u16Length); + ret = nm_write_block(u32CurrAddr, (uint8*)&strHif, M2M_HIF_HDR_OFFSET); + if(M2M_SUCCESS != ret) goto ERR1; + u32CurrAddr += M2M_HIF_HDR_OFFSET; + if(pu8CtrlBuf != NULL) + { + ret = nm_write_block(u32CurrAddr, pu8CtrlBuf, u16CtrlBufSize); + if(M2M_SUCCESS != ret) goto ERR1; + u32CurrAddr += u16CtrlBufSize; + } + if(pu8DataBuf != NULL) + { + u32CurrAddr += (u16DataOffset - u16CtrlBufSize); + ret = nm_write_block(u32CurrAddr, pu8DataBuf, u16DataSize); + if(M2M_SUCCESS != ret) goto ERR1; + u32CurrAddr += u16DataSize; + } + + reg = dma_addr << 2; + reg |= NBIT1; + ret = nm_write_reg(WIFI_HOST_RCV_CTRL_3, reg); + if(M2M_SUCCESS != ret) goto ERR1; + } + else + { + ret = hif_chip_sleep(); + M2M_DBG("Failed to alloc rx size %d\r",ret); + ret = M2M_ERR_MEM_ALLOC; + goto ERR2; + } + + } + else + { + M2M_ERR("(HIF)Fail to wakup the chip\n"); + goto ERR2; + } + /*actual sleep ret = M2M_SUCCESS*/ + ret = hif_chip_sleep(); + return ret; +ERR1: + /*reset the count but no actual sleep as it already bus error*/ + hif_chip_sleep_sc(); +ERR2: + /*logical error*/ + return ret; +} + +/** +* @fn hif_isr +* @brief Host interface interrupt service routine +* @author M. Abdelmawla +* @date 15 July 2012 +* @return 1 in case of interrupt received else 0 will be returned +* @version 1.0 +*/ +static sint8 hif_isr(void) +{ + sint8 ret = M2M_SUCCESS; + volatile uint32 reg; + volatile tstrHifHdr strHif; + +#ifdef ARDUINO + ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_0, (uint32*)®); +#else + ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_0, ®); +#endif + if(M2M_SUCCESS == ret) + { + if(reg & 0x1) /* New interrupt has been received */ + { + uint16 size; + + nm_bsp_interrupt_ctrl(0); + /*Clearing RX interrupt*/ + reg &= ~NBIT0; + ret = nm_write_reg(WIFI_HOST_RCV_CTRL_0,reg); + if(ret != M2M_SUCCESS)goto ERR1; + gstrHifCxt.u8HifRXDone = 1; + size = (uint16)((reg >> 2) & 0xfff); + if (size > 0) { + uint32 address = 0; + /** + start bus transfer + **/ + ret = nm_read_reg_with_ret(WIFI_HOST_RCV_CTRL_1, &address); + if(M2M_SUCCESS != ret) + { + M2M_ERR("(hif) WIFI_HOST_RCV_CTRL_1 bus fail\n"); + nm_bsp_interrupt_ctrl(1); + goto ERR1; + } + gstrHifCxt.u32RxAddr = address; + gstrHifCxt.u32RxSize = size; + ret = nm_read_block(address, (uint8*)&strHif, sizeof(tstrHifHdr)); + strHif.u16Length = NM_BSP_B_L_16(strHif.u16Length); + if(M2M_SUCCESS != ret) + { + M2M_ERR("(hif) address bus fail\n"); + nm_bsp_interrupt_ctrl(1); + goto ERR1; + } + if(strHif.u16Length != size) + { + if((size - strHif.u16Length) > 4) + { + M2M_ERR("(hif) Corrupted packet Size = %u \n", + size, strHif.u16Length, strHif.u8Gid, strHif.u8Opcode); + nm_bsp_interrupt_ctrl(1); + ret = M2M_ERR_BUS_FAIL; + goto ERR1; + } + } + + if(M2M_REQ_GROUP_WIFI == strHif.u8Gid) + { + if(gstrHifCxt.pfWifiCb) + gstrHifCxt.pfWifiCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET); + else +#ifdef ARDUINO + { +#endif + M2M_ERR("WIFI callback is not registered\n"); +#ifdef ARDUINO + } +#endif + } + else if(M2M_REQ_GROUP_IP == strHif.u8Gid) + { + if(gstrHifCxt.pfIpCb) + gstrHifCxt.pfIpCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET); + else +#ifdef ARDUINO + { +#endif + M2M_ERR("Scoket callback is not registered\n"); +#ifdef ARDUINO + } +#endif + } + else if(M2M_REQ_GROUP_OTA == strHif.u8Gid) + { + if(gstrHifCxt.pfOtaCb) + gstrHifCxt.pfOtaCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET); + else +#ifdef ARDUINO + { +#endif + M2M_ERR("Ota callback is not registered\n"); +#ifdef ARDUINO + } +#endif + } + else if(M2M_REQ_GROUP_CRYPTO == strHif.u8Gid) + { + if(gstrHifCxt.pfCryptoCb) + gstrHifCxt.pfCryptoCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET); + + else +#ifdef ARDUINO + { +#endif + M2M_ERR("Crypto callback is not registered\n"); +#ifdef ARDUINO + } +#endif + } + else if(M2M_REQ_GROUP_SIGMA == strHif.u8Gid) + { + if(gstrHifCxt.pfSigmaCb) + gstrHifCxt.pfSigmaCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET); + else +#ifdef ARDUINO + { +#endif + M2M_ERR("Sigma callback is not registered\n"); +#ifdef ARDUINO + } +#endif + } + else if(M2M_REQ_GROUP_SSL == strHif.u8Gid) + { + if(gstrHifCxt.pfSslCb) + gstrHifCxt.pfSslCb(strHif.u8Opcode,strHif.u16Length - M2M_HIF_HDR_OFFSET, address + M2M_HIF_HDR_OFFSET); + } + else + { + M2M_ERR("(hif) invalid group ID\n"); + ret = M2M_ERR_BUS_FAIL; + goto ERR1; + } + +#ifdef ARDUINO + if (hif_receive_blocked) { + return ret; + } +#endif + if(gstrHifCxt.u8HifRXDone) + { + M2M_ERR("(hif) host app didn't set RX Done <%u><%X>\n", strHif.u8Gid, strHif.u8Opcode); + ret = hif_set_rx_done(); + if(ret != M2M_SUCCESS) goto ERR1; + } + } + else + { + M2M_ERR("(hif) Wrong Size\n"); + ret = M2M_ERR_RCV; + goto ERR1; + } + } + else + { +#ifndef WIN32 + M2M_ERR("(hif) False interrupt %lx",reg); +#ifdef ARDUINO + // ignore false interrupts, since they cause infinite loops in hif_handle_isr +#else + ret = M2M_ERR_FAIL; +#endif + goto ERR1; +#else +#endif + } + } + else + { + M2M_ERR("(hif) Fail to Read interrupt reg\n"); + goto ERR1; + } + +ERR1: + return ret; +} + +/** +* @fn hif_handle_isr(void) +* @brief Handle interrupt received from NMC1500 firmware. +* @return The function SHALL return 0 for success and a negative value otherwise. +*/ + +sint8 hif_handle_isr(void) +{ + sint8 ret = M2M_SUCCESS; + +#ifdef ARDUINO + if (hif_receive_blocked) { + return ret; + } +#endif + + while (gstrHifCxt.u8Interrupt) { + /*must be at that place because of the race of interrupt increment and that decrement*/ + /*when the interrupt enabled*/ + gstrHifCxt.u8Interrupt--; + while(1) + { + ret = hif_isr(); +#ifdef ARDUINO + if (hif_receive_blocked) { + return ret; + } +#endif + if(ret == M2M_SUCCESS) { + /*we will try forever untill we get that interrupt*/ + /*Fail return errors here due to bus errors (reading expected values)*/ + break; + } else { + M2M_ERR("(HIF) Fail to handle interrupt %d try Again..\n",ret); + } + } + } + + return ret; +} +/* +* @fn hif_receive +* @brief Host interface interrupt serviece routine +* @param [in] u32Addr +* Receive start address +* @param [out] pu8Buf +* Pointer to receive buffer. Allocated by the caller +* @param [in] u16Sz +* Receive buffer size +* @param [in] isDone +* If you don't need any more packets send True otherwise send false +* @return The function shall return ZERO for successful operation and a negative value otherwise. +*/ +sint8 hif_receive(uint32 u32Addr, uint8 *pu8Buf, uint16 u16Sz, uint8 isDone) +{ + sint8 ret = M2M_SUCCESS; + if((u32Addr == 0)||(pu8Buf == NULL) || (u16Sz == 0)) + { + if(isDone) + { + /* set RX done */ + ret = hif_set_rx_done(); + } + else + { + ret = M2M_ERR_FAIL; + M2M_ERR(" hif_receive: Invalid argument\n"); + } + goto ERR1; + } + + if(u16Sz > gstrHifCxt.u32RxSize) + { + ret = M2M_ERR_FAIL; + M2M_ERR("APP Requested Size is larger than the recived buffer size <%u><%lu>\n",u16Sz, gstrHifCxt.u32RxSize); + goto ERR1; + } + if((u32Addr < gstrHifCxt.u32RxAddr)||((u32Addr + u16Sz)>(gstrHifCxt.u32RxAddr + gstrHifCxt.u32RxSize))) + { + ret = M2M_ERR_FAIL; + M2M_ERR("APP Requested Address beyond the recived buffer address and length\n"); + goto ERR1; + } + + /* Receive the payload */ + ret = nm_read_block(u32Addr, pu8Buf, u16Sz); + if(ret != M2M_SUCCESS)goto ERR1; + + /* check if this is the last packet */ + if((((gstrHifCxt.u32RxAddr + gstrHifCxt.u32RxSize) - (u32Addr + u16Sz)) <= 0) || isDone) + { + /* set RX done */ + ret = hif_set_rx_done(); + } + +ERR1: + return ret; +} + +/** +* @fn hif_register_cb +* @brief To set Callback function for every compantent Component +* @param [in] u8Grp +* Group to which the Callback function should be set. +* @param [in] fn +* function to be set +* @return The function shall return ZERO for successful operation and a negative value otherwise. +*/ + +sint8 hif_register_cb(uint8 u8Grp,tpfHifCallBack fn) +{ + sint8 ret = M2M_SUCCESS; + switch(u8Grp) + { + case M2M_REQ_GROUP_IP: + gstrHifCxt.pfIpCb = fn; + break; + case M2M_REQ_GROUP_WIFI: + gstrHifCxt.pfWifiCb = fn; + break; + case M2M_REQ_GROUP_OTA: + gstrHifCxt.pfOtaCb = fn; + break; + case M2M_REQ_GROUP_HIF: + gstrHifCxt.pfHifCb = fn; + break; + case M2M_REQ_GROUP_CRYPTO: + gstrHifCxt.pfCryptoCb = fn; + break; + case M2M_REQ_GROUP_SIGMA: + gstrHifCxt.pfSigmaCb = fn; + break; + case M2M_REQ_GROUP_SSL: + gstrHifCxt.pfSslCb = fn; + break; + default: + M2M_ERR("GRp ? %d\n",u8Grp); + ret = M2M_ERR_FAIL; + break; + } + return ret; +} + +#endif diff --git a/lib/WiFi101/src/driver/source/m2m_hif.h b/lib/WiFi101/src/driver/source/m2m_hif.h new file mode 100644 index 0000000..1187183 --- /dev/null +++ b/lib/WiFi101/src/driver/source/m2m_hif.h @@ -0,0 +1,249 @@ +/** + * + * \file + * + * \brief This module contains M2M host interface APIs implementation. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _M2M_HIF_ +#define _M2M_HIF_ + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +#include "common/include/nm_common.h" +/*!< Include depends on UNO Board is used or not*/ +#ifdef ENABLE_UNO_BOARD +#include "m2m_uno_hif.h" +#endif + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +MACROS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +#define M2M_HIF_MAX_PACKET_SIZE (1600 - 4) +/*!< Maximum size of the buffer could be transferred between Host and Firmware. +*/ + +#define M2M_HIF_HDR_OFFSET (sizeof(tstrHifHdr) + 4) + +/** +* @struct tstrHifHdr +* @brief Structure to hold HIF header +*/ +typedef struct +{ + uint8 u8Gid; /*!< Group ID */ + uint8 u8Opcode; /*!< OP code */ + uint16 u16Length; /*!< Payload length */ +}tstrHifHdr; + +#ifdef __cplusplus + extern "C" { +#endif + +/*! +@typedef typedef void (*tpfHifCallBack)(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr); +@brief used to point to Wi-Fi call back function depend on Arduino project or other projects. +@param [in] u8OpCode + HIF Opcode type. +@param [in] u16DataSize + HIF data length. +@param [in] u32Addr + HIF address. +@param [in] grp + HIF group type. +*/ +typedef void (*tpfHifCallBack)(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr); +/** +* @fn NMI_API sint8 hif_init(void * arg); +* @brief + To initialize HIF layer. +* @param [in] arg +* Pointer to the arguments. +* @return + The function shall return ZERO for successful operation and a negative value otherwise. +*/ +NMI_API sint8 hif_init(void * arg); +/** +* @fn NMI_API sint8 hif_deinit(void * arg); +* @brief + To Deinitialize HIF layer. +* @param [in] arg +* Pointer to the arguments. +* @return + The function shall return ZERO for successful operation and a negative value otherwise. +*/ +NMI_API sint8 hif_deinit(void * arg); +/** +* @fn NMI_API sint8 hif_send(uint8 u8Gid,uint8 u8Opcode,uint8 *pu8CtrlBuf,uint16 u16CtrlBufSize, + uint8 *pu8DataBuf,uint16 u16DataSize, uint16 u16DataOffset) +* @brief Send packet using host interface. + +* @param [in] u8Gid +* Group ID. +* @param [in] u8Opcode +* Operation ID. +* @param [in] pu8CtrlBuf +* Pointer to the Control buffer. +* @param [in] u16CtrlBufSize + Control buffer size. +* @param [in] u16DataOffset + Packet Data offset. +* @param [in] pu8DataBuf +* Packet buffer Allocated by the caller. +* @param [in] u16DataSize + Packet buffer size (including the HIF header). +* @return The function shall return ZERO for successful operation and a negative value otherwise. +*/ +NMI_API sint8 hif_send(uint8 u8Gid,uint8 u8Opcode,uint8 *pu8CtrlBuf,uint16 u16CtrlBufSize, + uint8 *pu8DataBuf,uint16 u16DataSize, uint16 u16DataOffset); +/* +* @fn hif_receive +* @brief Host interface interrupt serviece routine +* @param [in] u32Addr +* Receive start address +* @param [out] pu8Buf +* Pointer to receive buffer. Allocated by the caller +* @param [in] u16Sz +* Receive buffer size +* @param [in] isDone +* If you don't need any more packets send True otherwise send false +* @return + The function shall return ZERO for successful operation and a negative value otherwise. +*/ + +NMI_API sint8 hif_receive(uint32 u32Addr, uint8 *pu8Buf, uint16 u16Sz, uint8 isDone); +/** +* @fn hif_register_cb +* @brief + To set Callback function for every Component. + +* @param [in] u8Grp +* Group to which the Callback function should be set. + +* @param [in] fn +* function to be set to the specified group. +* @return + The function shall return ZERO for successful operation and a negative value otherwise. +*/ +NMI_API sint8 hif_register_cb(uint8 u8Grp,tpfHifCallBack fn); +/** +* @fn NMI_API sint8 hif_chip_sleep(void); +* @brief + To make the chip sleep. +* @return + The function shall return ZERO for successful operation and a negative value otherwise. +*/ +NMI_API sint8 hif_chip_sleep(void); +/** +* @fn NMI_API sint8 hif_chip_sleep_sc(void); +* @brief + To clear the chip count only but keep the chip awake +* @return + The function shall return ZERO for successful operation and a negative value otherwise. +*/ +NMI_API sint8 hif_chip_sleep_sc(void); +/** +* @fn NMI_API sint8 hif_chip_wake(void); +* @brief + To Wakeup the chip. +* @return + The function shall return ZERO for successful operation and a negative value otherwise. +*/ + +NMI_API sint8 hif_chip_wake(void); +/*! +@fn \ + NMI_API void hif_set_sleep_mode(uint8 u8Pstype); + +@brief + Set the sleep mode of the HIF layer. + +@param [in] u8Pstype + Sleep mode. + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ + +NMI_API void hif_set_sleep_mode(uint8 u8Pstype); +/*! +@fn \ + NMI_API uint8 hif_get_sleep_mode(void); + +@brief + Get the sleep mode of the HIF layer. + +@return + The function SHALL return the sleep mode of the HIF layer. +*/ + +NMI_API uint8 hif_get_sleep_mode(void); + +#ifdef CORTUS_APP +/** +* @fn hif_Resp_handler(uint8 *pu8Buffer, uint16 u16BufferSize) +* @brief + Response handler for HIF layer. + +* @param [in] pu8Buffer + Pointer to the buffer. + +* @param [in] u16BufferSize + Buffer size. + +* @return + The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 hif_Resp_handler(uint8 *pu8Buffer, uint16 u16BufferSize); +#endif + +/** +* @fn hif_handle_isr(void) +* @brief + Handle interrupt received from NMC1500 firmware. +* @return + The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 hif_handle_isr(void); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib/WiFi101/src/driver/source/m2m_ota.c b/lib/WiFi101/src/driver/source/m2m_ota.c new file mode 100644 index 0000000..cf4a30f --- /dev/null +++ b/lib/WiFi101/src/driver/source/m2m_ota.c @@ -0,0 +1,417 @@ +/** + * + * \file + * + * \brief NMC1500 IoT OTA Interface. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + + + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +#include "common/include/nm_common.h" +#include "driver/include/m2m_types.h" +#include "driver/include/m2m_ota.h" +#include "driver/source/m2m_hif.h" +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +MACROS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +DATA TYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +static tpfOtaUpdateCb gpfOtaUpdateCb = NULL; +static tpfOtaNotifCb gpfOtaNotifCb = NULL; + + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +FUNCTION PROTOTYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/** +* @fn m2m_wifi_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr, uint8 grp) +* @brief WiFi call back function +* @param [in] u8OpCode +* HIF Opcode type. +* @param [in] u16DataSize +* HIF data length. +* @param [in] u32Addr +* HIF address. +* @param [in] grp +* HIF group type. +* @author +* @date +* @version 1.0 +*/ +static void m2m_ota_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr) +{ +#ifdef ARDUINO + (void)u16DataSize; // Silence "unused" warning +#endif + sint8 ret = M2M_SUCCESS; + if(u8OpCode == M2M_OTA_RESP_NOTIF_UPDATE_INFO) + { + tstrOtaUpdateInfo strOtaUpdateInfo; + m2m_memset((uint8*)&strOtaUpdateInfo,0,sizeof(tstrOtaUpdateInfo)); + ret = hif_receive(u32Addr,(uint8*)&strOtaUpdateInfo,sizeof(tstrOtaUpdateInfo),0); + if(ret == M2M_SUCCESS) + { + if(gpfOtaNotifCb) + gpfOtaNotifCb(&strOtaUpdateInfo); + } + } + else if (u8OpCode == M2M_OTA_RESP_UPDATE_STATUS) + { + tstrOtaUpdateStatusResp strOtaUpdateStatusResp; + m2m_memset((uint8*)&strOtaUpdateStatusResp,0,sizeof(tstrOtaUpdateStatusResp)); + ret = hif_receive(u32Addr, (uint8*) &strOtaUpdateStatusResp,sizeof(tstrOtaUpdateStatusResp), 0); + if(ret == M2M_SUCCESS) + { + if(gpfOtaUpdateCb) + gpfOtaUpdateCb(strOtaUpdateStatusResp.u8OtaUpdateStatusType,strOtaUpdateStatusResp.u8OtaUpdateStatus); + } + } + else + { + M2M_ERR("Invaild OTA resp %d ?\n",u8OpCode); + } + +} +/*! +@fn \ + NMI_API sint8 m2m_ota_init(tpfOtaUpdateCb pfOtaUpdateCb, tpfOtaNotifCb pfOtaNotifCb); + +@brief + Initialize the OTA layer. + +@param [in] pfOtaUpdateCb + OTA Update callback function + +@param [in] pfOtaNotifCb + OTA notify callback function + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_init(tpfOtaUpdateCb pfOtaUpdateCb, tpfOtaNotifCb pfOtaNotifCb) +{ + sint8 ret = M2M_SUCCESS; + + if(pfOtaUpdateCb){ + gpfOtaUpdateCb = pfOtaUpdateCb; + }else{ + M2M_ERR("Invaild Ota update cb\n"); + } + if(pfOtaNotifCb){ + gpfOtaNotifCb = pfOtaNotifCb; + }else{ + M2M_ERR("Invaild Ota notify cb\n"); + } + + hif_register_cb(M2M_REQ_GROUP_OTA,m2m_ota_cb); + + return ret; +} +/*! +@fn \ + NMI_API sint8 m2m_ota_notif_set_url(uint8 * u8Url); + +@brief + Set the OTA url + +@param [in] u8Url + The url server address + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_notif_set_url(uint8 * u8Url) +{ + sint8 ret = M2M_SUCCESS; + uint16 u16UrlSize = m2m_strlen(u8Url) + 1; + /*Todo: we may change it to data pkt but we need to give it higer priority + but the priorty is not implemnted yet in data pkt + */ + ret = hif_send(M2M_REQ_GROUP_OTA,M2M_OTA_REQ_NOTIF_SET_URL,u8Url,u16UrlSize,NULL,0,0); + return ret; + +} + +/*! +@fn \ + NMI_API sint8 m2m_ota_notif_check_for_update(void); + +@brief + check for ota update + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_notif_check_for_update(void) +{ + sint8 ret = M2M_SUCCESS; + ret = hif_send(M2M_REQ_GROUP_OTA,M2M_OTA_REQ_NOTIF_CHECK_FOR_UPDATE,NULL,0,NULL,0,0); + return ret; +} + +/*! +@fn \ + NMI_API sint8 m2m_ota_notif_sched(uint32 u32Period); + +@brief + Schedule OTA update + +@param [in] u32Period + Period in days + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_notif_sched(uint32 u32Period) +{ +#ifdef ARDUINO + (void)u32Period; // Silence "unused" warning +#endif + sint8 ret = M2M_SUCCESS; + ret = hif_send(M2M_REQ_GROUP_OTA,M2M_OTA_REQ_NOTIF_CHECK_FOR_UPDATE,NULL,0,NULL,0,0); + return ret; +} + +/*! +@fn \ + NMI_API sint8 m2m_ota_start_update(uint8 * u8DownloadUrl); + +@brief + Request OTA start update using the downloaded url + +@param [in] u8DownloadUrl + The download firmware url, you get it from device info + +@return + The function SHALL return 0 for success and a negative value otherwise. + +*/ +NMI_API sint8 m2m_ota_start_update(uint8 * u8DownloadUrl) +{ + sint8 ret = M2M_SUCCESS; + uint16 u16DurlSize = m2m_strlen(u8DownloadUrl) + 1; + /*Todo: we may change it to data pkt but we need to give it higer priority + but the priorty is not implemnted yet in data pkt + */ + ret = hif_send(M2M_REQ_GROUP_OTA,M2M_OTA_REQ_START_FW_UPDATE,u8DownloadUrl,u16DurlSize,NULL,0,0); + return ret; +} +/*! +@fn \ + NMI_API sint8 m2m_ota_start_update_crt(uint8 * u8DownloadUrl); + +@brief + Request OTA start for the Cortus app image. + +@param [in] u8DownloadUrl + The cortus application image url. + +@return + The function SHALL return 0 for success and a negative value otherwise. + +*/ +NMI_API sint8 m2m_ota_start_update_crt(uint8 * u8DownloadUrl) +{ + sint8 ret = M2M_SUCCESS; + uint16 u16DurlSize = m2m_strlen(u8DownloadUrl) + 1; + ret = hif_send(M2M_REQ_GROUP_OTA,M2M_OTA_REQ_START_CRT_UPDATE,u8DownloadUrl,u16DurlSize,NULL,0,0); + return ret; +} + + +/*! +@fn \ + NMI_API sint8 m2m_ota_rollback(void); + +@brief + Request OTA Rollback image + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_rollback(void) +{ + sint8 ret = M2M_SUCCESS; + ret = hif_send(M2M_REQ_GROUP_OTA,M2M_OTA_REQ_ROLLBACK_FW,NULL,0,NULL,0,0); + return ret; +} +/*! +@fn \ + NMI_API sint8 m2m_ota_rollback_crt(void); + +@brief + Request Cortus application OTA Rollback image + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_rollback_crt(void) +{ + sint8 ret = M2M_SUCCESS; + ret = hif_send(M2M_REQ_GROUP_OTA,M2M_OTA_REQ_ROLLBACK_CRT,NULL,0,NULL,0,0); + return ret; +} + +/*! +@fn \ + NMI_API sint8 m2m_ota_abort(void); + +@brief + Request OTA Abort + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_abort(void) +{ + sint8 ret = M2M_SUCCESS; + ret = hif_send(M2M_REQ_GROUP_OTA,M2M_OTA_REQ_ABORT,NULL,0,NULL,0,0); + return ret; +} + + +/*! +@fn \ + NMI_API sint8 m2m_ota_switch_firmware(void); + +@brief + Switch to the upgraded Firmware + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_switch_firmware(void) +{ + sint8 ret = M2M_SUCCESS; + ret = hif_send(M2M_REQ_GROUP_OTA,M2M_OTA_REQ_SWITCH_FIRMWARE,NULL,0,NULL,0,0); + return ret; +} +/*! +@fn \ + NMI_API sint8 m2m_ota_switch_crt(void); + +@brief + Switch to the upgraded cortus application. + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_switch_crt(void) +{ + sint8 ret = M2M_SUCCESS; + ret = hif_send(M2M_REQ_GROUP_OTA,M2M_OTA_REQ_SWITCH_CRT_IMG,NULL,0,NULL,0,0); + return ret; +} + +/*! +@fn \ + NMI_API sint8 m2m_ota_get_firmware_version(tstrM2mRev * pstrRev); + +@brief + Get the OTA Firmware version. + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ota_get_firmware_version(tstrM2mRev * pstrRev) +{ + sint8 ret = M2M_SUCCESS; + ret = hif_chip_wake(); + if(ret == M2M_SUCCESS) + { + ret = nm_get_ota_firmware_info(pstrRev); + hif_chip_sleep(); + } + return ret; +} +#if 0 +#define M2M_OTA_FILE "../../../m2m_ota.dat" +NMI_API sint8 m2m_ota_test(void) +{ + uint32 page = 0; + uint8 buffer[1500]; + uint32 u32Sz = 0; + sint8 ret = M2M_SUCCESS; + FILE *fp =NULL; + fp = fopen(M2M_OTA_FILE,"rb"); + if(fp) + { + fseek(fp, 0L, SEEK_END); + u32Sz = ftell(fp); + fseek(fp, 0L, SEEK_SET); + + while(u32Sz > 0) + { + { + page = (rand()%1400); + + if((page<100)||(page>1400)) page = 1400; + } + + if(u32Sz>page) + { + u32Sz-=page; + } + else + { + page = u32Sz; + u32Sz = 0; + } + printf("page %d\n", (int)page); + fread(buffer,page,1,fp); + ret = hif_send(M2M_REQ_GROUP_OTA,M2M_OTA_REQ_TEST|M2M_REQ_DATA_PKT,NULL,0,(uint8*)&buffer,page,0); + if(ret != M2M_SUCCESS) + { + M2M_ERR("\n"); + } + nm_bsp_sleep(1); + } + + } + else + { + M2M_ERR("nO err\n"); + } + return ret; +} +#endif + diff --git a/lib/WiFi101/src/driver/source/m2m_periph.c b/lib/WiFi101/src/driver/source/m2m_periph.c new file mode 100644 index 0000000..0f8890b --- /dev/null +++ b/lib/WiFi101/src/driver/source/m2m_periph.c @@ -0,0 +1,187 @@ +/** + * + * \file + * + * \brief NMC1500 Peripherials Application Interface. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +#include "driver/include/m2m_periph.h" +#include "driver/source/nmasic.h" +#include "m2m_hif.h" + +#ifdef CONF_PERIPH + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +MACROS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +#define GPIO_OP_DIR 0 +#define GPIO_OP_SET 1 +#define GPIO_OP_GET 2 +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +DATA TYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +STATIC FUNCTIONS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +static sint8 get_gpio_idx(uint8 u8GpioNum) +{ + if(u8GpioNum >= M2M_PERIPH_GPIO_MAX) return -1; + if(u8GpioNum == M2M_PERIPH_GPIO15) { return 15; + } else if(u8GpioNum == M2M_PERIPH_GPIO16) { return 16; + } else if(u8GpioNum == M2M_PERIPH_GPIO18) { return 18; + } else if(u8GpioNum == M2M_PERIPH_GPIO3) { return 3; + } else if(u8GpioNum == M2M_PERIPH_GPIO4) { return 4; + } else if(u8GpioNum == M2M_PERIPH_GPIO5) { return 5; + } else if(u8GpioNum == M2M_PERIPH_GPIO6) { return 6; + } else { + return -2; + } +} +/* + * GPIO read/write skeleton with wakeup/sleep capability. + */ +static sint8 gpio_ioctl(uint8 op, uint8 u8GpioNum, uint8 u8InVal, uint8 * pu8OutVal) +{ + sint8 ret, gpio; + + ret = hif_chip_wake(); + if(ret != M2M_SUCCESS) goto _EXIT; + + gpio = get_gpio_idx(u8GpioNum); + if(gpio < 0) goto _EXIT1; + + if(op == GPIO_OP_DIR) { + ret = set_gpio_dir((uint8)gpio, u8InVal); + } else if(op == GPIO_OP_SET) { + ret = set_gpio_val((uint8)gpio, u8InVal); + } else if(op == GPIO_OP_GET) { + ret = get_gpio_val((uint8)gpio, pu8OutVal); + } + if(ret != M2M_SUCCESS) goto _EXIT1; + +_EXIT1: + ret = hif_chip_sleep(); +_EXIT: + return ret; +} +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +FUNCTION IMPLEMENTATION +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + + +sint8 m2m_periph_init(tstrPerphInitParam * param) +{ +#ifdef ARDUINO + (void)param; // Silence "unused" warning +#endif + return M2M_SUCCESS; +} + +sint8 m2m_periph_gpio_set_dir(uint8 u8GpioNum, uint8 u8GpioDir) +{ + return gpio_ioctl(GPIO_OP_DIR, u8GpioNum, u8GpioDir, NULL); +} + +sint8 m2m_periph_gpio_set_val(uint8 u8GpioNum, uint8 u8GpioVal) +{ + return gpio_ioctl(GPIO_OP_SET, u8GpioNum, u8GpioVal, NULL); +} + +sint8 m2m_periph_gpio_get_val(uint8 u8GpioNum, uint8 * pu8GpioVal) +{ + return gpio_ioctl(GPIO_OP_GET, u8GpioNum, 0, pu8GpioVal); +} + +sint8 m2m_periph_gpio_pullup_ctrl(uint8 u8GpioNum, uint8 u8PullupEn) +{ +#ifdef ARDUINO + (void)u8GpioNum; // Silence "unused" warning + (void)u8PullupEn; +#endif + /* TBD */ + return M2M_SUCCESS; +} + +sint8 m2m_periph_i2c_master_init(tstrI2cMasterInitParam * param) +{ +#ifdef ARDUINO + // Silence "unused" warning + (void)param; +#endif + /* TBD */ + return M2M_SUCCESS; +} + +sint8 m2m_periph_i2c_master_write(uint8 u8SlaveAddr, uint8 * pu8Buf, uint16 u16BufLen, uint8 flags) +{ +#ifdef ARDUINO + // Silence "unused" warning + (void)u8SlaveAddr; + (void)pu8Buf; + (void)u16BufLen; + (void)flags; +#endif + /* TBD */ + return M2M_SUCCESS; +} + +sint8 m2m_periph_i2c_master_read(uint8 u8SlaveAddr, uint8 * pu8Buf, uint16 u16BufLen, uint16 * pu16ReadLen, uint8 flags) +{ +#ifdef ARDUINO + // Silence "unused" warning + (void)u8SlaveAddr; + (void)pu8Buf; + (void)u16BufLen; + (void)pu16ReadLen; + (void)flags; +#endif + /* TBD */ + return M2M_SUCCESS; +} + + +sint8 m2m_periph_pullup_ctrl(uint32 pinmask, uint8 enable) +{ + return pullup_ctrl(pinmask, enable); +} +#endif /* CONF_PERIPH */ \ No newline at end of file diff --git a/lib/WiFi101/src/driver/source/m2m_ssl.c b/lib/WiFi101/src/driver/source/m2m_ssl.c new file mode 100644 index 0000000..07513f7 --- /dev/null +++ b/lib/WiFi101/src/driver/source/m2m_ssl.c @@ -0,0 +1,309 @@ +/** + * + * \file + * + * \brief This module contains M2M Wi-Fi APIs implementation. + * + * Copyright (c) 2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +#include "driver/include/m2m_ssl.h" +#include "driver/source/m2m_hif.h" +#include "driver/source/nmasic.h" + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +MACROS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +DATA TYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +static tpfAppSSLCb gpfAppSSLCb = NULL; +static uint32 gu32HIFAddr = 0; + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +FUNCTION PROTOTYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/*! + @fn \ m2m_ssl_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr) + @brief SSL callback function + @param [in] u8OpCode + HIF Opcode type. + @param [in] u16DataSize + HIF data length. + @param [in] u32Addr + HIF address. +*/ +static void m2m_ssl_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr) +{ +#ifdef ARDUINO + (void)u16DataSize; // Silence "unused" warning +#endif + sint8 s8tmp = M2M_SUCCESS; + switch(u8OpCode) + { + case M2M_SSL_REQ_ECC: + { + tstrEccReqInfo strEccREQ; + s8tmp = hif_receive(u32Addr, (uint8*)&strEccREQ, sizeof(tstrEccReqInfo), 0); + if(s8tmp == M2M_SUCCESS) + { + if (gpfAppSSLCb) + { + gu32HIFAddr = u32Addr + sizeof(tstrEccReqInfo); + gpfAppSSLCb(M2M_SSL_REQ_ECC, &strEccREQ); + } + } + } + break; + case M2M_SSL_RESP_SET_CS_LIST: + { + tstrSslSetActiveCsList strCsList; + s8tmp = hif_receive(u32Addr, (uint8*)&strCsList, sizeof(tstrSslSetActiveCsList), 0); + if(s8tmp == M2M_SUCCESS) + { + if (gpfAppSSLCb) + gpfAppSSLCb(M2M_SSL_RESP_SET_CS_LIST, &strCsList); + } + } + break; + } + if(s8tmp != M2M_SUCCESS) + { + M2M_ERR("Error receiving SSL from the HIF\n"); + } +} + + +/*! + @fn \ m2m_ssl_handshake_rsp(tstrEccReqInfo* strECCResp, uint8* pu8RspDataBuff, uint16 u16RspDataSz) + @brief Sends ECC responses to the WINC + @param [in] strECCResp + ECC Response struct. + @param [in] pu8RspDataBuffe + Pointer of the response data to be sent. + @param [in] u16RspDataSz + Response data size. + @return The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ssl_handshake_rsp(tstrEccReqInfo* strECCResp, uint8* pu8RspDataBuff, uint16 u16RspDataSz) +{ + sint8 s8Ret = M2M_SUCCESS; + + s8Ret = hif_send(M2M_REQ_GROUP_SSL, (M2M_SSL_RESP_ECC | M2M_REQ_DATA_PKT), (uint8*)strECCResp, sizeof(tstrEccReqInfo), pu8RspDataBuff, u16RspDataSz, sizeof(tstrEccReqInfo)); + + return s8Ret; +} + +/*! + @fn \ m2m_ssl_send_certs_to_winc(uint8* sector_buffer, uint32 sector_size) + @brief Sends certificates to the WINC + @param [in] pu8Buffer + Pointer to the certificates. + @param [in] u32BufferSz + Size of the certificates. + @return The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ssl_send_certs_to_winc(uint8* pu8Buffer, uint32 u32BufferSz) +{ + sint8 s8Ret = M2M_SUCCESS; + + s8Ret = hif_send(M2M_REQ_GROUP_SSL, (M2M_SSL_IND_CERTS_ECC | M2M_REQ_DATA_PKT), NULL, 0, pu8Buffer, u32BufferSz, 0); + + return s8Ret; +} + +/*! + @fn \ m2m_ssl_retrieve_cert(uint32 u32ReadAddr, uint16* pu16CurveType, uint8* pu8Hash, uint8* pu8Sig, tstrECPoint* pu8Key) + @brief Retrieve the certificate to be verified from the WINC + @param [in] pu16CurveType + Pointer to the certificate curve type. + @param [in] pu8Hash + Pointer to the certificate hash. + @param [in] pu8Sig + Pointer to the certificate signature. + @param [in] pu8Key + Pointer to the certificate Key. + @return The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ssl_retrieve_cert(uint16* pu16CurveType, uint8* pu8Hash, uint8* pu8Sig, tstrECPoint* pu8Key) +{ + uint8 bSetRxDone = 1; + uint16 u16HashSz, u16SigSz, u16KeySz; + sint8 s8Ret = M2M_SUCCESS; + + if(gu32HIFAddr == 0) return M2M_ERR_FAIL; + + if(hif_receive(gu32HIFAddr, (uint8*)pu16CurveType, 2, 0) != M2M_SUCCESS) goto __ERR; + gu32HIFAddr += 2; + + if(hif_receive(gu32HIFAddr, (uint8*)&u16KeySz, 2, 0) != M2M_SUCCESS) goto __ERR; + gu32HIFAddr += 2; + + if(hif_receive(gu32HIFAddr, (uint8*)&u16HashSz, 2, 0) != M2M_SUCCESS) goto __ERR; + gu32HIFAddr += 2; + + if(hif_receive(gu32HIFAddr, (uint8*)&u16SigSz, 2, 0) != M2M_SUCCESS) goto __ERR; + gu32HIFAddr += 2; + + (*pu16CurveType)= _htons((*pu16CurveType)); + pu8Key->u16Size = _htons(u16KeySz); + u16HashSz = _htons(u16HashSz); + u16SigSz = _htons(u16SigSz); + + if(hif_receive(gu32HIFAddr, pu8Key->X, pu8Key->u16Size * 2, 0) != M2M_SUCCESS) goto __ERR; + gu32HIFAddr += (pu8Key->u16Size * 2); + + if(hif_receive(gu32HIFAddr, pu8Hash, u16HashSz, 0) != M2M_SUCCESS) goto __ERR; + gu32HIFAddr += u16HashSz; + + if(hif_receive(gu32HIFAddr, pu8Sig, u16SigSz, 0) != M2M_SUCCESS) goto __ERR; + gu32HIFAddr += u16SigSz; + + bSetRxDone = 0; + +__ERR: + if(bSetRxDone) + { + s8Ret = M2M_ERR_FAIL; + hif_receive(0, NULL, 0, 1); + } + return s8Ret; +} + +/*! + @fn \ m2m_ssl_retrieve_hash(uint32 u32ReadAddr, uint8* pu8Hash, uint16 u16HashSz) + @brief Retrieve the certificate hash + @param [in] pu8Hash + Pointer to the certificate hash. + @param [in] u16HashSz + Hash size. + @return The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ssl_retrieve_hash(uint8* pu8Hash, uint16 u16HashSz) +{ + uint8 bSetRxDone = 1; + sint8 s8Ret = M2M_SUCCESS; + + if(gu32HIFAddr == 0) return M2M_ERR_FAIL; + + if(hif_receive(gu32HIFAddr, pu8Hash, u16HashSz, 0) != M2M_SUCCESS) goto __ERR; + + bSetRxDone = 0; + +__ERR: + if(bSetRxDone) + { + s8Ret = M2M_ERR_FAIL; + hif_receive(0, NULL, 0, 1); + } + return s8Ret; +} + +/*! + @fn \ m2m_ssl_stop_processing_certs(void) + @brief Stops receiving from the HIF +*/ +NMI_API void m2m_ssl_stop_processing_certs(void) +{ + hif_receive(0, NULL, 0, 1); +} + +/*! + @fn \ m2m_ssl_ecc_process_done(void) + @brief Stops receiving from the HIF +*/ +NMI_API void m2m_ssl_ecc_process_done(void) +{ + gu32HIFAddr = 0; +} + +/*! +@fn \ + m2m_ssl_set_active_ciphersuites(uint32 u32SslCsBMP); + Override the default Active SSL ciphers in the SSL module with a certain combination selected by the caller in the form of + a bitmap containing the required ciphers to be on. + There is no need to call this function if the application will not change the default ciphersuites. + +@param [in] u32SslCsBMP + Bitmap containing the desired ciphers to be enabled for the SSL module. The ciphersuites are defined in + @ref SSLCipherSuiteID. + The default ciphersuites are all ciphersuites supported by the firmware with the exception of ECC ciphersuites. + The caller can override the default with any desired combination, except for combinations involving both RSA + and ECC; if any RSA ciphersuite is enabled, then firmware will disable all ECC ciphersuites. + If u32SslCsBMP does not contain any ciphersuites supported by firmware, then the current active list will not + be changed. + +@return + - [SOCK_ERR_NO_ERROR](@ref SOCK_ERR_NO_ERROR) + - [SOCK_ERR_INVALID_ARG](@ref SOCK_ERR_INVALID_ARG) +*/ +sint8 m2m_ssl_set_active_ciphersuites(uint32 u32SslCsBMP) +{ + sint8 s8Ret = M2M_SUCCESS; + tstrSslSetActiveCsList strCsList; + + strCsList.u32CsBMP = u32SslCsBMP; + s8Ret = hif_send(M2M_REQ_GROUP_SSL, M2M_SSL_REQ_SET_CS_LIST, (uint8*)&strCsList, sizeof(tstrSslSetActiveCsList), NULL, 0, 0); + + return s8Ret; +} + +/*! + @fn \ m2m_ssl_init(tpfAppSslCb pfAppSslCb); + @brief Initializes the SSL layer. + @param [in] pfAppSslCb + Application SSL callback function. + @return The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_ssl_init(tpfAppSSLCb pfAppSSLCb) +{ + sint8 s8Ret = M2M_SUCCESS; + + gpfAppSSLCb = pfAppSSLCb; + gu32HIFAddr = 0; + + s8Ret = hif_register_cb(M2M_REQ_GROUP_SSL,m2m_ssl_cb); + if (s8Ret != M2M_SUCCESS) + { + M2M_ERR("hif_register_cb() failed with ret=%d", s8Ret); + } + return s8Ret; +} \ No newline at end of file diff --git a/lib/WiFi101/src/driver/source/m2m_wifi.c b/lib/WiFi101/src/driver/source/m2m_wifi.c new file mode 100644 index 0000000..fc4d1eb --- /dev/null +++ b/lib/WiFi101/src/driver/source/m2m_wifi.c @@ -0,0 +1,1496 @@ +/** + * + * \file + * + * \brief This module contains M2M Wi-Fi APIs implementation. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include "driver/include/m2m_wifi.h" +#include "driver/source/m2m_hif.h" +#include "driver/source/nmasic.h" + +static volatile uint8 gu8ChNum; +static volatile uint8 gu8scanInProgress = 0; +static tpfAppWifiCb gpfAppWifiCb = NULL; + + +#ifdef ETH_MODE +static tpfAppEthCb gpfAppEthCb = NULL; +static uint8* gau8ethRcvBuf=NULL; +static uint16 gu16ethRcvBufSize ; +#endif + + +//#define CONF_MGMT +#ifdef CONF_MGMT +static tpfAppMonCb gpfAppMonCb = NULL; +static struct _tstrMgmtCtrl +{ + uint8* pu8Buf; + uint16 u16Offset; + uint16 u16Sz; +} +gstrMgmtCtrl = {NULL, 0 , 0}; +#endif +/** +* @fn m2m_wifi_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr, uint8 grp) +* @brief WiFi call back function +* @param [in] u8OpCode +* HIF Opcode type. +* @param [in] u16DataSize +* HIF data length. +* @param [in] u32Addr +* HIF address. +* @param [in] grp +* HIF group type. +* @author +* @date +* @version 1.0 +*/ +static void m2m_wifi_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr) +{ +#ifdef ARDUINO + (void)u16DataSize; // Silence "unused" warning +#endif + uint8 rx_buf[8]; + if (u8OpCode == M2M_WIFI_RESP_CON_STATE_CHANGED) + { + tstrM2mWifiStateChanged strState; + if (hif_receive(u32Addr, (uint8*) &strState,sizeof(tstrM2mWifiStateChanged), 0) == M2M_SUCCESS) + { + if (gpfAppWifiCb) + gpfAppWifiCb(M2M_WIFI_RESP_CON_STATE_CHANGED, &strState); + } + } + else if (u8OpCode == M2M_WIFI_RESP_GET_SYS_TIME) + { + tstrSystemTime strSysTime; + if (hif_receive(u32Addr, (uint8*) &strSysTime,sizeof(tstrSystemTime), 0) == M2M_SUCCESS) + { + if (gpfAppWifiCb) + gpfAppWifiCb(M2M_WIFI_RESP_GET_SYS_TIME, &strSysTime); + } + } + else if(u8OpCode == M2M_WIFI_RESP_CONN_INFO) + { + tstrM2MConnInfo strConnInfo; + if(hif_receive(u32Addr, (uint8*)&strConnInfo, sizeof(tstrM2MConnInfo), 1) == M2M_SUCCESS) + { + if(gpfAppWifiCb) + gpfAppWifiCb(M2M_WIFI_RESP_CONN_INFO, &strConnInfo); + } + } + else if (u8OpCode == M2M_WIFI_RESP_MEMORY_RECOVER) + { +#if 0 + if (hif_receive(u32Addr, rx_buf, 4, 1) == M2M_SUCCESS) + { + tstrM2mWifiStateChanged strState; + m2m_memcpy((uint8*) &strState, rx_buf,sizeof(tstrM2mWifiStateChanged)); + if (app_wifi_recover_cb) + app_wifi_recover_cb(strState.u8CurrState); + } +#endif + } + else if (u8OpCode == M2M_WIFI_REQ_DHCP_CONF) + { + tstrM2MIPConfig strIpConfig; +#ifdef ARDUINO + extern uint32 nmdrv_firm_ver; + uint16 rxSize = sizeof(tstrM2MIPConfig); + + if (nmdrv_firm_ver < M2M_MAKE_VERSION(19, 5, 0)) { + // for backwards compatibility with firmware 19.4.4 and older, + // the old tstrM2MIPConfig does not contain the u32DhcpLeaseTime field + rxSize -= sizeof(strIpConfig.u32DhcpLeaseTime); + } + + if (hif_receive(u32Addr, (uint8 *)&strIpConfig, rxSize, 0) == M2M_SUCCESS) +#else + if (hif_receive(u32Addr, (uint8 *)&strIpConfig, sizeof(tstrM2MIPConfig), 0) == M2M_SUCCESS) +#endif + { + if (gpfAppWifiCb) + gpfAppWifiCb(M2M_WIFI_REQ_DHCP_CONF, (uint8 *)&strIpConfig); + } + } + else if (u8OpCode == M2M_WIFI_REQ_WPS) + { + tstrM2MWPSInfo strWps; + m2m_memset((uint8*)&strWps,0,sizeof(tstrM2MWPSInfo)); + if(hif_receive(u32Addr, (uint8*)&strWps, sizeof(tstrM2MWPSInfo), 0) == M2M_SUCCESS) + { + if (gpfAppWifiCb) + gpfAppWifiCb(M2M_WIFI_REQ_WPS, &strWps); + } + } + else if (u8OpCode == M2M_WIFI_RESP_IP_CONFLICT) + { + uint32 u32ConflictedIP; + if(hif_receive(u32Addr, (uint8 *)&u32ConflictedIP, sizeof(u32ConflictedIP), 0) == M2M_SUCCESS) + { + M2M_INFO("Conflicted IP \" %u.%u.%u.%u \" \n", + BYTE_0(u32ConflictedIP),BYTE_1(u32ConflictedIP),BYTE_2(u32ConflictedIP),BYTE_3(u32ConflictedIP)); + if (gpfAppWifiCb) + gpfAppWifiCb(M2M_WIFI_RESP_IP_CONFLICT, NULL); + + } + } + else if (u8OpCode == M2M_WIFI_RESP_SCAN_DONE) + { + tstrM2mScanDone strState; + gu8scanInProgress = 0; + if(hif_receive(u32Addr, (uint8*)&strState, sizeof(tstrM2mScanDone), 0) == M2M_SUCCESS) + { + gu8ChNum = strState.u8NumofCh; + if (gpfAppWifiCb) + gpfAppWifiCb(M2M_WIFI_RESP_SCAN_DONE, &strState); + } + } + else if (u8OpCode == M2M_WIFI_RESP_SCAN_RESULT) + { + tstrM2mWifiscanResult strScanResult; + if(hif_receive(u32Addr, (uint8*)&strScanResult, sizeof(tstrM2mWifiscanResult), 0) == M2M_SUCCESS) + { + if (gpfAppWifiCb) + gpfAppWifiCb(M2M_WIFI_RESP_SCAN_RESULT, &strScanResult); + } + } + else if (u8OpCode == M2M_WIFI_RESP_CURRENT_RSSI) + { + if (hif_receive(u32Addr, rx_buf, 4, 0) == M2M_SUCCESS) + { + if (gpfAppWifiCb) + gpfAppWifiCb(M2M_WIFI_RESP_CURRENT_RSSI, rx_buf); + } + } + else if (u8OpCode == M2M_WIFI_RESP_CLIENT_INFO) + { + if (hif_receive(u32Addr, rx_buf, 4, 0) == M2M_SUCCESS) + { + if (gpfAppWifiCb) + gpfAppWifiCb(M2M_WIFI_RESP_CLIENT_INFO, rx_buf); + } + } + else if(u8OpCode == M2M_WIFI_RESP_PROVISION_INFO) + { + tstrM2MProvisionInfo strProvInfo; + if(hif_receive(u32Addr, (uint8*)&strProvInfo, sizeof(tstrM2MProvisionInfo), 1) == M2M_SUCCESS) + { + if(gpfAppWifiCb) + gpfAppWifiCb(M2M_WIFI_RESP_PROVISION_INFO, &strProvInfo); + } + } + else if(u8OpCode == M2M_WIFI_RESP_DEFAULT_CONNECT) + { + tstrM2MDefaultConnResp strResp; + if(hif_receive(u32Addr, (uint8*)&strResp, sizeof(tstrM2MDefaultConnResp), 1) == M2M_SUCCESS) + { + if(gpfAppWifiCb) + gpfAppWifiCb(M2M_WIFI_RESP_DEFAULT_CONNECT, &strResp); + } + } + + else if(u8OpCode == M2M_WIFI_RESP_GET_PRNG) + { + tstrPrng strPrng; + if(hif_receive(u32Addr, (uint8*)&strPrng,sizeof(tstrPrng), 0) == M2M_SUCCESS) + { + if(hif_receive(u32Addr + sizeof(tstrPrng),strPrng.pu8RngBuff,strPrng.u16PrngSize, 1) == M2M_SUCCESS) + { + if(gpfAppWifiCb) + gpfAppWifiCb(M2M_WIFI_RESP_GET_PRNG,&strPrng); + } + } + } +#ifdef ETH_MODE + else if(u8OpCode == M2M_WIFI_RESP_ETHERNET_RX_PACKET) + { + uint8 u8SetRxDone; + tstrM2mIpRsvdPkt strM2mRsvd; + if(hif_receive(u32Addr, &strM2mRsvd ,sizeof(tstrM2mIpRsvdPkt), 0) == M2M_SUCCESS) + { + tstrM2mIpCtrlBuf strM2mIpCtrlBuf; + uint16 u16Offset = strM2mRsvd.u16PktOffset; + strM2mIpCtrlBuf.u16RemainigDataSize = strM2mRsvd.u16PktSz; + if((gpfAppEthCb) && (gau8ethRcvBuf) && (gu16ethRcvBufSize > 0)) + { + do + { + u8SetRxDone = 1; + if(strM2mIpCtrlBuf.u16RemainigDataSize > gu16ethRcvBufSize) + { + u8SetRxDone = 0; + strM2mIpCtrlBuf.u16DataSize = gu16ethRcvBufSize; + } + else + { + strM2mIpCtrlBuf.u16DataSize = strM2mIpCtrlBuf.u16RemainigDataSize; + } + + if(hif_receive(u32Addr + u16Offset, gau8ethRcvBuf, strM2mIpCtrlBuf.u16DataSize, u8SetRxDone) == M2M_SUCCESS) + { + strM2mIpCtrlBuf.u16RemainigDataSize -= strM2mIpCtrlBuf.u16DataSize; + u16Offset += strM2mIpCtrlBuf.u16DataSize; + gpfAppEthCb(M2M_WIFI_RESP_ETHERNET_RX_PACKET, gau8ethRcvBuf, &(strM2mIpCtrlBuf)); + } + else + { + break; + } + }while (strM2mIpCtrlBuf.u16RemainigDataSize > 0); + } + } + } +#endif /* ETH_MODE */ +#ifdef CONF_MGMT + else if(u8OpCode == M2M_WIFI_RESP_WIFI_RX_PACKET) + { + + tstrM2MWifiRxPacketInfo strRxPacketInfo; + if(u16DataSize >= sizeof(tstrM2MWifiRxPacketInfo)) { + if(hif_receive(u32Addr, (uint8*)&strRxPacketInfo, sizeof(tstrM2MWifiRxPacketInfo), 0) == M2M_SUCCESS) + { + u16DataSize -= sizeof(tstrM2MWifiRxPacketInfo); + if(u16DataSize > 0 && gstrMgmtCtrl.pu8Buf != NULL) + { + if(u16DataSize > (gstrMgmtCtrl.u16Sz + gstrMgmtCtrl.u16Offset)) + { + u16DataSize = gstrMgmtCtrl.u16Sz; + } + u32Addr += sizeof(tstrM2MWifiRxPacketInfo) + gstrMgmtCtrl.u16Offset; + if(hif_receive(u32Addr , gstrMgmtCtrl.pu8Buf, u16DataSize, 1) != M2M_SUCCESS) return; + } + if(gpfAppMonCb) + gpfAppMonCb(&strRxPacketInfo, gstrMgmtCtrl.pu8Buf,u16DataSize); + } + } else { + M2M_ERR("Incorrect mon data size %u\n", u16DataSize); + } + } +#endif + else + { + M2M_ERR("REQ Not defined %d\n",u8OpCode); + } +} + +sint8 m2m_wifi_download_mode() +{ + sint8 ret = M2M_SUCCESS; + /* Apply device specific initialization. */ + ret = nm_drv_init_download_mode(); + if(ret != M2M_SUCCESS) goto _EXIT0; + + + + enable_interrupts(); + +_EXIT0: + return ret; +} + +static sint8 m2m_validate_ap_parameters(CONST tstrM2MAPConfig* pstrM2MAPConfig) +{ + sint8 s8Ret = M2M_SUCCESS; + /* Check for incoming pointer */ + if(pstrM2MAPConfig == NULL) + { + M2M_ERR("INVALID POINTER\n"); + s8Ret = M2M_ERR_FAIL; + goto ERR1; + } + /* Check for SSID */ + if((m2m_strlen((uint8 *)pstrM2MAPConfig->au8SSID) <= 0) || (m2m_strlen((uint8 *)pstrM2MAPConfig->au8SSID) >= M2M_MAX_SSID_LEN)) + { + M2M_ERR("INVALID SSID\n"); + s8Ret = M2M_ERR_FAIL; + goto ERR1; + } + /* Check for Channel */ + if(pstrM2MAPConfig->u8ListenChannel > M2M_WIFI_CH_14 || pstrM2MAPConfig->u8ListenChannel < M2M_WIFI_CH_1) + { + M2M_ERR("INVALID CH\n"); + s8Ret = M2M_ERR_FAIL; + goto ERR1; + } + /* Check for DHCP Server IP address */ + if(!(pstrM2MAPConfig->au8DHCPServerIP[0] || pstrM2MAPConfig->au8DHCPServerIP[1])) + { + if(!(pstrM2MAPConfig->au8DHCPServerIP[2])) + { + M2M_ERR("INVALID DHCP SERVER IP\n"); + s8Ret = M2M_ERR_FAIL; + goto ERR1; + } + } + /* Check for Security */ + if(pstrM2MAPConfig->u8SecType == M2M_WIFI_SEC_OPEN) + { + goto ERR1; + } + else if(pstrM2MAPConfig->u8SecType == M2M_WIFI_SEC_WEP) + { + /* Check for WEP Key index */ + if((pstrM2MAPConfig->u8KeyIndx <= 0) || (pstrM2MAPConfig->u8KeyIndx > WEP_KEY_MAX_INDEX)) + { + M2M_ERR("INVALID KEY INDEX\n"); + s8Ret = M2M_ERR_FAIL; + goto ERR1; + } + /* Check for WEP Key size */ + if( (pstrM2MAPConfig->u8KeySz != WEP_40_KEY_STRING_SIZE) && + (pstrM2MAPConfig->u8KeySz != WEP_104_KEY_STRING_SIZE) + ) + { + M2M_ERR("INVALID KEY STRING SIZE\n"); + s8Ret = M2M_ERR_FAIL; + goto ERR1; + } + + if((m2m_strlen((uint8 *)pstrM2MAPConfig->au8WepKey) <= 0) || (m2m_strlen((uint8 *)pstrM2MAPConfig->au8WepKey) > WEP_104_KEY_STRING_SIZE)) + { + M2M_ERR("INVALID KEY SIZE\n"); + s8Ret = M2M_ERR_FAIL; + goto ERR1; + } + } + else if(pstrM2MAPConfig->u8SecType == M2M_WIFI_SEC_WPA_PSK) + { + /* Check for WPA Key size */ + if( ((pstrM2MAPConfig->u8KeySz + 1) < M2M_MIN_PSK_LEN) || ((pstrM2MAPConfig->u8KeySz + 1) > M2M_MAX_PSK_LEN)) + { + M2M_ERR("INVALID WPA KEY SIZE\n"); + s8Ret = M2M_ERR_FAIL; + goto ERR1; + } + } + else + { + M2M_ERR("INVALID AUTHENTICATION MODE\n"); + s8Ret = M2M_ERR_FAIL; + goto ERR1; + } + +ERR1: + return s8Ret; +} +static sint8 m2m_validate_scan_options(tstrM2MScanOption* ptstrM2MScanOption) +{ + sint8 s8Ret = M2M_SUCCESS; + /* Check for incoming pointer */ + if(ptstrM2MScanOption == NULL) + { + M2M_ERR("INVALID POINTER\n"); + s8Ret = M2M_ERR_FAIL; + goto ERR; + } + /* Check for valid No of slots */ + if(ptstrM2MScanOption->u8NumOfSlot == 0) + { + M2M_ERR("INVALID No of scan slots! %d\n",ptstrM2MScanOption->u8NumOfSlot); + s8Ret = M2M_ERR_FAIL; + goto ERR; + } + /* Check for valid time of slots */ + if(ptstrM2MScanOption->u8SlotTime < 10 || ptstrM2MScanOption->u8SlotTime > 250) + { + M2M_ERR("INVALID scan slot time! %d\n",ptstrM2MScanOption->u8SlotTime); + s8Ret = M2M_ERR_FAIL; + goto ERR; + } + /* Check for valid No of probe requests per slot */ + if((ptstrM2MScanOption->u8ProbesPerSlot == 0)||(ptstrM2MScanOption->u8ProbesPerSlot > M2M_SCAN_DEFAULT_NUM_PROBE)) + { + M2M_ERR("INVALID No of probe requests per scan slot %d\n",ptstrM2MScanOption->u8ProbesPerSlot); + s8Ret = M2M_ERR_FAIL; + goto ERR; + } + /* Check for valid RSSI threshold */ + if((ptstrM2MScanOption->s8RssiThresh < -99) || (ptstrM2MScanOption->s8RssiThresh >= 0)) + { + M2M_ERR("INVALID RSSI threshold %d \n",ptstrM2MScanOption->s8RssiThresh); + s8Ret = M2M_ERR_FAIL; + } + +ERR: + return s8Ret; +} + +sint8 m2m_wifi_send_crl(tstrTlsCrlInfo* pCRL) +{ + sint8 s8Ret = M2M_ERR_FAIL; + s8Ret = hif_send(M2M_REQ_GROUP_SSL, M2M_SSL_IND_CRL|M2M_REQ_DATA_PKT, NULL, 0, (uint8*)pCRL, sizeof(tstrTlsCrlInfo), 0); + return s8Ret; +} + +sint8 m2m_wifi_init(tstrWifiInitParam * param) +{ + tstrM2mRev strtmp; + sint8 ret = M2M_SUCCESS; + uint8 u8WifiMode = M2M_WIFI_MODE_NORMAL; + + if(param == NULL) { + ret = M2M_ERR_FAIL; + goto _EXIT0; + } + + gpfAppWifiCb = param->pfAppWifiCb; + +#ifdef ETH_MODE + gpfAppEthCb = param->strEthInitParam.pfAppEthCb; + gau8ethRcvBuf = param->strEthInitParam.au8ethRcvBuf; + gu16ethRcvBufSize = param->strEthInitParam.u16ethRcvBufSize; + u8WifiMode = param->strEthInitParam.u8EthernetEnable; +#endif /* ETH_MODE */ + +#ifdef CONF_MGMT + gpfAppMonCb = param->pfAppMonCb; +#endif + gu8scanInProgress = 0; + /* Apply device specific initialization. */ + ret = nm_drv_init(&u8WifiMode); + if(ret != M2M_SUCCESS) goto _EXIT0; + /* Initialize host interface module */ + ret = hif_init(NULL); + if(ret != M2M_SUCCESS) goto _EXIT1; + + hif_register_cb(M2M_REQ_GROUP_WIFI,m2m_wifi_cb); + + ret = nm_get_firmware_full_info(&strtmp); + +#ifdef ARDUINO + if (M2M_ERR_FAIL == ret) + { + // for compatibility with firmware version 19.3.0 + ret = nm_get_firmware_info(&strtmp); + } +#endif + M2M_INFO("Firmware ver : %u.%u.%u Svnrev %u\n", strtmp.u8FirmwareMajor, strtmp.u8FirmwareMinor, strtmp.u8FirmwarePatch,strtmp.u16FirmwareSvnNum); + M2M_INFO("Firmware Build %s Time %s\n",strtmp.BuildDate,strtmp.BuildTime); + M2M_INFO("Firmware Min driver ver : %u.%u.%u\n", strtmp.u8DriverMajor, strtmp.u8DriverMinor, strtmp.u8DriverPatch); + M2M_INFO("Driver ver: %u.%u.%u\n", M2M_RELEASE_VERSION_MAJOR_NO, M2M_RELEASE_VERSION_MINOR_NO, M2M_RELEASE_VERSION_PATCH_NO); + M2M_INFO("Driver built at %s\t%s\n",__DATE__,__TIME__); + if(M2M_ERR_FW_VER_MISMATCH == ret) + { + M2M_ERR("Mismatch Firmawre Version\n"); + } + + goto _EXIT0; + +_EXIT1: + nm_drv_deinit(NULL); +_EXIT0: + return ret; +} + +sint8 m2m_wifi_deinit(void * arg) +{ +#ifdef ARDUINO + (void)arg; // Silence "unused" warning +#endif + hif_deinit(NULL); + + nm_drv_deinit(NULL); + + return M2M_SUCCESS; +} + +sint8 m2m_wifi_handle_events(void * arg) +{ +#ifdef ARDUINO + (void)arg; // Silence "unused" warning +#endif + return hif_handle_isr(); +} + +sint8 m2m_wifi_default_connect(void) +{ + return hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_DEFAULT_CONNECT, NULL, 0,NULL, 0,0); +} + +sint8 m2m_wifi_connect(char *pcSsid, uint8 u8SsidLen, uint8 u8SecType, void *pvAuthInfo, uint16 u16Ch) +{ + return m2m_wifi_connect_sc(pcSsid, u8SsidLen, u8SecType, pvAuthInfo, u16Ch,0); +} +sint8 m2m_wifi_connect_sc(char *pcSsid, uint8 u8SsidLen, uint8 u8SecType, void *pvAuthInfo, uint16 u16Ch, uint8 u8NoSaveCred) +{ + sint8 ret = M2M_SUCCESS; + tstrM2mWifiConnect strConnect; + tstrM2MWifiSecInfo *pstrAuthInfo; + + if(u8SecType != M2M_WIFI_SEC_OPEN) + { + if(pvAuthInfo == NULL) + { + M2M_ERR("Key is not valid\n"); + ret = M2M_ERR_FAIL; + goto ERR1; + } + if((u8SecType == M2M_WIFI_SEC_WPA_PSK) && (m2m_strlen(pvAuthInfo) == (M2M_MAX_PSK_LEN-1))) + { + uint8 i = 0; + uint8* pu8Psk = (uint8*)pvAuthInfo; + while(i < (M2M_MAX_PSK_LEN-1)) + { + if(pu8Psk[i]<'0' || (pu8Psk[i]>'9' && pu8Psk[i] < 'A')|| (pu8Psk[i]>'F' && pu8Psk[i] < 'a') || pu8Psk[i] > 'f') + { + M2M_ERR("Invalid Key\n"); + ret = M2M_ERR_FAIL; + goto ERR1; + } + i++; + } + } + } + if((u8SsidLen<=0)||(u8SsidLen>=M2M_MAX_SSID_LEN)) + { + M2M_ERR("SSID LEN INVALID\n"); + ret = M2M_ERR_FAIL; + goto ERR1; + } + + if(u16Ch < M2M_WIFI_CH_1|| u16Ch > M2M_WIFI_CH_14) + { + if(u16Ch!=M2M_WIFI_CH_ALL) + { + M2M_ERR("CH INVALID\n"); + ret = M2M_ERR_FAIL; + goto ERR1; + } + } + + + m2m_memcpy(strConnect.au8SSID, (uint8*)pcSsid, u8SsidLen); + strConnect.au8SSID[u8SsidLen] = 0; + strConnect.u16Ch = NM_BSP_B_L_16(u16Ch); + /* Credentials will be Not be saved if u8NoSaveCred is set */ + strConnect.u8NoSaveCred = u8NoSaveCred ? 1:0; + pstrAuthInfo = &strConnect.strSec; + pstrAuthInfo->u8SecType = u8SecType; + + if(u8SecType == M2M_WIFI_SEC_WEP) + { + tstrM2mWifiWepParams * pstrWepParams = (tstrM2mWifiWepParams*)pvAuthInfo; + tstrM2mWifiWepParams *pstrWep = &pstrAuthInfo->uniAuth.strWepInfo; +#ifdef ARDUINO + pstrWep->u8KeyIndx =pstrWepParams->u8KeyIndx; +#else + pstrWep->u8KeyIndx =pstrWepParams->u8KeyIndx-1; +#endif + + if(pstrWep->u8KeyIndx >= WEP_KEY_MAX_INDEX) + { + M2M_ERR("Invalid Wep key index %d\n", pstrWep->u8KeyIndx); + ret = M2M_ERR_FAIL; + goto ERR1; + } +#ifdef ARDUINO + pstrWep->u8KeySz = pstrWepParams->u8KeySz; +#else + pstrWep->u8KeySz = pstrWepParams->u8KeySz-1; +#endif + if ((pstrWep->u8KeySz != WEP_40_KEY_STRING_SIZE)&& (pstrWep->u8KeySz != WEP_104_KEY_STRING_SIZE)) + { + M2M_ERR("Invalid Wep key length %d\n", pstrWep->u8KeySz); + ret = M2M_ERR_FAIL; + goto ERR1; + } + m2m_memcpy((uint8*)pstrWep->au8WepKey,(uint8*)pstrWepParams->au8WepKey, pstrWepParams->u8KeySz); + pstrWep->au8WepKey[pstrWepParams->u8KeySz] = 0; + + } + + + else if(u8SecType == M2M_WIFI_SEC_WPA_PSK) + { + uint16 u16KeyLen = m2m_strlen((uint8*)pvAuthInfo); + if((u16KeyLen <= 0)||(u16KeyLen >= M2M_MAX_PSK_LEN)) + { + M2M_ERR("Incorrect PSK key length\n"); + ret = M2M_ERR_FAIL; + goto ERR1; + } + m2m_memcpy(pstrAuthInfo->uniAuth.au8PSK, (uint8*)pvAuthInfo, u16KeyLen + 1); + } + else if(u8SecType == M2M_WIFI_SEC_802_1X) + { + m2m_memcpy((uint8*)&pstrAuthInfo->uniAuth.strCred1x, (uint8*)pvAuthInfo, sizeof(tstr1xAuthCredentials)); + } + else if(u8SecType == M2M_WIFI_SEC_OPEN) + { + + } + else + { + M2M_ERR("undefined sec type\n"); + ret = M2M_ERR_FAIL; + goto ERR1; + } + + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_CONNECT, (uint8*)&strConnect, sizeof(tstrM2mWifiConnect),NULL, 0,0); + +ERR1: + return ret; +} + +sint8 m2m_wifi_disconnect(void) +{ + return hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_DISCONNECT, NULL, 0, NULL, 0,0); +} +sint8 m2m_wifi_set_mac_address(uint8 au8MacAddress[6]) +{ + tstrM2mSetMacAddress strTmp; + m2m_memcpy((uint8*) strTmp.au8Mac, (uint8*) au8MacAddress, 6); + return hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SET_MAC_ADDRESS, + (uint8*) &strTmp, sizeof(tstrM2mSetMacAddress), NULL, 0,0); +} + +sint8 m2m_wifi_set_static_ip(tstrM2MIPConfig * pstrStaticIPConf) +{ + pstrStaticIPConf->u32DNS = NM_BSP_B_L_32(pstrStaticIPConf->u32DNS); + pstrStaticIPConf->u32Gateway = NM_BSP_B_L_32(pstrStaticIPConf->u32Gateway); + pstrStaticIPConf->u32StaticIP = NM_BSP_B_L_32( + pstrStaticIPConf->u32StaticIP); + pstrStaticIPConf->u32SubnetMask = NM_BSP_B_L_32( + pstrStaticIPConf->u32SubnetMask); + return hif_send(M2M_REQ_GROUP_IP, M2M_IP_REQ_STATIC_IP_CONF, + (uint8*) pstrStaticIPConf, sizeof(tstrM2MIPConfig), NULL, 0,0); +} + +sint8 m2m_wifi_request_dhcp_client(void) +{ + /*legacy API should be removed */ + return 0; +} +sint8 m2m_wifi_request_dhcp_server(uint8* addr) +{ +#ifdef ARDUINO + (void)addr; // Silence "unused" warning +#endif + /*legacy API should be removed */ + return 0; +} +/*! +@fn NMI_API sint8 m2m_wifi_set_lsn_int(tstrM2mLsnInt * pstrM2mLsnInt); +@brief Set the Wi-Fi listen interval for power save operation. It is represented in units + of AP Beacon periods. +@param [in] pstrM2mLsnInt + Structure holding the listen interval configurations. +@return The function SHALL return 0 for success and a negative value otherwise. +@sa tstrM2mLsnInt , m2m_wifi_set_sleep_mode +@pre m2m_wifi_set_sleep_mode shall be called first +@warning The Function called once after initialization. +*/ +sint8 m2m_wifi_enable_dhcp(uint8 u8DhcpEn ) +{ + + uint8 u8Req; + u8Req = u8DhcpEn ? M2M_IP_REQ_ENABLE_DHCP : M2M_IP_REQ_DISABLE_DHCP; + return hif_send(M2M_REQ_GROUP_IP, u8Req, NULL, 0, NULL, 0, 0); + + +} + +sint8 m2m_wifi_set_lsn_int(tstrM2mLsnInt* pstrM2mLsnInt) +{ + return hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_LSN_INT, (uint8*)pstrM2mLsnInt, sizeof(tstrM2mLsnInt), NULL, 0, 0); +} + +sint8 m2m_wifi_set_cust_InfoElement(uint8* pau8M2mCustInfoElement) +{ + + sint8 ret = M2M_ERR_FAIL; + if(pau8M2mCustInfoElement != NULL) + { + if((pau8M2mCustInfoElement[0] + 1) < M2M_CUST_IE_LEN_MAX) + { + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_CUST_INFO_ELEMENT|M2M_REQ_DATA_PKT, (uint8*)pau8M2mCustInfoElement, pau8M2mCustInfoElement[0]+1, NULL, 0, 0); + } + } + return ret; +} + +sint8 m2m_wifi_set_scan_options(tstrM2MScanOption* ptstrM2MScanOption) +{ + sint8 s8Ret = M2M_ERR_FAIL; + if(m2m_validate_scan_options (ptstrM2MScanOption) == M2M_SUCCESS) + { + s8Ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SET_SCAN_OPTION, (uint8*)ptstrM2MScanOption, sizeof(tstrM2MScanOption),NULL, 0,0); + } + return s8Ret; +} +sint8 m2m_wifi_set_scan_region(uint16 ScanRegion) +{ + sint8 s8Ret = M2M_ERR_FAIL; + tstrM2MScanRegion strScanRegion; + strScanRegion.u16ScanRegion = ScanRegion; + s8Ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SET_SCAN_REGION, (uint8*)&strScanRegion, sizeof(tstrM2MScanRegion),NULL, 0,0); + return s8Ret; +} +sint8 m2m_wifi_request_scan(uint8 ch) +{ + sint8 s8Ret = M2M_SUCCESS; + + if(!gu8scanInProgress) + { + if(((ch >= M2M_WIFI_CH_1) && (ch <= M2M_WIFI_CH_14)) || (ch == M2M_WIFI_CH_ALL)) + { + tstrM2MScan strtmp; + strtmp.u8ChNum = ch; + s8Ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SCAN, (uint8*)&strtmp, sizeof(tstrM2MScan),NULL, 0,0); + if(s8Ret == M2M_SUCCESS) + { + gu8scanInProgress = 1; + } + } + else + { + s8Ret = M2M_ERR_INVALID_ARG; + } + } + else + { + s8Ret = M2M_ERR_SCAN_IN_PROGRESS; + } + return s8Ret; +} + +sint8 m2m_wifi_request_scan_passive(uint8 ch, uint16 scan_time) +{ + sint8 s8Ret = M2M_SUCCESS; + + if(!gu8scanInProgress) + { + if(((ch >= M2M_WIFI_CH_1) && (ch <= M2M_WIFI_CH_14)) || (ch == M2M_WIFI_CH_ALL)) + { + tstrM2MScan strtmp; + strtmp.u8ChNum = ch; + + strtmp.u16PassiveScanTime = scan_time; + + s8Ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_PASSIVE_SCAN, (uint8*)&strtmp, sizeof(tstrM2MScan),NULL, 0,0); + if(s8Ret == M2M_SUCCESS) + { + gu8scanInProgress = 1; + } + } + else + { + s8Ret = M2M_ERR_INVALID_ARG; + } + } + else + { + s8Ret = M2M_ERR_SCAN_IN_PROGRESS; + } + return s8Ret; +} + +sint8 m2m_wifi_request_scan_ssid_list(uint8 ch,uint8 * u8Ssidlist) +{ + sint8 s8Ret = M2M_ERR_INVALID_ARG; + + if(!gu8scanInProgress) + { + if((((ch >= M2M_WIFI_CH_1) && (ch <= M2M_WIFI_CH_14)) || (ch == M2M_WIFI_CH_ALL))&&(u8Ssidlist != NULL)) + { + tstrM2MScan strtmp; + uint16 u16Lsize = 0; + uint8 u8Apnum = u8Ssidlist[u16Lsize]; + if(u8Apnum <= MAX_HIDDEN_SITES) + { + u16Lsize++; + while(u8Apnum) + { + if(u8Ssidlist[u16Lsize] >= M2M_MAX_SSID_LEN){ + goto EXIT; + }else { + u16Lsize += u8Ssidlist[u16Lsize] + 1; + u8Apnum--; + } + } + strtmp.u8ChNum = ch; + s8Ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SCAN_SSID_LIST|M2M_REQ_DATA_PKT, (uint8*)&strtmp, sizeof(tstrM2MScan),u8Ssidlist, u16Lsize,sizeof(tstrM2MScan)); + if(s8Ret == M2M_SUCCESS) + { + gu8scanInProgress = 1; + } + } + } + } + else + { + s8Ret = M2M_ERR_SCAN_IN_PROGRESS; + } +EXIT: + return s8Ret; +} +sint8 m2m_wifi_wps(uint8 u8TriggerType,const char *pcPinNumber) +{ + tstrM2MWPSConnect strtmp; + + /* Stop Scan if it is ongoing. + */ + gu8scanInProgress = 0; + strtmp.u8TriggerType = u8TriggerType; + /*If WPS is using PIN METHOD*/ + if (u8TriggerType == WPS_PIN_TRIGGER) + m2m_memcpy ((uint8*)strtmp.acPinNumber,(uint8*) pcPinNumber,8); + return hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_WPS, (uint8*)&strtmp,sizeof(tstrM2MWPSConnect), NULL, 0,0); +} +sint8 m2m_wifi_wps_disable(void) +{ + sint8 ret = M2M_SUCCESS; + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_DISABLE_WPS, NULL,0, NULL, 0, 0); + return ret; +} +/*! +@fn NMI_API sint8 m2m_wifi_req_client_ctrl(uint8 cmd); +@brief Send a command to the PS Client (An WINC1500 board running the ps_firmware), + if the PS client send any commands it will be received in wifi_cb M2M_WIFI_RESP_CLIENT_INFO +@param [in] cmd + Control command sent from PS Server to PS Client (command values defined by the application) +@return The function SHALL return M2M_SUCCESE for success and a negative value otherwise. +@sa m2m_wifi_req_server_init, M2M_WIFI_RESP_CLIENT_INFO +@pre m2m_wifi_req_server_init should be called first +@warning +*/ +sint8 m2m_wifi_req_client_ctrl(uint8 u8Cmd) +{ + + sint8 ret = M2M_SUCCESS; +#ifdef _PS_SERVER_ + tstrM2Mservercmd strCmd; + strCmd.u8cmd = u8Cmd; + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_CLIENT_CTRL, (uint8*)&strCmd, sizeof(tstrM2Mservercmd), NULL, 0, 0); +#else +#ifdef ARDUINO + (void)u8Cmd; // Silence "unused" warning +#endif + M2M_ERR("_PS_SERVER_ is not defined\n"); +#endif + return ret; +} +/*! +@fn NMI_API sint8 m2m_wifi_req_server_init(uint8 ch); +@brief Initialize the PS Server, The WINC1500 support Non secure communication with another WINC1500, + (SERVER/CLIENT) through one byte command (probe request and probe response) without any connection setup +@param [in] ch + Server listening channel +@return The function SHALL return M2M_SUCCESE for success and a negative value otherwise +@sa m2m_wifi_req_client_ctrl +@warning The server mode can't be used with any other modes (STA/P2P/AP) +*/ +sint8 m2m_wifi_req_server_init(uint8 ch) +{ + sint8 ret = M2M_SUCCESS; +#ifdef _PS_SERVER_ + tstrM2mServerInit strServer; + strServer.u8Channel = ch; + ret = hif_send(M2M_REQ_GROUP_WIFI,M2M_WIFI_REQ_SERVER_INIT, (uint8*)&strServer, sizeof(tstrM2mServerInit), NULL, 0, 0); +#else +#ifdef ARDUINO + (void)ch; // Silence "unused" warning +#endif + M2M_ERR("_PS_SERVER_ is not defined\n"); +#endif + return ret; +} +sint8 m2m_wifi_p2p(uint8 u8Channel) +{ + sint8 ret = M2M_SUCCESS; + if((u8Channel == M2M_WIFI_CH_1) || (u8Channel == M2M_WIFI_CH_6) || (u8Channel == M2M_WIFI_CH_11)) + { + tstrM2MP2PConnect strtmp; + strtmp.u8ListenChannel = u8Channel; + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_ENABLE_P2P, (uint8*)&strtmp, sizeof(tstrM2MP2PConnect), NULL, 0,0); + } + else + { + M2M_ERR("Listen channel should only be M2M_WIFI_CH_1/6/11 \n"); + ret = M2M_ERR_FAIL; + } + return ret; +} +sint8 m2m_wifi_p2p_disconnect(void) +{ + sint8 ret = M2M_SUCCESS; + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_DISABLE_P2P, NULL, 0, NULL, 0, 0); + return ret; +} +sint8 m2m_wifi_enable_ap(CONST tstrM2MAPConfig* pstrM2MAPConfig) +{ + sint8 ret = M2M_ERR_FAIL; + if(M2M_SUCCESS == m2m_validate_ap_parameters(pstrM2MAPConfig)) + { +#ifdef ARDUINO + extern uint32 nmdrv_firm_ver; + uint16 txSize = sizeof(tstrM2MAPConfig); + + if (nmdrv_firm_ver < M2M_MAKE_VERSION(19, 5, 0)) { + // for backwards compat with firmwware 19.4.x and older + // (listen channel is 0 based, there is no au8Key field) + ((tstrM2MAPConfig*)pstrM2MAPConfig)->u8ListenChannel--; + txSize -= sizeof(pstrM2MAPConfig->au8Key) + 1; + } + + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_ENABLE_AP, (uint8 *)pstrM2MAPConfig, txSize, NULL, 0, 0); +#else + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_ENABLE_AP, (uint8 *)pstrM2MAPConfig, sizeof(tstrM2MAPConfig), NULL, 0, 0); +#endif + } + return ret; +} + +sint8 m2m_wifi_set_gains(tstrM2mWifiGainsParams* pstrM2mGain) +{ + sint8 ret = M2M_ERR_FAIL; + if(pstrM2mGain != NULL) + { + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SET_GAINS, (uint8 *)pstrM2mGain, sizeof(tstrM2mWifiGainsParams), NULL, 0, 0); + } + return ret; +} +sint8 m2m_wifi_disable_ap(void) +{ + sint8 ret = M2M_SUCCESS; + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_DISABLE_AP, NULL, 0, NULL, 0, 0); + return ret; +} +/*! +@fn NMI_API sint8 m2m_wifi_req_curr_rssi(void); +@brief Request the current RSSI for the current connected AP, + the response received in wifi_cb M2M_WIFI_RESP_CURRENT_RSSI +@sa M2M_WIFI_RESP_CURRENT_RSSI +@return The function shall return M2M_SUCCESS for success and a negative value otherwise. +*/ +sint8 m2m_wifi_req_curr_rssi(void) +{ + sint8 ret = M2M_SUCCESS; + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_CURRENT_RSSI, NULL, 0, NULL,0, 0); + return ret; +} +sint8 m2m_wifi_send_ethernet_pkt(uint8* pu8Packet,uint16 u16PacketSize) +{ + sint8 s8Ret = -1; + if((pu8Packet != NULL)&&(u16PacketSize>0)) + { + tstrM2MWifiTxPacketInfo strTxPkt; + + strTxPkt.u16PacketSize = u16PacketSize; + strTxPkt.u16HeaderLength = M2M_ETHERNET_HDR_LEN; + s8Ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SEND_ETHERNET_PACKET | M2M_REQ_DATA_PKT, + (uint8*)&strTxPkt, sizeof(tstrM2MWifiTxPacketInfo), pu8Packet, u16PacketSize, M2M_ETHERNET_HDR_OFFSET - M2M_HIF_HDR_OFFSET); + } + return s8Ret; +} +/*! +@fn NMI_API sint8 m2m_wifi_get_otp_mac_address(uint8 *pu8MacAddr, uint8 * pu8IsValid); +@brief Request the MAC address stored on the OTP (one time programmable) memory of the device. + (the function is Blocking until response received) +@param [out] pu8MacAddr + Output MAC address buffer of 6 bytes size. Valid only if *pu8Valid=1. +@param [out] pu8IsValid + A output boolean value to indicate the validity of pu8MacAddr in OTP. + Output zero if the OTP memory is not programmed, non-zero otherwise. +@return The function shall return M2M_SUCCESS for success and a negative value otherwise. +@sa m2m_wifi_get_mac_address +@pre m2m_wifi_init required to call any WIFI/socket function +*/ +sint8 m2m_wifi_get_otp_mac_address(uint8 *pu8MacAddr, uint8* pu8IsValid) +{ + sint8 ret = M2M_SUCCESS; + ret = hif_chip_wake(); + if(ret == M2M_SUCCESS) + { + ret = nmi_get_otp_mac_address(pu8MacAddr, pu8IsValid); + if(ret == M2M_SUCCESS) + { + ret = hif_chip_sleep(); + } + } + return ret; +} +/*! +@fn NMI_API sint8 m2m_wifi_get_mac_address(uint8 *pu8MacAddr) +@brief Request the current MAC address of the device (the working mac address). + (the function is Blocking until response received) +@param [out] pu8MacAddr + Output MAC address buffer of 6 bytes size. +@return The function shall return M2M_SUCCESS for success and a negative value otherwise. +@sa m2m_wifi_get_otp_mac_address +@pre m2m_wifi_init required to call any WIFI/socket function +*/ +sint8 m2m_wifi_get_mac_address(uint8 *pu8MacAddr) +{ + sint8 ret = M2M_SUCCESS; + ret = hif_chip_wake(); + if(ret == M2M_SUCCESS) + { + ret = nmi_get_mac_address(pu8MacAddr); + if(ret == M2M_SUCCESS) + { + ret = hif_chip_sleep(); + } + } + + return ret; +} +/*! +@fn NMI_API sint8 m2m_wifi_req_scan_result(uint8 index); +@brief Reads the AP information from the Scan Result list with the given index, + the response received in wifi_cb M2M_WIFI_RESP_SCAN_RESULT, + the response pointer should be casted with tstrM2mWifiscanResult structure +@param [in] index + Index for the requested result, the index range start from 0 till number of AP's found +@sa tstrM2mWifiscanResult,m2m_wifi_get_num_ap_found,m2m_wifi_request_scan +@return The function shall return M2M_SUCCESE for success and a negative value otherwise +@pre m2m_wifi_request_scan need to be called first, then m2m_wifi_get_num_ap_found + to get the number of AP's found +@warning Function used only in STA mode only. the scan result updated only if scan request called, + else it will be cashed in firmware for the host scan request result, + which mean if large delay occur between the scan request and the scan result request, + the result will not be up-to-date +*/ + +sint8 m2m_wifi_req_scan_result(uint8 index) +{ + sint8 ret = M2M_SUCCESS; + tstrM2mReqScanResult strReqScanRlt; + strReqScanRlt.u8Index = index; + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SCAN_RESULT, (uint8*) &strReqScanRlt, sizeof(tstrM2mReqScanResult), NULL, 0, 0); + return ret; +} +/*! +@fn NMI_API uint8 m2m_wifi_get_num_ap_found(void); +@brief Reads the number of AP's found in the last Scan Request, + The function read the number of AP's from global variable which updated in the + wifi_cb in M2M_WIFI_RESP_SCAN_DONE. +@sa m2m_wifi_request_scan +@return Return the number of AP's found in the last Scan Request. +@pre m2m_wifi_request_scan need to be called first +@warning That function need to be called in the wifi_cb in M2M_WIFI_RESP_SCAN_DONE, + calling that function in any other place will return undefined/undated numbers. + Function used only in STA mode only. +*/ +uint8 m2m_wifi_get_num_ap_found(void) +{ + return gu8ChNum; +} +/*! +@fn NMI_API uint8 m2m_wifi_get_sleep_mode(void); +@brief Get the current Power save mode. +@return The current operating power saving mode. +@sa tenuPowerSaveModes , m2m_wifi_set_sleep_mode +*/ +uint8 m2m_wifi_get_sleep_mode(void) +{ + return hif_get_sleep_mode(); +} +/*! +@fn NMI_API sint8 m2m_wifi_set_sleep_mode(uint8 PsTyp, uint8 BcastEn); +@brief Set the power saving mode for the WINC1500. +@param [in] PsTyp + Desired power saving mode. Supported types are defined in tenuPowerSaveModes. +@param [in] BcastEn + Broadcast reception enable flag. + If it is 1, the WINC1500 must be awake each DTIM Beacon for receiving Broadcast traffic. + If it is 0, the WINC1500 will not wakeup at the DTIM Beacon, but its wakeup depends only + on the the configured Listen Interval. +@return The function SHALL return 0 for success and a negative value otherwise. +@sa tenuPowerSaveModes +@warning The function called once after initialization. +*/ +sint8 m2m_wifi_set_sleep_mode(uint8 PsTyp, uint8 BcastEn) +{ + sint8 ret = M2M_SUCCESS; + tstrM2mPsType strPs; + strPs.u8PsType = PsTyp; + strPs.u8BcastEn = BcastEn; + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SLEEP, (uint8*) &strPs,sizeof(tstrM2mPsType), NULL, 0, 0); + M2M_INFO("POWER SAVE %d\n",PsTyp); + hif_set_sleep_mode(PsTyp); + return ret; +} +/*! +@fn NMI_API sint8 m2m_wifi_request_sleep(void) +@brief Request from WINC1500 device to Sleep for specific time in the M2M_PS_MANUAL Power save mode (only). +@param [in] u32SlpReqTime + Request Sleep in ms +@return The function SHALL return M2M_SUCCESS for success and a negative value otherwise. +@sa tenuPowerSaveModes , m2m_wifi_set_sleep_mode +@warning the Function should be called in M2M_PS_MANUAL power save only +*/ +sint8 m2m_wifi_request_sleep(uint32 u32SlpReqTime) +{ + sint8 ret = M2M_SUCCESS; + uint8 psType; + psType = hif_get_sleep_mode(); + if(psType == M2M_PS_MANUAL) + { + tstrM2mSlpReqTime strPs; + strPs.u32SleepTime = u32SlpReqTime; + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_DOZE, (uint8*) &strPs,sizeof(tstrM2mSlpReqTime), NULL, 0, 0); + } + return ret; +} +/*! +@fn NMI_API sint8 m2m_wifi_set_device_name(uint8 *pu8DeviceName, uint8 u8DeviceNameLength); +@brief Set the WINC1500 device name which is used as P2P device name. +@param [in] pu8DeviceName + Buffer holding the device name. +@param [in] u8DeviceNameLength + Length of the device name. +@return The function SHALL return M2M_SUCCESS for success and a negative value otherwise. +@warning The Function called once after initialization. +*/ +sint8 m2m_wifi_set_device_name(uint8 *pu8DeviceName, uint8 u8DeviceNameLength) +{ + tstrM2MDeviceNameConfig strDeviceName; + if(u8DeviceNameLength >= M2M_DEVICE_NAME_MAX) + { + u8DeviceNameLength = M2M_DEVICE_NAME_MAX; + } + //pu8DeviceName[u8DeviceNameLength] = '\0'; + u8DeviceNameLength ++; + m2m_memcpy(strDeviceName.au8DeviceName, pu8DeviceName, u8DeviceNameLength); + return hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SET_DEVICE_NAME, + (uint8*)&strDeviceName, sizeof(tstrM2MDeviceNameConfig), NULL, 0,0); +} +sint8 m2m_wifi_get_firmware_version(tstrM2mRev *pstrRev) +{ + sint8 ret = M2M_SUCCESS; + ret = hif_chip_wake(); + if(ret == M2M_SUCCESS) + { + ret = nm_get_firmware_full_info(pstrRev); + hif_chip_sleep(); + } + return ret; +} +#ifdef CONF_MGMT +sint8 m2m_wifi_enable_monitoring_mode(tstrM2MWifiMonitorModeCtrl *pstrMtrCtrl, uint8 *pu8PayloadBuffer, + uint16 u16BufferSize, uint16 u16DataOffset) +{ + sint8 s8Ret = -1; + if((pstrMtrCtrl->u8ChannelID >= M2M_WIFI_CH_1) && (pstrMtrCtrl->u8ChannelID <= M2M_WIFI_CH_14)) + { + gstrMgmtCtrl.pu8Buf = pu8PayloadBuffer; + gstrMgmtCtrl.u16Sz = u16BufferSize; + gstrMgmtCtrl.u16Offset = u16DataOffset; + s8Ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_ENABLE_MONITORING, + (uint8*)pstrMtrCtrl, sizeof(tstrM2MWifiMonitorModeCtrl), NULL, 0,0); + } + return s8Ret; +} + +sint8 m2m_wifi_disable_monitoring_mode(void) +{ + return hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_DISABLE_MONITORING, NULL, 0, NULL, 0,0); +} + +sint8 m2m_wifi_send_wlan_pkt(uint8 *pu8WlanPacket, uint16 u16WlanHeaderLength, uint16 u16WlanPktSize) +{ + sint8 s8Ret = -1; + if(pu8WlanPacket != NULL) + { + tstrM2MWifiTxPacketInfo strTxPkt; + + strTxPkt.u16PacketSize = u16WlanPktSize; + strTxPkt.u16HeaderLength = u16WlanHeaderLength; + s8Ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SEND_WIFI_PACKET | M2M_REQ_DATA_PKT, + (uint8*)&strTxPkt, sizeof(tstrM2MWifiTxPacketInfo), pu8WlanPacket, u16WlanPktSize, sizeof(tstrM2MWifiTxPacketInfo)); + } + return s8Ret; +} +#endif + +sint8 m2m_wifi_start_provision_mode(tstrM2MAPConfig *pstrAPConfig, char *pcHttpServerDomainName, uint8 bEnableHttpRedirect) +{ + sint8 s8Ret = M2M_ERR_FAIL; + + if((pstrAPConfig != NULL)) + { + tstrM2MProvisionModeConfig strProvConfig; + if(M2M_SUCCESS == m2m_validate_ap_parameters(pstrAPConfig)) + { + m2m_memcpy((uint8*)&strProvConfig.strApConfig, (uint8*)pstrAPConfig, sizeof(tstrM2MAPConfig)); + if((m2m_strlen((uint8 *)pcHttpServerDomainName) <= 0) || (NULL == pcHttpServerDomainName)) + { + M2M_ERR("INVALID DOMAIN NAME\n"); + goto ERR1; + } + m2m_memcpy((uint8*)strProvConfig.acHttpServerDomainName, (uint8*)pcHttpServerDomainName, 64); + strProvConfig.u8EnableRedirect = bEnableHttpRedirect; + + /* Stop Scan if it is ongoing. + */ + gu8scanInProgress = 0; +#ifdef ARDUINO + extern uint32 nmdrv_firm_ver; + uint16 txSize = sizeof(tstrM2MProvisionModeConfig); + + if (nmdrv_firm_ver < M2M_MAKE_VERSION(19, 5, 0)) { + // for backwards compat with firmwware 19.4.x and older + // (listen channel is 0 based, there is no au8Key field) + strProvConfig.strApConfig.u8ListenChannel--; + txSize -= sizeof(strProvConfig.strApConfig.au8Key) + 1; + m2m_memcpy((uint8*)&strProvConfig.strApConfig.au8Key[3], (uint8*)pcHttpServerDomainName, 64); + uint8* pu8EnableRedirect = (uint8*)strProvConfig.strApConfig.au8Key; + pu8EnableRedirect[3 + 64] = bEnableHttpRedirect; + } + + s8Ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_START_PROVISION_MODE | M2M_REQ_DATA_PKT, + (uint8*)&strProvConfig, txSize, NULL, 0, 0); +#else + s8Ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_START_PROVISION_MODE | M2M_REQ_DATA_PKT, + (uint8*)&strProvConfig, sizeof(tstrM2MProvisionModeConfig), NULL, 0, 0); +#endif + } + else + { + /*goto ERR1;*/ + } + } +ERR1: + return s8Ret; +} + +sint8 m2m_wifi_stop_provision_mode(void) +{ + return hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_STOP_PROVISION_MODE, NULL, 0, NULL, 0, 0); +} + +sint8 m2m_wifi_get_connection_info(void) +{ + return hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_GET_CONN_INFO, NULL, 0, NULL, 0, 0); +} + +sint8 m2m_wifi_set_sytem_time(uint32 u32UTCSeconds) +{ + /* + The firmware accepts timestamps relative to 1900 like NTP Timestamp. + */ + return hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SET_SYS_TIME, (uint8*)&u32UTCSeconds, sizeof(tstrSystemTime), NULL, 0, 0); +} +/*! + * @fn NMI_API sint8 m2m_wifi_get_sytem_time(void); + * @see m2m_wifi_enable_sntp + tstrSystemTime + * @note get the system time from the sntp client + * using the API \ref m2m_wifi_get_sytem_time. + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + */ +sint8 m2m_wifi_get_sytem_time(void) +{ + return hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_GET_SYS_TIME, NULL,0, NULL, 0, 0); +} + +sint8 m2m_wifi_enable_sntp(uint8 bEnable) +{ + uint8 u8Req; + + u8Req = bEnable ? M2M_WIFI_REQ_ENABLE_SNTP_CLIENT : M2M_WIFI_REQ_DISABLE_SNTP_CLIENT; + return hif_send(M2M_REQ_GROUP_WIFI, u8Req, NULL, 0, NULL, 0, 0); +} +/*! +@fn NMI_API sint8 m2m_wifi_set_power_profile(uint8 u8PwrMode); +@brief Change the power profile mode +@param [in] u8PwrMode + Change the WINC power profile to different mode + PWR_LOW1/PWR_LOW2/PWR_HIGH/PWR_AUTO (tenuM2mPwrMode) +@return The function SHALL return M2M_SUCCESE for success and a negative value otherwise. +@sa tenuM2mPwrMode +@pre m2m_wifi_init +@warning must be called after the initializations and before any connection request and can't be changed in run time, +*/ +sint8 m2m_wifi_set_power_profile(uint8 u8PwrMode) +{ + sint8 ret = M2M_SUCCESS; + tstrM2mPwrMode strM2mPwrMode; + strM2mPwrMode.u8PwrMode = u8PwrMode; + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SET_POWER_PROFILE, (uint8*)&strM2mPwrMode,sizeof(tstrM2mPwrMode), NULL, 0, 0); + return ret; +} +/*! +@fn NMI_API sint8 m2m_wifi_set_tx_power(uint8 u8TxPwrLevel); +@brief set the TX power tenuM2mTxPwrLevel +@param [in] u8TxPwrLevel + change the TX power tenuM2mTxPwrLevel +@return The function SHALL return M2M_SUCCESE for success and a negative value otherwise. +@sa tenuM2mTxPwrLevel +@pre m2m_wifi_init +@warning +*/ +sint8 m2m_wifi_set_tx_power(uint8 u8TxPwrLevel) +{ + sint8 ret = M2M_SUCCESS; + tstrM2mTxPwrLevel strM2mTxPwrLevel; + strM2mTxPwrLevel.u8TxPwrLevel = u8TxPwrLevel; + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SET_TX_POWER, (uint8*)&strM2mTxPwrLevel,sizeof(tstrM2mTxPwrLevel), NULL, 0, 0); + return ret; +} + +/*! +@fn NMI_API sint8 m2m_wifi_enable_firmware_logs(uint8 u8Enable); +@brief Enable or Disable logs in run time (Disable Firmware logs will + enhance the firmware start-up time and performance) +@param [in] u8Enable + Set 1 to enable the logs 0 for disable +@return The function SHALL return M2M_SUCCESE for success and a negative value otherwise. +@sa __DISABLE_FIRMWARE_LOGS__ (build option to disable logs from initializations) +@pre m2m_wifi_init +@warning +*/ +sint8 m2m_wifi_enable_firmware_logs(uint8 u8Enable) +{ + sint8 ret = M2M_SUCCESS; + tstrM2mEnableLogs strM2mEnableLogs; + strM2mEnableLogs.u8Enable = u8Enable; + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SET_ENABLE_LOGS, (uint8*)&strM2mEnableLogs,sizeof(tstrM2mEnableLogs), NULL, 0, 0); + return ret; +} + +/*! +@fn NMI_API sint8 m2m_wifi_set_battery_voltage(uint16 u16BattVoltx100); +@brief Enable or Disable logs in run time (Disable Firmware logs will + enhance the firmware start-up time and performance) +@param [in] u16BattVoltx100 + battery voltage multiplied by 100 +@return The function SHALL return M2M_SUCCESE for success and a negative value otherwise. +@sa __DISABLE_FIRMWARE_LOGS__ (build option to disable logs from initializations) +@pre m2m_wifi_init +@warning +*/ +sint8 m2m_wifi_set_battery_voltage(uint16 u16BattVoltx100) +{ + sint8 ret = M2M_SUCCESS; + tstrM2mBatteryVoltage strM2mBattVol = {0}; + strM2mBattVol.u16BattVolt = u16BattVoltx100; + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SET_BATTERY_VOLTAGE, (uint8*)&strM2mBattVol,sizeof(tstrM2mBatteryVoltage), NULL, 0, 0); + return ret; +} +/*! +@fn sint8 m2m_wifi_prng_get_random_bytes(uint8 * pu8PrngBuff,uint16 u16PrngSize) +@brief Get random bytes using the PRNG bytes. +@param [in] u16PrngSize + Size of the required random bytes to be generated. +@param [in] pu8PrngBuff + Pointer to user allocated buffer. +@return The function SHALL return M2M_SUCCESE for success and a negative value otherwise. +*/ +sint8 m2m_wifi_prng_get_random_bytes(uint8 * pu8PrngBuff,uint16 u16PrngSize) +{ + sint8 ret = M2M_ERR_FAIL; + tstrPrng strRng = {0}; + if((u16PrngSize < (M2M_BUFFER_MAX_SIZE - sizeof(tstrPrng)))&&(pu8PrngBuff != NULL)) + { + strRng.u16PrngSize = u16PrngSize; + strRng.pu8RngBuff = pu8PrngBuff; + ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_GET_PRNG|M2M_REQ_DATA_PKT,(uint8 *)&strRng, sizeof(tstrPrng),NULL,0, 0); + } + else + { + M2M_ERR("PRNG Buffer exceeded maximum size %d or NULL Buffer\n",u16PrngSize); + } + return ret; +} +#ifdef ETH_MODE +/*! +@fn \ + NMI_API sint8 m2m_wifi_enable_mac_mcast(uint8* pu8MulticastMacAddress, uint8 u8AddRemove) + +@brief + Add MAC filter to receive Multicast packets. + +@param [in] pu8MulticastMacAddress + Pointer to the MAC address. +@param [in] u8AddRemove + Flag to Add/Remove MAC address. +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ + +NMI_API sint8 m2m_wifi_enable_mac_mcast(uint8* pu8MulticastMacAddress, uint8 u8AddRemove) +{ + sint8 s8ret = M2M_ERR_FAIL; + tstrM2MMulticastMac strMulticastMac; + + if(pu8MulticastMacAddress != NULL ) + { + strMulticastMac.u8AddRemove = u8AddRemove; + m2m_memcpy(strMulticastMac.au8macaddress,pu8MulticastMacAddress,M2M_MAC_ADDRES_LEN); + M2M_DBG("mac multicast: %x:%x:%x:%x:%x:%x\r\n",strMulticastMac.au8macaddress[0],strMulticastMac.au8macaddress[1],strMulticastMac.au8macaddress[2],strMulticastMac.au8macaddress[3],strMulticastMac.au8macaddress[4],strMulticastMac.au8macaddress[5]); + s8ret = hif_send(M2M_REQ_GROUP_WIFI, M2M_WIFI_REQ_SET_MAC_MCAST, (uint8 *)&strMulticastMac,sizeof(tstrM2MMulticastMac),NULL,0,0); + } + + return s8ret; + +} + +/*! +@fn \ + NMI_API sint8 m2m_wifi_set_receive_buffer(void* pvBuffer,uint16 u16BufferLen); + +@brief + set the ethernet receive buffer, should be called in the receive call back. + +@param [in] pvBuffer + Pointer to the ethernet receive buffer. +@param [in] u16BufferLen + Length of the buffer. + +@return + The function SHALL return 0 for success and a negative value otherwise. +*/ +NMI_API sint8 m2m_wifi_set_receive_buffer(void* pvBuffer,uint16 u16BufferLen) +{ + sint8 s8ret = M2M_SUCCESS; + if(pvBuffer != NULL) + { + gau8ethRcvBuf = pvBuffer; + gu16ethRcvBufSize= u16BufferLen; + } + else + { + s8ret = M2M_ERR_FAIL; + M2M_ERR("Buffer NULL pointer\r\n"); + } + return s8ret; +} +#endif /* ETH_MODE */ diff --git a/lib/WiFi101/src/driver/source/nmasic.c b/lib/WiFi101/src/driver/source/nmasic.c new file mode 100644 index 0000000..91c0e5a --- /dev/null +++ b/lib/WiFi101/src/driver/source/nmasic.c @@ -0,0 +1,688 @@ +/** + * + * \file + * + * \brief This module contains NMC1500 ASIC specific internal APIs. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include "common/include/nm_common.h" +#include "driver/source/nmbus.h" +#include "bsp/include/nm_bsp.h" +#include "driver/source/nmasic.h" +#include "driver/include/m2m_types.h" + +#define NMI_GLB_RESET_0 (NMI_PERIPH_REG_BASE + 0x400) +#define NMI_INTR_REG_BASE (NMI_PERIPH_REG_BASE + 0xa00) +#define NMI_PIN_MUX_0 (NMI_PERIPH_REG_BASE + 0x408) +#define NMI_INTR_ENABLE (NMI_INTR_REG_BASE) +#define GET_UINT32(X,Y) (X[0+Y] + ((uint32)X[1+Y]<<8) + ((uint32)X[2+Y]<<16) +((uint32)X[3+Y]<<24)) + +/*SPI and I2C only*/ +#define CORT_HOST_COMM (0x10) +#define HOST_CORT_COMM (0x0b) +#define WAKE_CLK_REG (0x1) +#define CLOCKS_EN_REG (0xf) + + + +#ifdef ARDUINO +#define TIMEOUT (2000) +#else +#define TIMEOUT (0xfffffffful) +#endif +#define WAKUP_TRAILS_TIMEOUT (4) + +sint8 chip_apply_conf(uint32 u32Conf) +{ + sint8 ret = M2M_SUCCESS; + uint32 val32 = u32Conf; + +#if (defined __ENABLE_PMU__) || (defined CONF_WINC_INT_PMU) + val32 |= rHAVE_USE_PMU_BIT; +#endif +#ifdef __ENABLE_SLEEP_CLK_SRC_RTC__ + val32 |= rHAVE_SLEEP_CLK_SRC_RTC_BIT; +#elif defined __ENABLE_SLEEP_CLK_SRC_XO__ + val32 |= rHAVE_SLEEP_CLK_SRC_XO_BIT; +#endif +#ifdef __ENABLE_EXT_PA_INV_TX_RX__ + val32 |= rHAVE_EXT_PA_INV_TX_RX; +#endif +#ifdef __ENABLE_LEGACY_RF_SETTINGS__ + val32 |= rHAVE_LEGACY_RF_SETTINGS; +#endif +#ifdef __DISABLE_FIRMWARE_LOGS__ + val32 |= rHAVE_LOGS_DISABLED_BIT; +#endif + + val32 |= rHAVE_RESERVED1_BIT; + do { + nm_write_reg(rNMI_GP_REG_1, val32); + if(val32 != 0) { + uint32 reg = 0; + ret = nm_read_reg_with_ret(rNMI_GP_REG_1, ®); + if(ret == M2M_SUCCESS) { + if(reg == val32) + break; + } + } else { + break; + } + } while(1); + + return M2M_SUCCESS; +} +void chip_idle(void) +{ + uint32 reg = 0; + nm_read_reg_with_ret(WAKE_CLK_REG, ®); + if(reg & NBIT1) + { + reg &=~ NBIT1; + nm_write_reg(WAKE_CLK_REG, reg); + } +} + +sint8 enable_interrupts(void) +{ + uint32 reg = 0; + sint8 ret = M2M_SUCCESS; + /** + interrupt pin mux select + **/ + ret = nm_read_reg_with_ret(NMI_PIN_MUX_0, ®); + if (M2M_SUCCESS != ret) goto ERR1; + + reg |= ((uint32) 1 << 8); + ret = nm_write_reg(NMI_PIN_MUX_0, reg); + if (M2M_SUCCESS != ret) goto ERR1; + + /** + interrupt enable + **/ + ret = nm_read_reg_with_ret(NMI_INTR_ENABLE, ®); + if (M2M_SUCCESS != ret) goto ERR1; + + reg |= ((uint32) 1 << 16); + ret = nm_write_reg(NMI_INTR_ENABLE, reg); + if (M2M_SUCCESS != ret) goto ERR1; +ERR1: + return ret; +} + +sint8 cpu_start(void) { + uint32 reg = 0; + sint8 ret; + + /** + reset regs + */ + ret = nm_write_reg(BOOTROM_REG,0); + ret += nm_write_reg(NMI_STATE_REG,0); + ret += nm_write_reg(NMI_REV_REG,0); + /** + Go... + **/ + ret += nm_read_reg_with_ret(0x1118, ®); + reg |= (1 << 0); + ret += nm_write_reg(0x1118, reg); + ret += nm_read_reg_with_ret(NMI_GLB_RESET_0, ®); + if ((reg & (1ul << 10)) == (1ul << 10)) { + reg &= ~(1ul << 10); + ret += nm_write_reg(NMI_GLB_RESET_0, reg); + } + reg |= (1ul << 10); + ret += nm_write_reg(NMI_GLB_RESET_0, reg); + nm_bsp_sleep(1); + return ret; +} + +uint32 nmi_get_chipid(void) +{ + static uint32 chipid = 0; + + if (chipid == 0) { + uint32 rfrevid; + + if((nm_read_reg_with_ret(0x1000, &chipid)) != M2M_SUCCESS) { + chipid = 0; + return 0; + } + //if((ret = nm_read_reg_with_ret(0x11fc, &revid)) != M2M_SUCCESS) { + // return 0; + //} + if((nm_read_reg_with_ret(0x13f4, &rfrevid)) != M2M_SUCCESS) { + chipid = 0; + return 0; + } + + if (chipid == 0x1002a0) { + if (rfrevid == 0x1) { /* 1002A0 */ + } else /* if (rfrevid == 0x2) */ { /* 1002A1 */ + chipid = 0x1002a1; + } + } else if(chipid == 0x1002b0) { + if(rfrevid == 3) { /* 1002B0 */ + } else if(rfrevid == 4) { /* 1002B1 */ + chipid = 0x1002b1; + } else /* if(rfrevid == 5) */ { /* 1002B2 */ + chipid = 0x1002b2; + } + }else if(chipid == 0x1000F0) { + if((nm_read_reg_with_ret(0x3B0000, &chipid)) != M2M_SUCCESS) { + chipid = 0; + return 0; + } + }else { + + } +//#define PROBE_FLASH +#ifdef PROBE_FLASH + if(chipid) { + UWORD32 flashid; + + flashid = probe_spi_flash(); + if(flashid == 0x1230ef) { + chipid &= ~(0x0f0000); + chipid |= 0x050000; + } + if(flashid == 0xc21320c2) { + chipid &= ~(0x0f0000); + chipid |= 0x050000; + } + } +#else + /*M2M is by default have SPI flash*/ + chipid &= ~(0x0f0000); + chipid |= 0x050000; +#endif /* PROBE_FLASH */ + } + return chipid; +} + +uint32 nmi_get_rfrevid(void) +{ + uint32 rfrevid; + if((nm_read_reg_with_ret(0x13f4, &rfrevid)) != M2M_SUCCESS) { + rfrevid = 0; + return 0; + } + return rfrevid; +} + +void restore_pmu_settings_after_global_reset(void) +{ + /* + * Must restore PMU register value after + * global reset if PMU toggle is done at + * least once since the last hard reset. + */ + if(REV(nmi_get_chipid()) >= REV_2B0) { + nm_write_reg(0x1e48, 0xb78469ce); + } +} + +void nmi_update_pll(void) +{ + uint32 pll; + + pll = nm_read_reg(0x1428); + pll &= ~0x1ul; + nm_write_reg(0x1428, pll); + pll |= 0x1ul; + nm_write_reg(0x1428, pll); + +} +void nmi_set_sys_clk_src_to_xo(void) +{ + uint32 val32; + + /* Switch system clock source to XO. This will take effect after nmi_update_pll(). */ + val32 = nm_read_reg(0x141c); + val32 |= (1 << 2); + nm_write_reg(0x141c, val32); + + /* Do PLL update */ + nmi_update_pll(); +} +sint8 chip_sleep(void) +{ + uint32 reg; + sint8 ret = M2M_SUCCESS; + + while(1) + { + ret = nm_read_reg_with_ret(CORT_HOST_COMM,®); + if(ret != M2M_SUCCESS) goto ERR1; + if((reg & NBIT0) == 0) break; + } + + /* Clear bit 1 */ + ret = nm_read_reg_with_ret(WAKE_CLK_REG, ®); + if(ret != M2M_SUCCESS)goto ERR1; + if(reg & NBIT1) + { + reg &=~NBIT1; + ret = nm_write_reg(WAKE_CLK_REG, reg); + if(ret != M2M_SUCCESS)goto ERR1; + } + + ret = nm_read_reg_with_ret(HOST_CORT_COMM, ®); + if(ret != M2M_SUCCESS)goto ERR1; + if(reg & NBIT0) + { + reg &= ~NBIT0; + ret = nm_write_reg(HOST_CORT_COMM, reg); + if(ret != M2M_SUCCESS)goto ERR1; + } + +ERR1: + return ret; +} +sint8 chip_wake(void) +{ + sint8 ret = M2M_SUCCESS; + uint32 reg = 0, clk_status_reg = 0,trials = 0; + + ret = nm_read_reg_with_ret(HOST_CORT_COMM, ®); + if(ret != M2M_SUCCESS)goto _WAKE_EXIT; + + if(!(reg & NBIT0)) + { + /*USE bit 0 to indicate host wakeup*/ + ret = nm_write_reg(HOST_CORT_COMM, reg|NBIT0); + if(ret != M2M_SUCCESS)goto _WAKE_EXIT; + } + + ret = nm_read_reg_with_ret(WAKE_CLK_REG, ®); + if(ret != M2M_SUCCESS)goto _WAKE_EXIT; + /* Set bit 1 */ + if(!(reg & NBIT1)) + { + ret = nm_write_reg(WAKE_CLK_REG, reg | NBIT1); + if(ret != M2M_SUCCESS) goto _WAKE_EXIT; + } + + do + { + ret = nm_read_reg_with_ret(CLOCKS_EN_REG, &clk_status_reg); + if(ret != M2M_SUCCESS) { + M2M_ERR("Bus error (5).%d %lx\n",ret,clk_status_reg); + goto _WAKE_EXIT; + } + if(clk_status_reg & NBIT2) { + break; + } + nm_bsp_sleep(2); + trials++; + if(trials > WAKUP_TRAILS_TIMEOUT) + { + M2M_ERR("Failed to wakup the chip\n"); + ret = M2M_ERR_TIME_OUT; + goto _WAKE_EXIT; + } + }while(1); + + /*workaround sometimes spi fail to read clock regs after reading/writing clockless registers*/ + nm_bus_reset(); + +_WAKE_EXIT: + return ret; +} +sint8 cpu_halt(void) +{ + sint8 ret; + uint32 reg = 0; + ret = nm_read_reg_with_ret(0x1118, ®); + reg |= (1 << 0); + ret += nm_write_reg(0x1118, reg); + ret += nm_read_reg_with_ret(NMI_GLB_RESET_0, ®); + if ((reg & (1ul << 10)) == (1ul << 10)) { + reg &= ~(1ul << 10); + ret += nm_write_reg(NMI_GLB_RESET_0, reg); + ret += nm_read_reg_with_ret(NMI_GLB_RESET_0, ®); + } + return ret; +} +sint8 chip_reset_and_cpu_halt(void) +{ + sint8 ret = M2M_SUCCESS; + + /*Wakeup needed only for I2C interface*/ + ret = chip_wake(); + if(ret != M2M_SUCCESS) goto ERR1; + /*Reset and CPU halt need for no wait board only*/ + ret = chip_reset(); + if(ret != M2M_SUCCESS) goto ERR1; + ret = cpu_halt(); + if(ret != M2M_SUCCESS) goto ERR1; +ERR1: + return ret; +} +sint8 chip_reset(void) +{ + sint8 ret = M2M_SUCCESS; + ret = nm_write_reg(NMI_GLB_RESET_0, 0); + nm_bsp_sleep(50); + return ret; +} + +sint8 wait_for_bootrom(uint8 arg) +{ + sint8 ret = M2M_SUCCESS; + uint32 reg = 0, cnt = 0; + uint32 u32GpReg1 = 0; + uint32 u32DriverVerInfo = M2M_MAKE_VERSION_INFO(M2M_RELEASE_VERSION_MAJOR_NO,\ + M2M_RELEASE_VERSION_MINOR_NO, M2M_RELEASE_VERSION_PATCH_NO,\ + M2M_RELEASE_VERSION_MAJOR_NO, M2M_RELEASE_VERSION_MINOR_NO,\ + M2M_RELEASE_VERSION_PATCH_NO); + + + reg = 0; + while(1) { + reg = nm_read_reg(0x1014); /* wait for efuse loading done */ + if (reg & 0x80000000) { + break; + } + nm_bsp_sleep(1); /* TODO: Why bus error if this delay is not here. */ + } + reg = nm_read_reg(M2M_WAIT_FOR_HOST_REG); + reg &= 0x1; + + /* check if waiting for the host will be skipped or not */ + if(reg == 0) + { + reg = 0; + while(reg != M2M_FINISH_BOOT_ROM) + { + nm_bsp_sleep(1); + reg = nm_read_reg(BOOTROM_REG); + + if(++cnt > TIMEOUT) + { + M2M_DBG("failed to load firmware from flash.\n"); + ret = M2M_ERR_INIT; + goto ERR2; + } + } + } + + if(M2M_WIFI_MODE_ATE_HIGH == arg) { + nm_write_reg(NMI_REV_REG, M2M_ATE_FW_START_VALUE); + nm_write_reg(NMI_STATE_REG, NBIT20); + }else if(M2M_WIFI_MODE_ATE_LOW == arg) { + nm_write_reg(NMI_REV_REG, M2M_ATE_FW_START_VALUE); + nm_write_reg(NMI_STATE_REG, 0); + }else if(M2M_WIFI_MODE_ETHERNET == arg){ + u32GpReg1 = rHAVE_ETHERNET_MODE_BIT; + nm_write_reg(NMI_STATE_REG, u32DriverVerInfo); + } else { + /*bypass this step*/ + nm_write_reg(NMI_STATE_REG, u32DriverVerInfo); + } + + if(REV(nmi_get_chipid()) >= REV_3A0){ + chip_apply_conf(u32GpReg1 | rHAVE_USE_PMU_BIT); + } else { + chip_apply_conf(u32GpReg1); + } + M2M_INFO("DriverVerInfo: 0x%08lx\n",u32DriverVerInfo); + + nm_write_reg(BOOTROM_REG,M2M_START_FIRMWARE); + +#ifdef __ROM_TEST__ + rom_test(); +#endif /* __ROM_TEST__ */ + +ERR2: + return ret; +} + +sint8 wait_for_firmware_start(uint8 arg) +{ + sint8 ret = M2M_SUCCESS; + uint32 reg = 0, cnt = 0; + uint32 u32Timeout = TIMEOUT; + volatile uint32 regAddress = NMI_STATE_REG; + volatile uint32 checkValue = M2M_FINISH_INIT_STATE; + + if((M2M_WIFI_MODE_ATE_HIGH == arg)||(M2M_WIFI_MODE_ATE_LOW == arg)) { + regAddress = NMI_REV_REG; + checkValue = M2M_ATE_FW_IS_UP_VALUE; + } else { + /*bypass this step*/ + } + + + while (checkValue != reg) + { + nm_bsp_sleep(2); /* TODO: Why bus error if this delay is not here. */ + M2M_DBG("%x %x %x\n",(unsigned int)nm_read_reg(0x108c),(unsigned int)nm_read_reg(0x108c),(unsigned int)nm_read_reg(0x14A0)); + reg = nm_read_reg(regAddress); + if(++cnt >= u32Timeout) + { + M2M_DBG("Time out for wait firmware Run\n"); + ret = M2M_ERR_INIT; + goto ERR; + } + } + if(M2M_FINISH_INIT_STATE == checkValue) + { + nm_write_reg(NMI_STATE_REG, 0); + } +ERR: + return ret; +} + +sint8 chip_deinit(void) +{ + uint32 reg = 0; + sint8 ret; + + /** + stop the firmware, need a re-download + **/ + ret = nm_read_reg_with_ret(NMI_GLB_RESET_0, ®); + if (ret != M2M_SUCCESS) { + M2M_ERR("failed to de-initialize\n"); + goto ERR1; + } + reg &= ~(1 << 10); + ret = nm_write_reg(NMI_GLB_RESET_0, reg); + if (ret != M2M_SUCCESS) { + M2M_ERR("failed to de-initialize\n"); + goto ERR1; + } + +ERR1: + return ret; +} + +#ifdef CONF_PERIPH + +sint8 set_gpio_dir(uint8 gpio, uint8 dir) +{ + uint32 val32; + sint8 ret; + + ret = nm_read_reg_with_ret(0x20108, &val32); + if(ret != M2M_SUCCESS) goto _EXIT; + + if(dir) { + val32 |= (1ul << gpio); + } else { + val32 &= ~(1ul << gpio); + } + + ret = nm_write_reg(0x20108, val32); + +_EXIT: + return ret; +} +sint8 set_gpio_val(uint8 gpio, uint8 val) +{ + uint32 val32; + sint8 ret; + + ret = nm_read_reg_with_ret(0x20100, &val32); + if(ret != M2M_SUCCESS) goto _EXIT; + + if(val) { + val32 |= (1ul << gpio); + } else { + val32 &= ~(1ul << gpio); + } + + ret = nm_write_reg(0x20100, val32); + +_EXIT: + return ret; +} + +sint8 get_gpio_val(uint8 gpio, uint8* val) +{ + uint32 val32; + sint8 ret; + + ret = nm_read_reg_with_ret(0x20104, &val32); + if(ret != M2M_SUCCESS) goto _EXIT; + + *val = (uint8)((val32 >> gpio) & 0x01); + +_EXIT: + return ret; +} + +sint8 pullup_ctrl(uint32 pinmask, uint8 enable) +{ + sint8 s8Ret; + uint32 val32; + s8Ret = nm_read_reg_with_ret(0x142c, &val32); + if(s8Ret != M2M_SUCCESS) { + M2M_ERR("[pullup_ctrl]: failed to read\n"); + goto _EXIT; + } + if(enable) { + val32 &= ~pinmask; + } else { + val32 |= pinmask; + } + s8Ret = nm_write_reg(0x142c, val32); + if(s8Ret != M2M_SUCCESS) { + M2M_ERR("[pullup_ctrl]: failed to write\n"); + goto _EXIT; + } +_EXIT: + return s8Ret; +} +#endif /* CONF_PERIPH */ + +sint8 nmi_get_otp_mac_address(uint8 *pu8MacAddr, uint8 * pu8IsValid) +{ + sint8 ret; + uint32 u32RegValue; + uint8 mac[6]; + tstrGpRegs strgp = {0}; + + ret = nm_read_reg_with_ret(rNMI_GP_REG_2, &u32RegValue); + if(ret != M2M_SUCCESS) goto _EXIT_ERR; +#ifdef ARDUINO + if (u32RegValue) { + ret = nm_read_block(u32RegValue|0x30000,(uint8*)&strgp,sizeof(tstrGpRegs)); + if(ret != M2M_SUCCESS) goto _EXIT_ERR; + u32RegValue = strgp.u32Mac_efuse_mib; + } else { + // firmware version 19.3.0 + ret = nm_read_reg_with_ret(rNMI_GP_REG_0, &u32RegValue); + if(ret != M2M_SUCCESS) goto _EXIT_ERR; + } +#else + ret = nm_read_block(u32RegValue|0x30000,(uint8*)&strgp,sizeof(tstrGpRegs)); + if(ret != M2M_SUCCESS) goto _EXIT_ERR; + u32RegValue = strgp.u32Mac_efuse_mib; +#endif + if(!EFUSED_MAC(u32RegValue)) { + M2M_DBG("Default MAC\n"); + m2m_memset(pu8MacAddr, 0, 6); + goto _EXIT_ERR; + } + + M2M_DBG("OTP MAC\n"); + u32RegValue >>=16; + ret = nm_read_block(u32RegValue|0x30000, mac, 6); + m2m_memcpy(pu8MacAddr,mac,6); + if(pu8IsValid) *pu8IsValid = 1; + return ret; + +_EXIT_ERR: + if(pu8IsValid) *pu8IsValid = 0; + return ret; +} + +sint8 nmi_get_mac_address(uint8 *pu8MacAddr) +{ + sint8 ret; + uint32 u32RegValue; + uint8 mac[6]; + tstrGpRegs strgp = {0}; + + ret = nm_read_reg_with_ret(rNMI_GP_REG_2, &u32RegValue); + if(ret != M2M_SUCCESS) goto _EXIT_ERR; +#ifdef ARDUINO + if (u32RegValue) { + ret = nm_read_block(u32RegValue|0x30000,(uint8*)&strgp,sizeof(tstrGpRegs)); + if(ret != M2M_SUCCESS) goto _EXIT_ERR; + u32RegValue = strgp.u32Mac_efuse_mib; + } else { + // firmware version 19.3.0 + ret = nm_read_reg_with_ret(rNMI_GP_REG_0, &u32RegValue); + if(ret != M2M_SUCCESS) goto _EXIT_ERR; + } +#else + ret = nm_read_block(u32RegValue|0x30000,(uint8*)&strgp,sizeof(tstrGpRegs)); + if(ret != M2M_SUCCESS) goto _EXIT_ERR; + u32RegValue = strgp.u32Mac_efuse_mib; +#endif + u32RegValue &=0x0000ffff; + ret = nm_read_block(u32RegValue|0x30000, mac, 6); + m2m_memcpy(pu8MacAddr, mac, 6); + + return ret; + +_EXIT_ERR: + return ret; +} diff --git a/lib/WiFi101/src/driver/source/nmasic.h b/lib/WiFi101/src/driver/source/nmasic.h new file mode 100644 index 0000000..84a395b --- /dev/null +++ b/lib/WiFi101/src/driver/source/nmasic.h @@ -0,0 +1,215 @@ +/** + * + * \file + * + * \brief This module contains NMC1500 ASIC specific internal APIs. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef _NMASIC_H_ +#define _NMASIC_H_ + +#include "common/include/nm_common.h" + +#define NMI_PERIPH_REG_BASE 0x1000 +#define NMI_CHIPID (NMI_PERIPH_REG_BASE) +#define rNMI_GP_REG_0 (0x149c) +#define rNMI_GP_REG_1 (0x14A0) +#define rNMI_GP_REG_2 (0xc0008) +#define rNMI_GLB_RESET (0x1400) +#define rNMI_BOOT_RESET_MUX (0x1118) +#define NMI_STATE_REG (0x108c) +#define BOOTROM_REG (0xc000c) +#define NMI_REV_REG (0x207ac) /*Also, Used to load ATE firmware from SPI Flash and to ensure that it is running too*/ +#define NMI_REV_REG_ATE (0x1048) /*Revision info register in case of ATE FW*/ +#define M2M_WAIT_FOR_HOST_REG (0x207bc) +#define M2M_FINISH_INIT_STATE 0x02532636UL +#define M2M_FINISH_BOOT_ROM 0x10add09eUL +#define M2M_START_FIRMWARE 0xef522f61UL +#define M2M_START_PS_FIRMWARE 0x94992610UL + +#define M2M_ATE_FW_START_VALUE (0x3C1CD57D) /*Also, Change this value in boot_firmware if it will be changed here*/ +#define M2M_ATE_FW_IS_UP_VALUE (0xD75DC1C3) /*Also, Change this value in ATE (Burst) firmware if it will be changed here*/ + +#define REV_2B0 (0x2B0) +#define REV_B0 (0x2B0) +#define REV_3A0 (0x3A0) +#define GET_CHIPID() nmi_get_chipid() +#define ISNMC1000(id) ((((id) & 0xfffff000) == 0x100000) ? 1 : 0) +#define ISNMC1500(id) ((((id) & 0xfffff000) == 0x150000) ? 1 : 0) +#define ISNMC3000(id) ((((id) & 0xfff00000) == 0x300000) ? 1 : 0) +#define REV(id) (((id) & 0x00000fff )) +#define EFUSED_MAC(value) (value & 0xffff0000) + +#define rHAVE_SDIO_IRQ_GPIO_BIT (NBIT0) +#define rHAVE_USE_PMU_BIT (NBIT1) +#define rHAVE_SLEEP_CLK_SRC_RTC_BIT (NBIT2) +#define rHAVE_SLEEP_CLK_SRC_XO_BIT (NBIT3) +#define rHAVE_EXT_PA_INV_TX_RX (NBIT4) +#define rHAVE_LEGACY_RF_SETTINGS (NBIT5) +#define rHAVE_LOGS_DISABLED_BIT (NBIT6) +#define rHAVE_ETHERNET_MODE_BIT (NBIT7) +#define rHAVE_RESERVED1_BIT (NBIT8) + +typedef struct{ + uint32 u32Mac_efuse_mib; + uint32 u32Firmware_Ota_rev; +}tstrGpRegs; + +#ifdef __cplusplus + extern "C" { +#endif + +/* +* @fn cpu_halt +* @brief +*/ +sint8 cpu_halt(void); +/* +* @fn chip_sleep +* @brief +*/ +sint8 chip_sleep(void); +/* +* @fn chip_wake +* @brief +*/ +sint8 chip_wake(void); +/* +* @fn chip_idle +* @brief +*/ +void chip_idle(void); +/* +* @fn enable_interrupts +* @brief +*/ +sint8 enable_interrupts(void); +/* +* @fn cpu_start +* @brief +*/ +sint8 cpu_start(void); +/* +* @fn nmi_get_chipid +* @brief +*/ +uint32 nmi_get_chipid(void); +/* +* @fn nmi_get_rfrevid +* @brief +*/ +uint32 nmi_get_rfrevid(void); +/* +* @fn restore_pmu_settings_after_global_reset +* @brief +*/ +void restore_pmu_settings_after_global_reset(void); +/* +* @fn nmi_update_pll +* @brief +*/ +void nmi_update_pll(void); +/* +* @fn nmi_set_sys_clk_src_to_xo +* @brief +*/ +void nmi_set_sys_clk_src_to_xo(void); +/* +* @fn chip_reset +* @brief +*/ +sint8 chip_reset(void); +/* +* @fn wait_for_bootrom +* @brief +*/ +sint8 wait_for_bootrom(uint8); +/* +* @fn wait_for_firmware_start +* @brief +*/ +sint8 wait_for_firmware_start(uint8); +/* +* @fn chip_deinit +* @brief +*/ +sint8 chip_deinit(void); +/* +* @fn chip_reset_and_cpu_halt +* @brief +*/ +sint8 chip_reset_and_cpu_halt(void); +/* +* @fn set_gpio_dir +* @brief +*/ +sint8 set_gpio_dir(uint8 gpio, uint8 dir); +/* +* @fn set_gpio_val +* @brief +*/ +sint8 set_gpio_val(uint8 gpio, uint8 val); +/* +* @fn get_gpio_val +* @brief +*/ +sint8 get_gpio_val(uint8 gpio, uint8* val); +/* +* @fn pullup_ctrl +* @brief +*/ +sint8 pullup_ctrl(uint32 pinmask, uint8 enable); +/* +* @fn nmi_get_otp_mac_address +* @brief +*/ +sint8 nmi_get_otp_mac_address(uint8 *pu8MacAddr, uint8 * pu8IsValid); +/* +* @fn nmi_get_mac_address +* @brief +*/ +sint8 nmi_get_mac_address(uint8 *pu8MacAddr); +/* +* @fn chip_apply_conf +* @brief +*/ +sint8 chip_apply_conf(uint32 u32conf); + +#ifdef __cplusplus + } +#endif + +#endif /*_NMASIC_H_*/ diff --git a/lib/WiFi101/src/driver/source/nmbus.c b/lib/WiFi101/src/driver/source/nmbus.c new file mode 100644 index 0000000..d001d72 --- /dev/null +++ b/lib/WiFi101/src/driver/source/nmbus.c @@ -0,0 +1,301 @@ +/** + * + * \file + * + * \brief This module contains NMC1000 bus APIs implementation. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef CORTUS_APP + +#include "nmbus.h" +#include "nmi2c.h" +#include "nmspi.h" +#include "nmuart.h" + +#define MAX_TRX_CFG_SZ 8 + +/** +* @fn nm_bus_iface_init +* @brief Initialize bus interface +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +sint8 nm_bus_iface_init(void *pvInitVal) +{ + sint8 ret = M2M_SUCCESS; + ret = nm_bus_init(pvInitVal); + return ret; +} + +/** +* @fn nm_bus_iface_deinit +* @brief Deinitialize bus interface +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author Samer Sarhan +* @date 07 April 2014 +* @version 1.0 +*/ +sint8 nm_bus_iface_deinit(void) +{ + sint8 ret = M2M_SUCCESS; + ret = nm_bus_deinit(); + + return ret; +} + +/** +* @fn nm_bus_reset +* @brief reset bus interface +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @version 1.0 +*/ +sint8 nm_bus_reset(void) +{ + sint8 ret = M2M_SUCCESS; +#ifdef CONF_WINC_USE_UART +#elif defined (CONF_WINC_USE_SPI) + return nm_spi_reset(); +#elif defined (CONF_WINC_USE_I2C) +#else +#error "Plesae define bus usage" +#endif + + return ret; +} + +/** +* @fn nm_bus_iface_reconfigure +* @brief reconfigure bus interface +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author Viswanathan Murugesan +* @date 22 Oct 2014 +* @version 1.0 +*/ +sint8 nm_bus_iface_reconfigure(void *ptr) +{ +#ifdef ARDUINO + (void)ptr; // Silence "unused" warning +#endif + sint8 ret = M2M_SUCCESS; +#ifdef CONF_WINC_USE_UART + ret = nm_uart_reconfigure(ptr); +#endif + return ret; +} +/* +* @fn nm_read_reg +* @brief Read register +* @param [in] u32Addr +* Register address +* @return Register value +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +uint32 nm_read_reg(uint32 u32Addr) +{ +#ifdef CONF_WINC_USE_UART + return nm_uart_read_reg(u32Addr); +#elif defined (CONF_WINC_USE_SPI) + return nm_spi_read_reg(u32Addr); +#elif defined (CONF_WINC_USE_I2C) + return nm_i2c_read_reg(u32Addr); +#else +#error "Plesae define bus usage" +#endif + +} + +/* +* @fn nm_read_reg_with_ret +* @brief Read register with error code return +* @param [in] u32Addr +* Register address +* @param [out] pu32RetVal +* Pointer to u32 variable used to return the read value +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +sint8 nm_read_reg_with_ret(uint32 u32Addr, uint32* pu32RetVal) +{ +#ifdef CONF_WINC_USE_UART + return nm_uart_read_reg_with_ret(u32Addr,pu32RetVal); +#elif defined (CONF_WINC_USE_SPI) + return nm_spi_read_reg_with_ret(u32Addr,pu32RetVal); +#elif defined (CONF_WINC_USE_I2C) + return nm_i2c_read_reg_with_ret(u32Addr,pu32RetVal); +#else +#error "Plesae define bus usage" +#endif +} + +/* +* @fn nm_write_reg +* @brief write register +* @param [in] u32Addr +* Register address +* @param [in] u32Val +* Value to be written to the register +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +sint8 nm_write_reg(uint32 u32Addr, uint32 u32Val) +{ +#ifdef CONF_WINC_USE_UART + return nm_uart_write_reg(u32Addr,u32Val); +#elif defined (CONF_WINC_USE_SPI) + return nm_spi_write_reg(u32Addr,u32Val); +#elif defined (CONF_WINC_USE_I2C) + return nm_i2c_write_reg(u32Addr,u32Val); +#else +#error "Plesae define bus usage" +#endif +} + +static sint8 p_nm_read_block(uint32 u32Addr, uint8 *puBuf, uint16 u16Sz) +{ +#ifdef CONF_WINC_USE_UART + return nm_uart_read_block(u32Addr,puBuf,u16Sz); +#elif defined (CONF_WINC_USE_SPI) + return nm_spi_read_block(u32Addr,puBuf,u16Sz); +#elif defined (CONF_WINC_USE_I2C) + return nm_i2c_read_block(u32Addr,puBuf,u16Sz); +#else +#error "Plesae define bus usage" +#endif + +} +/* +* @fn nm_read_block +* @brief Read block of data +* @param [in] u32Addr +* Start address +* @param [out] puBuf +* Pointer to a buffer used to return the read data +* @param [in] u32Sz +* Number of bytes to read. The buffer size must be >= u32Sz +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +sint8 nm_read_block(uint32 u32Addr, uint8 *puBuf, uint32 u32Sz) +{ + uint16 u16MaxTrxSz = egstrNmBusCapabilities.u16MaxTrxSz - MAX_TRX_CFG_SZ; + uint32 off = 0; + sint8 s8Ret = M2M_SUCCESS; + + for(;;) + { + if(u32Sz <= u16MaxTrxSz) + { + s8Ret += p_nm_read_block(u32Addr, &puBuf[off], (uint16)u32Sz); + break; + } + else + { + s8Ret += p_nm_read_block(u32Addr, &puBuf[off], u16MaxTrxSz); + if(M2M_SUCCESS != s8Ret) break; + u32Sz -= u16MaxTrxSz; + off += u16MaxTrxSz; + u32Addr += u16MaxTrxSz; + } + } + + return s8Ret; +} + +static sint8 p_nm_write_block(uint32 u32Addr, uint8 *puBuf, uint16 u16Sz) +{ +#ifdef CONF_WINC_USE_UART + return nm_uart_write_block(u32Addr,puBuf,u16Sz); +#elif defined (CONF_WINC_USE_SPI) + return nm_spi_write_block(u32Addr,puBuf,u16Sz); +#elif defined (CONF_WINC_USE_I2C) + return nm_i2c_write_block(u32Addr,puBuf,u16Sz); +#else +#error "Plesae define bus usage" +#endif + +} +/** +* @fn nm_write_block +* @brief Write block of data +* @param [in] u32Addr +* Start address +* @param [in] puBuf +* Pointer to the buffer holding the data to be written +* @param [in] u32Sz +* Number of bytes to write. The buffer size must be >= u32Sz +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +sint8 nm_write_block(uint32 u32Addr, uint8 *puBuf, uint32 u32Sz) +{ + uint16 u16MaxTrxSz = egstrNmBusCapabilities.u16MaxTrxSz - MAX_TRX_CFG_SZ; + uint32 off = 0; + sint8 s8Ret = M2M_SUCCESS; + + for(;;) + { + if(u32Sz <= u16MaxTrxSz) + { + s8Ret += p_nm_write_block(u32Addr, &puBuf[off], (uint16)u32Sz); + break; + } + else + { + s8Ret += p_nm_write_block(u32Addr, &puBuf[off], u16MaxTrxSz); + if(M2M_SUCCESS != s8Ret) break; + u32Sz -= u16MaxTrxSz; + off += u16MaxTrxSz; + u32Addr += u16MaxTrxSz; + } + } + + return s8Ret; +} + +#endif + diff --git a/lib/WiFi101/src/driver/source/nmbus.h b/lib/WiFi101/src/driver/source/nmbus.h new file mode 100644 index 0000000..2ea7838 --- /dev/null +++ b/lib/WiFi101/src/driver/source/nmbus.h @@ -0,0 +1,147 @@ +/** + * + * \file + * + * \brief This module contains NMC1000 bus APIs implementation. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _NMBUS_H_ +#define _NMBUS_H_ + +#include "common/include/nm_common.h" +#include "bus_wrapper/include/nm_bus_wrapper.h" + + + +#ifdef __cplusplus +extern "C"{ +#endif +/** +* @fn nm_bus_iface_init +* @brief Initialize bus interface +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_bus_iface_init(void *); + + +/** +* @fn nm_bus_iface_deinit +* @brief Deinitialize bus interface +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_bus_iface_deinit(void); + +/** +* @fn nm_bus_reset +* @brief reset bus interface +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @version 1.0 +*/ +sint8 nm_bus_reset(void); + +/** +* @fn nm_bus_iface_reconfigure +* @brief reconfigure bus interface +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_bus_iface_reconfigure(void *ptr); + +/** +* @fn nm_read_reg +* @brief Read register +* @param [in] u32Addr +* Register address +* @return Register value +*/ +uint32 nm_read_reg(uint32 u32Addr); + +/** +* @fn nm_read_reg_with_ret +* @brief Read register with error code return +* @param [in] u32Addr +* Register address +* @param [out] pu32RetVal +* Pointer to u32 variable used to return the read value +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_read_reg_with_ret(uint32 u32Addr, uint32* pu32RetVal); + +/** +* @fn nm_write_reg +* @brief write register +* @param [in] u32Addr +* Register address +* @param [in] u32Val +* Value to be written to the register +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_write_reg(uint32 u32Addr, uint32 u32Val); + +/** +* @fn nm_read_block +* @brief Read block of data +* @param [in] u32Addr +* Start address +* @param [out] puBuf +* Pointer to a buffer used to return the read data +* @param [in] u32Sz +* Number of bytes to read. The buffer size must be >= u32Sz +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_read_block(uint32 u32Addr, uint8 *puBuf, uint32 u32Sz); + +/** +* @fn nm_write_block +* @brief Write block of data +* @param [in] u32Addr +* Start address +* @param [in] puBuf +* Pointer to the buffer holding the data to be written +* @param [in] u32Sz +* Number of bytes to write. The buffer size must be >= u32Sz +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_write_block(uint32 u32Addr, uint8 *puBuf, uint32 u32Sz); + + + + +#ifdef __cplusplus +} +#endif + +#endif /* _NMBUS_H_ */ diff --git a/lib/WiFi101/src/driver/source/nmdrv.c b/lib/WiFi101/src/driver/source/nmdrv.c new file mode 100644 index 0000000..396ade9 --- /dev/null +++ b/lib/WiFi101/src/driver/source/nmdrv.c @@ -0,0 +1,408 @@ +/** + * + * \file + * + * \brief This module contains NMC1000 M2M driver APIs implementation. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include "common/include/nm_common.h" +#include "driver/source/nmbus.h" +#include "bsp/include/nm_bsp.h" +#include "driver/source/nmdrv.h" +#include "driver/source/nmasic.h" +#include "driver/include/m2m_types.h" +#include "spi_flash/include/spi_flash.h" + +#ifdef CONF_WINC_USE_SPI +#include "driver/source/nmspi.h" +#endif + +#ifdef ARDUINO + uint32 nmdrv_firm_ver = 0; +#endif + +/** +* @fn nm_get_firmware_info(tstrM2mRev* M2mRev) +* @brief Get Firmware version info +* @param [out] M2mRev +* pointer holds address of structure "tstrM2mRev" that contains the firmware version parameters +* @version 1.0 +*/ +sint8 nm_get_firmware_info(tstrM2mRev* M2mRev) +{ + uint16 curr_drv_ver, min_req_drv_ver,curr_firm_ver; + uint32 reg = 0; + sint8 ret = M2M_SUCCESS; + + ret = nm_read_reg_with_ret(NMI_REV_REG, ®); + //In case the Firmware running is ATE fw + if(M2M_ATE_FW_IS_UP_VALUE == reg) + { + //Read FW info again from the register specified for ATE + ret = nm_read_reg_with_ret(NMI_REV_REG_ATE, ®); + } + M2mRev->u8DriverMajor = M2M_GET_DRV_MAJOR(reg); + M2mRev->u8DriverMinor = M2M_GET_DRV_MINOR(reg); + M2mRev->u8DriverPatch = M2M_GET_DRV_PATCH(reg); + M2mRev->u8FirmwareMajor = M2M_GET_FW_MAJOR(reg); + M2mRev->u8FirmwareMinor = M2M_GET_FW_MINOR(reg); + M2mRev->u8FirmwarePatch = M2M_GET_FW_PATCH(reg); + M2mRev->u32Chipid = nmi_get_chipid(); + M2mRev->u16FirmwareSvnNum = 0; + + curr_firm_ver = M2M_MAKE_VERSION(M2mRev->u8FirmwareMajor, M2mRev->u8FirmwareMinor,M2mRev->u8FirmwarePatch); +#ifdef ARDUINO + nmdrv_firm_ver = curr_firm_ver; +#endif + curr_drv_ver = M2M_MAKE_VERSION(M2M_RELEASE_VERSION_MAJOR_NO, M2M_RELEASE_VERSION_MINOR_NO, M2M_RELEASE_VERSION_PATCH_NO); + min_req_drv_ver = M2M_MAKE_VERSION(M2mRev->u8DriverMajor, M2mRev->u8DriverMinor,M2mRev->u8DriverPatch); + if(curr_drv_ver < min_req_drv_ver) { + /*The current driver version should be larger or equal + than the min driver that the current firmware support */ + ret = M2M_ERR_FW_VER_MISMATCH; + } + if(curr_drv_ver > curr_firm_ver) { + /*The current driver should be equal or less than the firmware version*/ + ret = M2M_ERR_FW_VER_MISMATCH; + } + return ret; +} +/** +* @fn nm_get_firmware_info(tstrM2mRev* M2mRev) +* @brief Get Firmware version info +* @param [out] M2mRev +* pointer holds address of structure "tstrM2mRev" that contains the firmware version parameters +* @version 1.0 +*/ +sint8 nm_get_firmware_full_info(tstrM2mRev* pstrRev) +{ + uint16 curr_drv_ver, min_req_drv_ver,curr_firm_ver; + uint32 reg = 0; + sint8 ret = M2M_SUCCESS; + tstrGpRegs strgp = {0}; + if (pstrRev != NULL) + { + m2m_memset((uint8*)pstrRev,0,sizeof(tstrM2mRev)); + ret = nm_read_reg_with_ret(rNMI_GP_REG_2, ®); + if(ret == M2M_SUCCESS) + { + if(reg != 0) + { + ret = nm_read_block(reg|0x30000,(uint8*)&strgp,sizeof(tstrGpRegs)); + if(ret == M2M_SUCCESS) + { + reg = strgp.u32Firmware_Ota_rev; + reg &= 0x0000ffff; + if(reg != 0) + { + ret = nm_read_block(reg|0x30000,(uint8*)pstrRev,sizeof(tstrM2mRev)); + if(ret == M2M_SUCCESS) + { + curr_firm_ver = M2M_MAKE_VERSION(pstrRev->u8FirmwareMajor, pstrRev->u8FirmwareMinor,pstrRev->u8FirmwarePatch); +#ifdef ARDUINO + nmdrv_firm_ver = curr_firm_ver; +#endif + curr_drv_ver = M2M_MAKE_VERSION(M2M_RELEASE_VERSION_MAJOR_NO, M2M_RELEASE_VERSION_MINOR_NO, M2M_RELEASE_VERSION_PATCH_NO); + min_req_drv_ver = M2M_MAKE_VERSION(pstrRev->u8DriverMajor, pstrRev->u8DriverMinor,pstrRev->u8DriverPatch); + if((curr_firm_ver == 0)||(min_req_drv_ver == 0)||(min_req_drv_ver == 0)){ + ret = M2M_ERR_FAIL; + goto EXIT; + } + if(curr_drv_ver < min_req_drv_ver) { + /*The current driver version should be larger or equal + than the min driver that the current firmware support */ + ret = M2M_ERR_FW_VER_MISMATCH; + goto EXIT; + } + if(curr_drv_ver > curr_firm_ver) { + /*The current driver should be equal or less than the firmware version*/ + ret = M2M_ERR_FW_VER_MISMATCH; + goto EXIT; + } + } + }else { + ret = M2M_ERR_FAIL; + } + } + }else{ + ret = M2M_ERR_FAIL; + } + } + } +EXIT: + return ret; +} +/** +* @fn nm_get_ota_firmware_info(tstrM2mRev* pstrRev) +* @brief Get Firmware version info +* @param [out] M2mRev +* pointer holds address of structure "tstrM2mRev" that contains the firmware version parameters + +* @version 1.0 +*/ +sint8 nm_get_ota_firmware_info(tstrM2mRev* pstrRev) +{ + uint16 curr_drv_ver, min_req_drv_ver,curr_firm_ver; + uint32 reg = 0; + sint8 ret; + tstrGpRegs strgp = {0}; + + if (pstrRev != NULL) + { + m2m_memset((uint8*)pstrRev,0,sizeof(tstrM2mRev)); + ret = nm_read_reg_with_ret(rNMI_GP_REG_2, ®); + if(ret == M2M_SUCCESS) + { + if(reg != 0) + { + ret = nm_read_block(reg|0x30000,(uint8*)&strgp,sizeof(tstrGpRegs)); + if(ret == M2M_SUCCESS) + { + reg = strgp.u32Firmware_Ota_rev; + reg >>= 16; + if(reg != 0) + { + ret = nm_read_block(reg|0x30000,(uint8*)pstrRev,sizeof(tstrM2mRev)); + if(ret == M2M_SUCCESS) + { + curr_firm_ver = M2M_MAKE_VERSION(pstrRev->u8FirmwareMajor, pstrRev->u8FirmwareMinor,pstrRev->u8FirmwarePatch); + curr_drv_ver = M2M_MAKE_VERSION(M2M_RELEASE_VERSION_MAJOR_NO, M2M_RELEASE_VERSION_MINOR_NO, M2M_RELEASE_VERSION_PATCH_NO); + min_req_drv_ver = M2M_MAKE_VERSION(pstrRev->u8DriverMajor, pstrRev->u8DriverMinor,pstrRev->u8DriverPatch); + if((curr_firm_ver == 0)||(min_req_drv_ver == 0)||(min_req_drv_ver == 0)){ + ret = M2M_ERR_FAIL; + goto EXIT; + } + if(curr_drv_ver < min_req_drv_ver) { + /*The current driver version should be larger or equal + than the min driver that the current firmware support */ + ret = M2M_ERR_FW_VER_MISMATCH; + } + if(curr_drv_ver > curr_firm_ver) { + /*The current driver should be equal or less than the firmware version*/ + ret = M2M_ERR_FW_VER_MISMATCH; + } + } + }else{ + ret = M2M_ERR_INVALID; + } + } + }else{ + ret = M2M_ERR_FAIL; + } + } + } else { + ret = M2M_ERR_INVALID_ARG; + } +EXIT: + return ret; +} + + + +/* +* @fn nm_drv_init_download_mode +* @brief Initialize NMC1000 driver +* @return M2M_SUCCESS in case of success and Negative error code in case of failure +* @param [in] arg +* Generic argument +* @author Viswanathan Murugesan +* @date 10 Oct 2014 +* @version 1.0 +*/ +sint8 nm_drv_init_download_mode() +{ + sint8 ret = M2M_SUCCESS; + + ret = nm_bus_iface_init(NULL); + if (M2M_SUCCESS != ret) { + M2M_ERR("[nmi start]: fail init bus\n"); + goto ERR1; + } + + /** + TODO:reset the chip and halt the cpu in case of no wait efuse is set (add the no wait effuse check) + */ + if(!ISNMC3000(GET_CHIPID())) + { + /*Execuate that function only for 1500A/B, no room in 3000, but it may be needed in 3400 no wait*/ + chip_reset_and_cpu_halt(); + } + +#ifdef CONF_WINC_USE_SPI + /* Must do this after global reset to set SPI data packet size. */ + nm_spi_init(); +#endif + + M2M_INFO("Chip ID %lx\n", nmi_get_chipid()); + + /*disable all interrupt in ROM (to disable uart) in 2b0 chip*/ + nm_write_reg(0x20300,0); + +ERR1: + return ret; +} + +/* +* @fn nm_drv_init +* @brief Initialize NMC1000 driver +* @return M2M_SUCCESS in case of success and Negative error code in case of failure +* @param [in] arg +* Generic argument +* @author M. Abdelmawla +* @date 15 July 2012 +* @version 1.0 +*/ +sint8 nm_drv_init(void * arg) +{ + sint8 ret = M2M_SUCCESS; + uint8 u8Mode; + + if(NULL != arg) { + u8Mode = *((uint8 *)arg); + if((u8Mode < M2M_WIFI_MODE_NORMAL)||(u8Mode >= M2M_WIFI_MODE_MAX)) { + u8Mode = M2M_WIFI_MODE_NORMAL; + } + } else { + u8Mode = M2M_WIFI_MODE_NORMAL; + } + + ret = nm_bus_iface_init(NULL); + if (M2M_SUCCESS != ret) { + M2M_ERR("[nmi start]: fail init bus\n"); + goto ERR1; + } + +#ifdef BUS_ONLY + return; +#endif + + +#ifdef NO_HW_CHIP_EN + ret = chip_wake(); + if (M2M_SUCCESS != ret) { + M2M_ERR("[nmi start]: fail chip_wakeup\n"); + goto ERR2; + } + /** + Go... + **/ + ret = chip_reset(); + if (M2M_SUCCESS != ret) { + goto ERR2; + } +#endif + M2M_INFO("Chip ID %lx\n", nmi_get_chipid()); +#ifdef ARDUINO + if ((REV(GET_CHIPID()) & 0xff0) != REV_3A0 && (REV(GET_CHIPID()) & 0xff0) != REV_B0) { + ret = M2M_ERR_INVALID; + goto ERR2; + } +#endif +#ifdef CONF_WINC_USE_SPI + /* Must do this after global reset to set SPI data packet size. */ + nm_spi_init(); +#endif + ret = wait_for_bootrom(u8Mode); + if (M2M_SUCCESS != ret) { + goto ERR2; + } + + ret = wait_for_firmware_start(u8Mode); + if (M2M_SUCCESS != ret) { + goto ERR2; + } + + if((M2M_WIFI_MODE_ATE_HIGH == u8Mode)||(M2M_WIFI_MODE_ATE_LOW == u8Mode)) { + goto ERR1; + } else { + /*continue running*/ + } + + ret = enable_interrupts(); + if (M2M_SUCCESS != ret) { + M2M_ERR("failed to enable interrupts..\n"); + goto ERR2; + } + return ret; +ERR2: + nm_bus_iface_deinit(); +ERR1: + return ret; +} + +/* +* @fn nm_drv_deinit +* @brief Deinitialize NMC1000 driver +* @author M. Abdelmawla +* @date 17 July 2012 +* @version 1.0 +*/ +sint8 nm_drv_deinit(void * arg) +{ +#ifdef ARDUINO + (void)arg; // Silence "unused" warning +#endif + sint8 ret; + + ret = chip_deinit(); + if (M2M_SUCCESS != ret) { + M2M_ERR("[nmi stop]: chip_deinit fail\n"); + goto ERR1; + } + + /* Disable SPI flash to save power when the chip is off */ + ret = spi_flash_enable(0); + if (M2M_SUCCESS != ret) { + M2M_ERR("[nmi stop]: SPI flash disable fail\n"); + goto ERR1; + } + + ret = nm_bus_iface_deinit(); + if (M2M_SUCCESS != ret) { + M2M_ERR("[nmi stop]: fail init bus\n"); + goto ERR1; + } +#ifdef CONF_WINC_USE_SPI + /* Must do this after global reset to set SPI data packet size. */ + nm_spi_deinit(); +#endif + +ERR1: + return ret; +} + + diff --git a/lib/WiFi101/src/driver/source/nmdrv.h b/lib/WiFi101/src/driver/source/nmdrv.h new file mode 100644 index 0000000..6a416b2 --- /dev/null +++ b/lib/WiFi101/src/driver/source/nmdrv.h @@ -0,0 +1,138 @@ +/** + * + * \file + * + * \brief This module contains NMC1500 M2M driver APIs declarations. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _NMDRV_H_ +#define _NMDRV_H_ + +#include "common/include/nm_common.h" + +/** +* @struct tstrM2mRev +* @brief Structure holding firmware version parameters and build date/time +*/ +typedef struct { + uint32 u32Chipid; /* HW revision which will be basically the chip ID */ + uint8 u8FirmwareMajor; /* Version Major Number which represents the official release base */ + uint8 u8FirmwareMinor; /* Version Minor Number which represents the engineering release base */ + uint8 u8FirmwarePatch; /* Version pathc Number which represents the pathces release base */ + uint8 u8DriverMajor; /* Version Major Number which represents the official release base */ + uint8 u8DriverMinor; /* Version Minor Number which represents the engineering release base */ + uint8 u8DriverPatch; /* Version Patch Number which represents the pathces release base */ + uint8 BuildDate[sizeof(__DATE__)]; + uint8 BuildTime[sizeof(__TIME__)]; + uint8 _PAD8_; + uint16 u16FirmwareSvnNum; + uint16 _PAD16_[2]; +} tstrM2mRev; + +/** +* @struct tstrM2mBinaryHeader +* @brief Structure holding compatibility version info for firmware binaries +*/ +typedef struct { + tstrM2mRev binVerInfo; + uint32 flashOffset; + uint32 payloadSize; +} tstrM2mBinaryHeader; + +#ifdef __cplusplus + extern "C" { + #endif +/** +* @fn nm_get_firmware_info(tstrM2mRev* M2mRev) +* @brief Get Firmware version info +* @param [out] M2mRev +* pointer holds address of structure "tstrM2mRev" that contains the firmware version parameters +* @version 1.0 +*/ +sint8 nm_get_firmware_info(tstrM2mRev* M2mRev); +/** +* @fn nm_get_firmware_full_info(tstrM2mRev* pstrRev) +* @brief Get Firmware version info +* @param [out] M2mRev +* pointer holds address of structure "tstrM2mRev" that contains the firmware version parameters +* @version 1.0 +*/ +sint8 nm_get_firmware_full_info(tstrM2mRev* pstrRev); +/** +* @fn nm_get_ota_firmware_info(tstrM2mRev* pstrRev) +* @brief Get Firmware version info +* @param [out] M2mRev +* pointer holds address of structure "tstrM2mRev" that contains the firmware version parameters + +* @version 1.0 +*/ +sint8 nm_get_ota_firmware_info(tstrM2mRev* pstrRev); +/* +* @fn nm_drv_init +* @brief Initialize NMC1000 driver +* @return ZERO in case of success and Negative error code in case of failure +*/ +sint8 nm_drv_init_download_mode(void); + +/* +* @fn nm_drv_init +* @brief Initialize NMC1000 driver +* @return M2M_SUCCESS in case of success and Negative error code in case of failure +* @param [in] arg +* Generic argument TBD +* @return ZERO in case of success and Negative error code in case of failure + +*/ +sint8 nm_drv_init(void * arg); + +/** +* @fn nm_drv_deinit +* @brief Deinitialize NMC1000 driver +* @author M. Abdelmawla +* @param [in] arg +* Generic argument TBD +* @return ZERO in case of success and Negative error code in case of failure +*/ +sint8 nm_drv_deinit(void * arg); + +#ifdef __cplusplus + } + #endif + +#endif /*_NMDRV_H_*/ + + diff --git a/lib/WiFi101/src/driver/source/nmi2c.c b/lib/WiFi101/src/driver/source/nmi2c.c new file mode 100644 index 0000000..e11d2f7 --- /dev/null +++ b/lib/WiFi101/src/driver/source/nmi2c.c @@ -0,0 +1,269 @@ +/** + * + * \file + * + * \brief This module contains NMC1000 I2C protocol bus APIs implementation. + * + * Copyright (c) 2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include "common/include/nm_common.h" + +#ifdef CONF_WINC_USE_I2C + +#include "nmi2c.h" +#include "bus_wrapper/include/nm_bus_wrapper.h" + + +/* +* @fn nm_i2c_read_reg_with_ret +* @brief Read register with error code return +* @param [in] u32Addr +* Register address +* @param [out] pu32RetVal +* Pointer to u32 variable used to return the read value +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ + sint8 nm_i2c_read_reg_with_ret(uint32 u32Addr, uint32* pu32RetVal) +{ + uint8 b[6]; + uint8 rsz; + tstrNmI2cDefault strI2c; + sint8 s8Ret = M2M_SUCCESS; + + if(u32Addr < 0xff) { /* clockless i2c */ + b[0] = 0x09; + b[1] = (uint8)(u32Addr); + rsz = 1; + strI2c.u16Sz = 2; + } else { + b[0] = 0x80; + b[1] = (uint8)(u32Addr >> 24); + b[2] = (uint8)(u32Addr >> 16); + b[3] = (uint8)(u32Addr >> 8); + b[4] = (uint8)(u32Addr); + b[5] = 0x04; + rsz = 4; + strI2c.u16Sz = 6; + } + + strI2c.pu8Buf = b; + + if(M2M_SUCCESS == nm_bus_ioctl(NM_BUS_IOCTL_W, &strI2c)) + { + strI2c.u16Sz = rsz; + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_R, &strI2c)) + { + //M2M_ERR("read error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + } + else + { + M2M_ERR("failed to send cfg bytes\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + + if (rsz == 1) { + *pu32RetVal = b[0]; + } else { + *pu32RetVal = b[0] | ((uint32)b[1] << 8) | ((uint32)b[2] << 16) | ((uint32)b[3] << 24); + } + return s8Ret; +} + +/* +* @fn nm_i2c_read_reg +* @brief Read register +* @param [in] u32Addr +* Register address +* @return Register value +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +uint32 nm_i2c_read_reg(uint32 u32Addr) +{ + uint32 val; + nm_i2c_read_reg_with_ret(u32Addr, &val); + return val; +} + +/* +* @fn nm_i2c_write_reg +* @brief write register +* @param [in] u32Addr +* Register address +* @param [in] u32Val +* Value to be written to the register +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +sint8 nm_i2c_write_reg(uint32 u32Addr, uint32 u32Val) +{ + tstrNmI2cDefault strI2c; + uint8 b[16]; + sint8 s8Ret = M2M_SUCCESS; + + if(u32Addr < 0xff) { /* clockless i2c */ + b[0] = 0x19; + b[1] = (uint8)(u32Addr); + b[2] = (uint8)(u32Val); + strI2c.u16Sz = 3; + } else { + b[0] = 0x90; + b[1] = (uint8)(u32Addr >> 24); + b[2] = (uint8)(u32Addr >> 16); + b[3] = (uint8)(u32Addr >> 8); + b[4] = (uint8)u32Addr; + b[5] = 0x04; + b[6] = (uint8)u32Val; + b[7] = (uint8)(u32Val >> 8); + b[8] = (uint8)(u32Val >> 16); + b[9] = (uint8)(u32Val >> 24); + strI2c.u16Sz = 10; + } + + strI2c.pu8Buf = b; + + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_W, &strI2c)) + { + M2M_ERR("write error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + + return s8Ret; +} + +/* +* @fn nm_i2c_read_block +* @brief Read block of data +* @param [in] u32Addr +* Start address +* @param [out] puBuf +* Pointer to a buffer used to return the read data +* @param [in] u16Sz +* Number of bytes to read. The buffer size must be >= u16Sz +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +sint8 nm_i2c_read_block(uint32 u32Addr, uint8 *pu8Buf, uint16 u16Sz) +{ + tstrNmI2cDefault strI2c; + uint8 au8Buf[7]; + sint8 s8Ret = M2M_SUCCESS; + + au8Buf[0] = 0x02; + au8Buf[1] = (uint8)(u32Addr >> 24); + au8Buf[2] = (uint8)(u32Addr >> 16); + au8Buf[3] = (uint8)(u32Addr >> 8); + au8Buf[4] = (uint8)(u32Addr >> 0); + au8Buf[5] = (uint8)(u16Sz >> 8); + au8Buf[6] = (uint8)(u16Sz); + + strI2c.pu8Buf = au8Buf; + strI2c.u16Sz = sizeof(au8Buf); + + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_W, &strI2c)) + { + M2M_ERR("write error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + else + { + strI2c.pu8Buf = pu8Buf; + strI2c.u16Sz = u16Sz; + + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_R, &strI2c)) + { + M2M_ERR("read error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + } + + return s8Ret; +} + +/* +* @fn nm_i2c_write_block +* @brief Write block of data +* @param [in] u32Addr +* Start address +* @param [in] puBuf +* Pointer to the buffer holding the data to be written +* @param [in] u16Sz +* Number of bytes to write. The buffer size must be >= u16Sz +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +sint8 nm_i2c_write_block(uint32 u32Addr, uint8 *pu8Buf, uint16 u16Sz) +{ + uint8 au8Buf[7]; + tstrNmI2cSpecial strI2c; + sint8 s8Ret = M2M_SUCCESS; + + au8Buf[0] = 0x12; + au8Buf[1] = (uint8)(u32Addr >> 24); + au8Buf[2] = (uint8)(u32Addr >> 16); + au8Buf[3] = (uint8)(u32Addr >> 8); + au8Buf[4] = (uint8)(u32Addr); + au8Buf[5] = (uint8)(u16Sz >> 8); + au8Buf[6] = (uint8)(u16Sz); + + strI2c.pu8Buf1 = au8Buf; + strI2c.pu8Buf2 = pu8Buf; + strI2c.u16Sz1 = sizeof(au8Buf); + strI2c.u16Sz2 = u16Sz; + + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_W_SPECIAL, &strI2c)) + { + M2M_ERR("write error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + + return s8Ret; +} + +#endif +/* EOF */ diff --git a/lib/WiFi101/src/driver/source/nmi2c.h b/lib/WiFi101/src/driver/source/nmi2c.h new file mode 100644 index 0000000..fea85e6 --- /dev/null +++ b/lib/WiFi101/src/driver/source/nmi2c.h @@ -0,0 +1,104 @@ +/** + * + * \file + * + * \brief This module contains NMC1000 I2C protocol bus APIs implementation. + * + * Copyright (c) 2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _NMI2C_H_ +#define _NMI2C_H_ + +#include "common/include/nm_common.h" + +/** +* @fn nm_i2c_read_reg +* @brief Read register +* @param [in] u32Addr +* Register address +* @return Register value +*/ +uint32 nm_i2c_read_reg(uint32 u32Addr); + +/** +* @fn nm_i2c_read_reg_with_ret +* @brief Read register with error code return +* @param [in] u32Addr +* Register address +* @param [out] pu32RetVal +* Pointer to u32 variable used to return the read value +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_i2c_read_reg_with_ret(uint32 u32Addr, uint32* pu32RetVal); + +/** +* @fn nm_i2c_write_reg +* @brief write register +* @param [in] u32Addr +* Register address +* @param [in] u32Val +* Value to be written to the register +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_i2c_write_reg(uint32 u32Addr, uint32 u32Val); + +/** +* @fn nm_i2c_read_block +* @brief Read block of data +* @param [in] u32Addr +* Start address +* @param [out] puBuf +* Pointer to a buffer used to return the read data +* @param [in] u16Sz +* Number of bytes to read. The buffer size must be >= u16Sz +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_i2c_read_block(uint32 u32Addr, uint8 *puBuf, uint16 u16Sz); + +/** +* @fn nm_i2c_write_block +* @brief Write block of data +* @param [in] u32Addr +* Start address +* @param [in] puBuf +* Pointer to the buffer holding the data to be written +* @param [in] u16Sz +* Number of bytes to write. The buffer size must be >= u16Sz +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_i2c_write_block(uint32 u32Addr, uint8 *puBuf, uint16 u16Sz); + +#endif /* _NMI2C_H_ */ diff --git a/lib/WiFi101/src/driver/source/nmspi.c b/lib/WiFi101/src/driver/source/nmspi.c new file mode 100644 index 0000000..9483ab7 --- /dev/null +++ b/lib/WiFi101/src/driver/source/nmspi.c @@ -0,0 +1,1401 @@ +/** + * + * \file + * + * \brief This module contains NMC1000 SPI protocol bus APIs implementation. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#include "common/include/nm_common.h" + +#ifdef CONF_WINC_USE_SPI + +#define USE_OLD_SPI_SW + +#include "bus_wrapper/include/nm_bus_wrapper.h" +#include "nmspi.h" + +#define NMI_PERIPH_REG_BASE 0x1000 +#define NMI_INTR_REG_BASE (NMI_PERIPH_REG_BASE+0xa00) +#define NMI_CHIPID (NMI_PERIPH_REG_BASE) +#define NMI_PIN_MUX_0 (NMI_PERIPH_REG_BASE + 0x408) +#define NMI_INTR_ENABLE (NMI_INTR_REG_BASE) + +#define NMI_SPI_REG_BASE 0xe800 +#define NMI_SPI_CTL (NMI_SPI_REG_BASE) +#define NMI_SPI_MASTER_DMA_ADDR (NMI_SPI_REG_BASE+0x4) +#define NMI_SPI_MASTER_DMA_COUNT (NMI_SPI_REG_BASE+0x8) +#define NMI_SPI_SLAVE_DMA_ADDR (NMI_SPI_REG_BASE+0xc) +#define NMI_SPI_SLAVE_DMA_COUNT (NMI_SPI_REG_BASE+0x10) +#define NMI_SPI_TX_MODE (NMI_SPI_REG_BASE+0x20) +#define NMI_SPI_PROTOCOL_CONFIG (NMI_SPI_REG_BASE+0x24) +#define NMI_SPI_INTR_CTL (NMI_SPI_REG_BASE+0x2c) +#define NMI_SPI_MISC_CTRL (NMI_SPI_REG_BASE+0x48) + +#define NMI_SPI_PROTOCOL_OFFSET (NMI_SPI_PROTOCOL_CONFIG-NMI_SPI_REG_BASE) + +#define SPI_BASE NMI_SPI_REG_BASE + +#define CMD_DMA_WRITE 0xc1 +#define CMD_DMA_READ 0xc2 +#define CMD_INTERNAL_WRITE 0xc3 +#define CMD_INTERNAL_READ 0xc4 +#define CMD_TERMINATE 0xc5 +#define CMD_REPEAT 0xc6 +#define CMD_DMA_EXT_WRITE 0xc7 +#define CMD_DMA_EXT_READ 0xc8 +#define CMD_SINGLE_WRITE 0xc9 +#define CMD_SINGLE_READ 0xca +#define CMD_RESET 0xcf + +#define N_OK 1 +#define N_FAIL 0 +#define N_RESET -1 +#define N_RETRY -2 + +#define SPI_RESP_RETRY_COUNT (10) +#define SPI_RETRY_COUNT (10) +#define DATA_PKT_SZ_256 256 +#define DATA_PKT_SZ_512 512 +#define DATA_PKT_SZ_1K 1024 +#define DATA_PKT_SZ_4K (4 * 1024) +#define DATA_PKT_SZ_8K (8 * 1024) +#define DATA_PKT_SZ DATA_PKT_SZ_8K + +static uint8 gu8Crc_off = 0; + +static sint8 nmi_spi_read(uint8* b, uint16 sz) +{ + tstrNmSpiRw spi; + spi.pu8InBuf = NULL; + spi.pu8OutBuf = b; + spi.u16Sz = sz; + return nm_bus_ioctl(NM_BUS_IOCTL_RW, &spi); +} + +static sint8 nmi_spi_write(uint8* b, uint16 sz) +{ + tstrNmSpiRw spi; + spi.pu8InBuf = b; + spi.pu8OutBuf = NULL; + spi.u16Sz = sz; + return nm_bus_ioctl(NM_BUS_IOCTL_RW, &spi); +} +#ifndef USE_OLD_SPI_SW +static sint8 nmi_spi_rw(uint8 *bin,uint8* bout,uint16 sz) +{ + tstrNmSpiRw spi; + spi.pu8InBuf = bin; + spi.pu8OutBuf = bout; + spi.u16Sz = sz; + return nm_bus_ioctl(NM_BUS_IOCTL_RW, &spi); +} +#endif +/******************************************** + + Crc7 + +********************************************/ +#if (defined ARDUINO_ARCH_AVR) +#include +static PROGMEM const uint8 crc7_syndrome_table[256] = { +#else +static const uint8 crc7_syndrome_table[256] = { +#endif + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, + 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, + 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26, + 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e, + 0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d, + 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45, + 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14, + 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c, + 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b, + 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13, + 0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42, + 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a, + 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69, + 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21, + 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70, + 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38, + 0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e, + 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36, + 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67, + 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f, + 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, + 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, + 0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55, + 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d, + 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a, + 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52, + 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03, + 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b, + 0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28, + 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60, + 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31, + 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79 +}; + + +static uint8 crc7_byte(uint8 crc, uint8 data) +{ +#if (defined ARDUINO_ARCH_AVR) + return pgm_read_byte_near(crc7_syndrome_table + ((crc << 1) ^ data)); +#else + return crc7_syndrome_table[(crc << 1) ^ data]; +#endif +} + +static uint8 crc7(uint8 crc, const uint8 *buffer, uint32 len) +{ + while (len--) + crc = crc7_byte(crc, *buffer++); + return crc; +} + +/******************************************** + + Spi protocol Function + +********************************************/ + +#define CMD_DMA_WRITE 0xc1 +#define CMD_DMA_READ 0xc2 +#define CMD_INTERNAL_WRITE 0xc3 +#define CMD_INTERNAL_READ 0xc4 +#define CMD_TERMINATE 0xc5 +#define CMD_REPEAT 0xc6 +#define CMD_DMA_EXT_WRITE 0xc7 +#define CMD_DMA_EXT_READ 0xc8 +#define CMD_SINGLE_WRITE 0xc9 +#define CMD_SINGLE_READ 0xca +#define CMD_RESET 0xcf + +#define DATA_PKT_SZ_256 256 +#define DATA_PKT_SZ_512 512 +#define DATA_PKT_SZ_1K 1024 +#define DATA_PKT_SZ_4K (4 * 1024) +#define DATA_PKT_SZ_8K (8 * 1024) +#define DATA_PKT_SZ DATA_PKT_SZ_8K + +static sint8 spi_cmd(uint8 cmd, uint32 adr, uint32 u32data, uint32 sz,uint8 clockless) +{ + uint8 bc[9]; + uint8 len = 5; + sint8 result = N_OK; + + bc[0] = cmd; + switch (cmd) { + case CMD_SINGLE_READ: /* single word (4 bytes) read */ + bc[1] = (uint8)(adr >> 16); + bc[2] = (uint8)(adr >> 8); + bc[3] = (uint8)adr; + len = 5; + break; + case CMD_INTERNAL_READ: /* internal register read */ + bc[1] = (uint8)(adr >> 8); + if(clockless) bc[1] |= (1 << 7); + bc[2] = (uint8)adr; + bc[3] = 0x00; + len = 5; + break; + case CMD_TERMINATE: /* termination */ + bc[1] = 0x00; + bc[2] = 0x00; + bc[3] = 0x00; + len = 5; + break; + case CMD_REPEAT: /* repeat */ + bc[1] = 0x00; + bc[2] = 0x00; + bc[3] = 0x00; + len = 5; + break; + case CMD_RESET: /* reset */ + bc[1] = 0xff; + bc[2] = 0xff; + bc[3] = 0xff; + len = 5; + break; + case CMD_DMA_WRITE: /* dma write */ + case CMD_DMA_READ: /* dma read */ + bc[1] = (uint8)(adr >> 16); + bc[2] = (uint8)(adr >> 8); + bc[3] = (uint8)adr; + bc[4] = (uint8)(sz >> 8); + bc[5] = (uint8)(sz); + len = 7; + break; + case CMD_DMA_EXT_WRITE: /* dma extended write */ + case CMD_DMA_EXT_READ: /* dma extended read */ + bc[1] = (uint8)(adr >> 16); + bc[2] = (uint8)(adr >> 8); + bc[3] = (uint8)adr; + bc[4] = (uint8)(sz >> 16); + bc[5] = (uint8)(sz >> 8); + bc[6] = (uint8)(sz); + len = 8; + break; + case CMD_INTERNAL_WRITE: /* internal register write */ + bc[1] = (uint8)(adr >> 8); + if(clockless) bc[1] |= (1 << 7); + bc[2] = (uint8)(adr); + bc[3] = (uint8)(u32data >> 24); + bc[4] = (uint8)(u32data >> 16); + bc[5] = (uint8)(u32data >> 8); + bc[6] = (uint8)(u32data); + len = 8; + break; + case CMD_SINGLE_WRITE: /* single word write */ + bc[1] = (uint8)(adr >> 16); + bc[2] = (uint8)(adr >> 8); + bc[3] = (uint8)(adr); + bc[4] = (uint8)(u32data >> 24); + bc[5] = (uint8)(u32data >> 16); + bc[6] = (uint8)(u32data >> 8); + bc[7] = (uint8)(u32data); + len = 9; + break; + default: + result = N_FAIL; + break; + } + + if (result) { + if (!gu8Crc_off) + bc[len-1] = (crc7(0x7f, (const uint8 *)&bc[0], len-1)) << 1; + else + len-=1; + + if (M2M_SUCCESS != nmi_spi_write(bc, len)) { + M2M_ERR("[nmi spi]: Failed cmd write, bus error...\n"); + result = N_FAIL; + } + } + + return result; +} + +static sint8 spi_data_rsp(uint8 cmd) +{ +#ifdef ARDUINO + (void)cmd; // Silence "unused" warning +#endif + uint8 len; + uint8 rsp[3]; + sint8 result = N_OK; + + if (!gu8Crc_off) + len = 2; + else + len = 3; + + if (M2M_SUCCESS != nmi_spi_read(&rsp[0], len)) { + M2M_ERR("[nmi spi]: Failed bus error...\n"); + result = N_FAIL; + goto _fail_; + } + + if((rsp[len-1] != 0)||(rsp[len-2] != 0xC3)) + { + M2M_ERR("[nmi spi]: Failed data response read, %x %x %x\n",rsp[0],rsp[1],rsp[2]); + result = N_FAIL; + goto _fail_; + } +_fail_: + + return result; +} + +static sint8 spi_cmd_rsp(uint8 cmd) +{ + uint8 rsp; + sint8 result = N_OK; + sint8 s8RetryCnt; + + /** + Command/Control response + **/ + if ((cmd == CMD_RESET) || + (cmd == CMD_TERMINATE) || + (cmd == CMD_REPEAT)) { + if (M2M_SUCCESS != nmi_spi_read(&rsp, 1)) { + result = N_FAIL; + goto _fail_; + } + } + + /* wait for response */ + s8RetryCnt = SPI_RESP_RETRY_COUNT; + do + { + if (M2M_SUCCESS != nmi_spi_read(&rsp, 1)) { + M2M_ERR("[nmi spi]: Failed cmd response read, bus error...\n"); + result = N_FAIL; + goto _fail_; + } + } while((rsp != cmd) && (s8RetryCnt-- >0)); + + /** + State response + **/ + /* wait for response */ + s8RetryCnt = SPI_RESP_RETRY_COUNT; + do + { + if (M2M_SUCCESS != nmi_spi_read(&rsp, 1)) { + M2M_ERR("[nmi spi]: Failed cmd response read, bus error...\n"); + result = N_FAIL; + goto _fail_; + } + } while((rsp != 0x00) && (s8RetryCnt-- >0)); + +_fail_: + + return result; +} +#ifndef USE_OLD_SPI_SW +static int spi_cmd_complete(uint8_t cmd, uint32_t adr, uint8_t *b, uint32_t sz, uint8_t clockless) +{ + uint8_t wb[32], rb[32]; + uint8_t wix, rix; + uint32_t len2; + uint8_t rsp; + int len = 0; + int result = N_OK; + + wb[0] = cmd; + switch (cmd) { + case CMD_SINGLE_READ: /* single word (4 bytes) read */ + wb[1] = (uint8_t)(adr >> 16); + wb[2] = (uint8_t)(adr >> 8); + wb[3] = (uint8_t)adr; + len = 5; + break; + case CMD_INTERNAL_READ: /* internal register read */ + wb[1] = (uint8_t)(adr >> 8); + if(clockless == 1) wb[1] |= (1 << 7); + wb[2] = (uint8_t)adr; + wb[3] = 0x00; + len = 5; + break; + case CMD_TERMINATE: /* termination */ + wb[1] = 0x00; + wb[2] = 0x00; + wb[3] = 0x00; + len = 5; + break; + case CMD_REPEAT: /* repeat */ + wb[1] = 0x00; + wb[2] = 0x00; + wb[3] = 0x00; + len = 5; + break; + case CMD_RESET: /* reset */ + wb[1] = 0xff; + wb[2] = 0xff; + wb[3] = 0xff; + len = 5; + break; + case CMD_DMA_WRITE: /* dma write */ + case CMD_DMA_READ: /* dma read */ + wb[1] = (uint8_t)(adr >> 16); + wb[2] = (uint8_t)(adr >> 8); + wb[3] = (uint8_t)adr; + wb[4] = (uint8_t)(sz >> 8); + wb[5] = (uint8_t)(sz); + len = 7; + break; + case CMD_DMA_EXT_WRITE: /* dma extended write */ + case CMD_DMA_EXT_READ: /* dma extended read */ + wb[1] = (uint8_t)(adr >> 16); + wb[2] = (uint8_t)(adr >> 8); + wb[3] = (uint8_t)adr; + wb[4] = (uint8_t)(sz >> 16); + wb[5] = (uint8_t)(sz >> 8); + wb[6] = (uint8_t)(sz); + len = 8; + break; + case CMD_INTERNAL_WRITE: /* internal register write */ + wb[1] = (uint8_t)(adr >> 8); + if(clockless == 1) wb[1] |= (1 << 7); + wb[2] = (uint8_t)(adr); + wb[3] = b[3]; + wb[4] = b[2]; + wb[5] = b[1]; + wb[6] = b[0]; + len = 8; + break; + case CMD_SINGLE_WRITE: /* single word write */ + wb[1] = (uint8_t)(adr >> 16); + wb[2] = (uint8_t)(adr >> 8); + wb[3] = (uint8_t)(adr); + wb[4] = b[3]; + wb[5] = b[2]; + wb[6] = b[1]; + wb[7] = b[0]; + len = 9; + break; + default: + result = N_FAIL; + break; + } + + if (result != N_OK) { + return result; + } + + if (!gu8Crc_off) { + wb[len-1] = (crc7(0x7f, (const uint8_t *)&wb[0], len-1)) << 1; + } else { + len -=1; + } + +#define NUM_SKIP_BYTES (1) +#define NUM_RSP_BYTES (2) +#define NUM_DATA_HDR_BYTES (1) +#define NUM_DATA_BYTES (4) +#define NUM_CRC_BYTES (2) +#define NUM_DUMMY_BYTES (3) + + if ((cmd == CMD_RESET) || + (cmd == CMD_TERMINATE) || + (cmd == CMD_REPEAT)) { + len2 = len + (NUM_SKIP_BYTES + NUM_RSP_BYTES + NUM_DUMMY_BYTES); + } else if ((cmd == CMD_INTERNAL_READ) || (cmd == CMD_SINGLE_READ)) { + if (!gu8Crc_off) { + len2 = len + (NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES + + NUM_CRC_BYTES + NUM_DUMMY_BYTES); + } else { + len2 = len + (NUM_RSP_BYTES + NUM_DATA_HDR_BYTES + NUM_DATA_BYTES + + NUM_DUMMY_BYTES); + } + } else { + len2 = len + (NUM_RSP_BYTES + NUM_DUMMY_BYTES); + } +#undef NUM_DUMMY_BYTES + + if(len2 > (sizeof(wb)/sizeof(wb[0]))) { + M2M_ERR("[nmi spi]: spi buffer size too small (%d) (%d)\n", + len2, (sizeof(wb)/sizeof(wb[0]))); + result = N_FAIL; + return result; + } + /* zero spi write buffers. */ + for(wix = len; wix< len2; wix++) { + wb[wix] = 0; + } + rix = len; + + if (nmi_spi_rw(wb, rb, len2) != M2M_SUCCESS) { + M2M_ERR("[nmi spi]: Failed cmd write, bus error...\n"); + result = N_FAIL; + return result; + } + +#if 0 + { + int jj; + printk("--- cnd = %x, len=%d, len2=%d\n", cmd, len, len2); + for(jj=0; jj= len2) break; + if(((jj+1)%16) != 0) { + if((jj%16) == 0) { + printk("wb[%02x]: %02x ", jj, wb[jj]); + } else { + printk("%02x ", wb[jj]); + } + } else { + printk("%02x\n", wb[jj]); + } + } + printk("\n"); + + for(jj=0; jj= len2) break; + if(((jj+1)%16) != 0) { + if((jj%16) == 0) { + printk("rb[%02x]: %02x ", jj, rb[jj]); + } else { + printk("%02x ", rb[jj]); + } + } else { + printk("%02x\n", rb[jj]); + } + } + printk("\n"); + } +#endif + + /** + Command/Control response + **/ + if ((cmd == CMD_RESET) || + (cmd == CMD_TERMINATE) || + (cmd == CMD_REPEAT)) { + rix++; /* skip 1 byte */ + } + + rsp = rb[rix++]; + + + if (rsp != cmd) { + M2M_ERR("[nmi spi]: Failed cmd response, cmd (%02x), resp (%02x)\n", cmd, rsp); + result = N_FAIL; + return result; + } + + /** + State response + **/ + rsp = rb[rix++]; + if (rsp != 0x00) { + M2M_ERR("[nmi spi]: Failed cmd state response state (%02x)\n", rsp); + result = N_FAIL; + return result; + } + + if ((cmd == CMD_INTERNAL_READ) || (cmd == CMD_SINGLE_READ) + || (cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) { + int retry; + //uint16_t crc1, crc2; + uint8_t crc[2]; + /** + Data Respnose header + **/ + retry = SPI_RESP_RETRY_COUNT; + do { + /* ensure there is room in buffer later to read data and crc */ + if(rix < len2) { + rsp = rb[rix++]; + } else { + retry = 0; + break; + } + if (((rsp >> 4) & 0xf) == 0xf) + break; + } while (retry--); + + if (retry <= 0) { + M2M_ERR("[nmi spi]: Error, data read response (%02x)\n", rsp); + result = N_RESET; + return result; + } + + if ((cmd == CMD_INTERNAL_READ) || (cmd == CMD_SINGLE_READ)) { + /** + Read bytes + **/ + if((rix+3) < len2) { + b[0] = rb[rix++]; + b[1] = rb[rix++]; + b[2] = rb[rix++]; + b[3] = rb[rix++]; + } else { + M2M_ERR("[nmi spi]: buffer overrun when reading data.\n"); + result = N_FAIL; + return result; + } + + if (!gu8Crc_off) { + /** + Read Crc + **/ + if((rix+1) < len2) { + crc[0] = rb[rix++]; + crc[1] = rb[rix++]; + } else { + M2M_ERR("[nmi spi]: buffer overrun when reading crc.\n"); + result = N_FAIL; + return result; + } + } + } else if((cmd == CMD_DMA_READ) || (cmd == CMD_DMA_EXT_READ)) { + int ix; + + /* some data may be read in response to dummy bytes. */ + for(ix=0; (rix < len2) && (ix < sz);) { + b[ix++] = rb[rix++]; + } +#if 0 + if(ix) M2M_INFO("ttt %d %d\n", sz, ix); +#endif + sz -= ix; + + if(sz > 0) { + int nbytes; + + if (sz <= (DATA_PKT_SZ-ix)) { + nbytes = sz; + } else { + nbytes = DATA_PKT_SZ-ix; + } + + /** + Read bytes + **/ + if (nmi_spi_read(&b[ix], nbytes) != M2M_SUCCESS) { + M2M_ERR("[nmi spi]: Failed data block read, bus error...\n"); + result = N_FAIL; + goto _error_; + } + + /** + Read Crc + **/ + if (!gu8Crc_off) { + if (nmi_spi_read(crc, 2) != M2M_SUCCESS) { + M2M_ERR("[nmi spi]: Failed data block crc read, bus error...\n"); + result = N_FAIL; + goto _error_; + } + } + + + ix += nbytes; + sz -= nbytes; + } + + /* if any data in left unread, then read the rest using normal DMA code.*/ + while(sz > 0) { + int nbytes; + + if (sz <= DATA_PKT_SZ) { + nbytes = sz; + } else { + nbytes = DATA_PKT_SZ; + } + + /** + read data response only on the next DMA cycles not + the first DMA since data response header is already + handled above for the first DMA. + **/ + /** + Data Respnose header + **/ + retry = SPI_RESP_RETRY_COUNT; + do { + if (nmi_spi_read(&rsp, 1) != M2M_SUCCESS) { + M2M_ERR("[nmi spi]: Failed data response read, bus error...\n"); + result = N_FAIL; + break; + } + if (((rsp >> 4) & 0xf) == 0xf) + break; + } while (retry--); + + if (result == N_FAIL) + break; + + + /** + Read bytes + **/ + if (nmi_spi_read(&b[ix], nbytes) != M2M_SUCCESS) { + M2M_ERR("[nmi spi]: Failed data block read, bus error...\n"); + result = N_FAIL; + break; + } + + /** + Read Crc + **/ + if (!gu8Crc_off) { + if (nmi_spi_read(crc, 2) != M2M_SUCCESS) { + M2M_ERR("[nmi spi]: Failed data block crc read, bus error...\n"); + result = N_FAIL; + break; + } + } + + ix += nbytes; + sz -= nbytes; + } + } + } +_error_: + return result; +} +#endif +static sint8 spi_data_read(uint8 *b, uint16 sz,uint8 clockless) +{ + sint16 retry, ix, nbytes; + sint8 result = N_OK; + uint8 crc[2]; + uint8 rsp; + + /** + Data + **/ + ix = 0; + do { + if (sz <= DATA_PKT_SZ) + nbytes = sz; + else + nbytes = DATA_PKT_SZ; + + /** + Data Respnose header + **/ + retry = SPI_RESP_RETRY_COUNT; + do { + if (M2M_SUCCESS != nmi_spi_read(&rsp, 1)) { + M2M_ERR("[nmi spi]: Failed data response read, bus error...\n"); + result = N_FAIL; + break; + } + if (((rsp >> 4) & 0xf) == 0xf) + break; + } while (retry--); + + if (result == N_FAIL) + break; + + if (retry <= 0) { + M2M_ERR("[nmi spi]: Failed data response read...(%02x)\n", rsp); + result = N_FAIL; + break; + } + + /** + Read bytes + **/ + if (M2M_SUCCESS != nmi_spi_read(&b[ix], nbytes)) { + M2M_ERR("[nmi spi]: Failed data block read, bus error...\n"); + result = N_FAIL; + break; + } + if(!clockless) + { + /** + Read Crc + **/ + if (!gu8Crc_off) { + if (M2M_SUCCESS != nmi_spi_read(crc, 2)) { + M2M_ERR("[nmi spi]: Failed data block crc read, bus error...\n"); + result = N_FAIL; + break; + } + } + } + ix += nbytes; + sz -= nbytes; + + } while (sz); + + return result; +} + +static sint8 spi_data_write(uint8 *b, uint16 sz) +{ + sint16 ix; + uint16 nbytes; + sint8 result = 1; + uint8 cmd, order, crc[2] = {0}; + //uint8 rsp; + + /** + Data + **/ + ix = 0; + do { + if (sz <= DATA_PKT_SZ) + nbytes = sz; + else + nbytes = DATA_PKT_SZ; + + /** + Write command + **/ + cmd = 0xf0; + if (ix == 0) { + if (sz <= DATA_PKT_SZ) + order = 0x3; + else + order = 0x1; + } else { + if (sz <= DATA_PKT_SZ) + order = 0x3; + else + order = 0x2; + } + cmd |= order; + if (M2M_SUCCESS != nmi_spi_write(&cmd, 1)) { + M2M_ERR("[nmi spi]: Failed data block cmd write, bus error...\n"); + result = N_FAIL; + break; + } + + /** + Write data + **/ + if (M2M_SUCCESS != nmi_spi_write(&b[ix], nbytes)) { + M2M_ERR("[nmi spi]: Failed data block write, bus error...\n"); + result = N_FAIL; + break; + } + + /** + Write Crc + **/ + if (!gu8Crc_off) { + if (M2M_SUCCESS != nmi_spi_write(crc, 2)) { + M2M_ERR("[nmi spi]: Failed data block crc write, bus error...\n"); + result = N_FAIL; + break; + } + } + + ix += nbytes; + sz -= nbytes; + } while (sz); + + + return result; +} + +/******************************************** + + Spi Internal Read/Write Function + +********************************************/ + +/******************************************** + + Spi interfaces + +********************************************/ + +static sint8 spi_write_reg(uint32 addr, uint32 u32data) +{ + uint8 retry = SPI_RETRY_COUNT; + sint8 result = N_OK; + uint8 cmd = CMD_SINGLE_WRITE; + uint8 clockless = 0; + +_RETRY_: + if (addr <= 0x30) + { + /** + NMC1000 clockless registers. + **/ + cmd = CMD_INTERNAL_WRITE; + clockless = 1; + } + else + { + cmd = CMD_SINGLE_WRITE; + clockless = 0; + } + +#if defined USE_OLD_SPI_SW + result = spi_cmd(cmd, addr, u32data, 4, clockless); + if (result != N_OK) { + M2M_ERR("[nmi spi]: Failed cmd, write reg (%08x)...\n", (unsigned int)addr); + goto _FAIL_; + } + + result = spi_cmd_rsp(cmd); + if (result != N_OK) { + M2M_ERR("[nmi spi]: Failed cmd response, write reg (%08x)...\n", (unsigned int)addr); + goto _FAIL_; + } + +#else + + result = spi_cmd_complete(cmd, addr, (uint8*)&u32data, 4, clockless); + if (result != N_OK) { + M2M_ERR( "[nmi spi]: Failed cmd, write reg (%08x)...\n", addr); + goto _FAIL_; + } + +#endif +_FAIL_: + if(result != N_OK) + { + nm_bsp_sleep(1); + spi_cmd(CMD_RESET, 0, 0, 0, 0); + spi_cmd_rsp(CMD_RESET); + M2M_ERR("Reset and retry %d %lx %lx\n",retry,addr,u32data); + nm_bsp_sleep(1); + retry--; + if(retry) goto _RETRY_; + } + + return result; +} + +static sint8 nm_spi_write(uint32 addr, uint8 *buf, uint16 size) +{ + sint8 result; + uint8 retry = SPI_RETRY_COUNT; + uint8 cmd = CMD_DMA_EXT_WRITE; + + +_RETRY_: + /** + Command + **/ +#if defined USE_OLD_SPI_SW + //Workaround hardware problem with single byte transfers over SPI bus + if (size == 1) + size = 2; + + result = spi_cmd(cmd, addr, 0, size,0); + if (result != N_OK) { + M2M_ERR("[nmi spi]: Failed cmd, write block (%08x)...\n", (unsigned int)addr); + goto _FAIL_; + } + + result = spi_cmd_rsp(cmd); + if (result != N_OK) { + M2M_ERR("[nmi spi ]: Failed cmd response, write block (%08x)...\n", (unsigned int)addr); + goto _FAIL_; + } +#else + result = spi_cmd_complete(cmd, addr, NULL, size, 0); + if (result != N_OK) { + M2M_ERR( "[nmi spi]: Failed cmd, write block (%08x)...\n", addr); + goto _FAIL_; + } +#endif + + /** + Data + **/ + result = spi_data_write(buf, size); + if (result != N_OK) { + M2M_ERR("[nmi spi]: Failed block data write...\n"); + goto _FAIL_; + } + /** + Data RESP + **/ + result = spi_data_rsp(cmd); + if (result != N_OK) { + M2M_ERR("[nmi spi]: Failed block data write...\n"); + goto _FAIL_; + } + +_FAIL_: + if(result != N_OK) + { + nm_bsp_sleep(1); + spi_cmd(CMD_RESET, 0, 0, 0, 0); + spi_cmd_rsp(CMD_RESET); + M2M_ERR("Reset and retry %d %lx %d\n",retry,addr,size); + nm_bsp_sleep(1); + retry--; + if(retry) goto _RETRY_; + } + + + return result; +} + +static sint8 spi_read_reg(uint32 addr, uint32 *u32data) +{ + uint8 retry = SPI_RETRY_COUNT; + sint8 result = N_OK; + uint8 cmd = CMD_SINGLE_READ; + uint8 tmp[4]; + uint8 clockless = 0; + +_RETRY_: + + if (addr <= 0xff) + { + /** + NMC1000 clockless registers. + **/ + cmd = CMD_INTERNAL_READ; + clockless = 1; + } + else + { + cmd = CMD_SINGLE_READ; + clockless = 0; + } + +#if defined USE_OLD_SPI_SW + result = spi_cmd(cmd, addr, 0, 4, clockless); + if (result != N_OK) { + M2M_ERR("[nmi spi]: Failed cmd, read reg (%08x)...\n", (unsigned int)addr); + goto _FAIL_; + } + + result = spi_cmd_rsp(cmd); + if (result != N_OK) { + M2M_ERR("[nmi spi]: Failed cmd response, read reg (%08x)...\n", (unsigned int)addr); + goto _FAIL_; + } + + /* to avoid endianess issues */ + result = spi_data_read(&tmp[0], 4, clockless); + if (result != N_OK) { + M2M_ERR("[nmi spi]: Failed data read...\n"); + goto _FAIL_; + } +#else + result = spi_cmd_complete(cmd, addr, (uint8*)&tmp[0], 4, clockless); + if (result != N_OK) { + M2M_ERR( "[nmi spi]: Failed cmd, read reg (%08x)...\n", addr); + goto _FAIL_; + } + +#endif + + *u32data = tmp[0] | + ((uint32)tmp[1] << 8) | + ((uint32)tmp[2] << 16) | + ((uint32)tmp[3] << 24); + +_FAIL_: + if(result != N_OK) + { + + nm_bsp_sleep(1); + spi_cmd(CMD_RESET, 0, 0, 0, 0); + spi_cmd_rsp(CMD_RESET); + M2M_ERR("Reset and retry %d %lx\n",retry,addr); + nm_bsp_sleep(1); + retry--; + if(retry) goto _RETRY_; + } + + return result; +} + +static sint8 nm_spi_read(uint32 addr, uint8 *buf, uint16 size) +{ + uint8 cmd = CMD_DMA_EXT_READ; + sint8 result; + uint8 retry = SPI_RETRY_COUNT; +#if defined USE_OLD_SPI_SW + uint8 tmp[2]; + uint8 single_byte_workaround = 0; +#endif + +_RETRY_: + + /** + Command + **/ +#if defined USE_OLD_SPI_SW + if (size == 1) + { + //Workaround hardware problem with single byte transfers over SPI bus + size = 2; + single_byte_workaround = 1; + } + result = spi_cmd(cmd, addr, 0, size,0); + if (result != N_OK) { + M2M_ERR("[nmi spi]: Failed cmd, read block (%08x)...\n", (unsigned int)addr); + goto _FAIL_; + } + + result = spi_cmd_rsp(cmd); + if (result != N_OK) { + M2M_ERR("[nmi spi]: Failed cmd response, read block (%08x)...\n", (unsigned int)addr); + goto _FAIL_; + } + + /** + Data + **/ + if (single_byte_workaround) + { + result = spi_data_read(tmp, size,0); + buf[0] = tmp[0]; + } + else + result = spi_data_read(buf, size,0); + + if (result != N_OK) { + M2M_ERR("[nmi spi]: Failed block data read...\n"); + goto _FAIL_; + } +#else + result = spi_cmd_complete(cmd, addr, buf, size, 0); + if (result != N_OK) { + M2M_ERR("[nmi spi]: Failed cmd, read block (%08x)...\n", addr); + goto _FAIL_; + } +#endif + +_FAIL_: + if(result != N_OK) + { + nm_bsp_sleep(1); + spi_cmd(CMD_RESET, 0, 0, 0, 0); + spi_cmd_rsp(CMD_RESET); + M2M_ERR("Reset and retry %d %lx %d\n",retry,addr,size); + nm_bsp_sleep(1); + retry--; + if(retry) goto _RETRY_; + } + + return result; +} + +/******************************************** + + Bus interfaces + +********************************************/ + +static void spi_init_pkt_sz(void) +{ + uint32 val32; + + /* Make sure SPI max. packet size fits the defined DATA_PKT_SZ. */ + val32 = nm_spi_read_reg(SPI_BASE+0x24); + val32 &= ~(0x7 << 4); + switch(DATA_PKT_SZ) + { + case 256: val32 |= (0 << 4); break; + case 512: val32 |= (1 << 4); break; + case 1024: val32 |= (2 << 4); break; + case 2048: val32 |= (3 << 4); break; + case 4096: val32 |= (4 << 4); break; + case 8192: val32 |= (5 << 4); break; + + } + nm_spi_write_reg(SPI_BASE+0x24, val32); +} + +sint8 nm_spi_reset(void) +{ + spi_cmd(CMD_RESET, 0, 0, 0, 0); + spi_cmd_rsp(CMD_RESET); + return M2M_SUCCESS; +} + +/* +* @fn nm_spi_init +* @brief Initialize the SPI +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +sint8 nm_spi_init(void) +{ + uint32 chipid; + uint32 reg = 0; + + + /** + configure protocol + **/ + gu8Crc_off = 0; + + // TODO: We can remove the CRC trials if there is a definite way to reset + // the SPI to it's initial value. + if (!spi_read_reg(NMI_SPI_PROTOCOL_CONFIG, ®)) { + /* Read failed. Try with CRC off. This might happen when module + is removed but chip isn't reset*/ + gu8Crc_off = 1; + M2M_ERR("[nmi spi]: Failed internal read protocol with CRC on, retyring with CRC off...\n"); + if (!spi_read_reg(NMI_SPI_PROTOCOL_CONFIG, ®)){ + // Reaad failed with both CRC on and off, something went bad + M2M_ERR( "[nmi spi]: Failed internal read protocol...\n"); + return 0; + } + } + if(gu8Crc_off == 0) + { + reg &= ~0xc; /* disable crc checking */ + reg &= ~0x70; + reg |= (0x5 << 4); + if (!spi_write_reg(NMI_SPI_PROTOCOL_CONFIG, reg)) { + M2M_ERR( "[nmi spi]: Failed internal write protocol reg...\n"); + return 0; + } + gu8Crc_off = 1; + } + + /** + make sure can read back chip id correctly + **/ + if (!spi_read_reg(0x1000, &chipid)) { + M2M_ERR("[nmi spi]: Fail cmd read chip id...\n"); + return M2M_ERR_BUS_FAIL; + } + + M2M_DBG("[nmi spi]: chipid (%08x)\n", (unsigned int)chipid); + spi_init_pkt_sz(); + + + return M2M_SUCCESS; +} + +/* +* @fn nm_spi_init +* @brief DeInitialize the SPI +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author Samer Sarhan +* @date 27 Feb 2015 +* @version 1.0 +*/ +sint8 nm_spi_deinit(void) +{ + gu8Crc_off = 0; + return M2M_SUCCESS; +} + +/* +* @fn nm_spi_read_reg +* @brief Read register +* @param [in] u32Addr +* Register address +* @return Register value +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +uint32 nm_spi_read_reg(uint32 u32Addr) +{ + uint32 u32Val; + + spi_read_reg(u32Addr, &u32Val); + + return u32Val; +} + +/* +* @fn nm_spi_read_reg_with_ret +* @brief Read register with error code return +* @param [in] u32Addr +* Register address +* @param [out] pu32RetVal +* Pointer to u32 variable used to return the read value +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +sint8 nm_spi_read_reg_with_ret(uint32 u32Addr, uint32* pu32RetVal) +{ + sint8 s8Ret; + + s8Ret = spi_read_reg(u32Addr,pu32RetVal); + + if(N_OK == s8Ret) s8Ret = M2M_SUCCESS; + else s8Ret = M2M_ERR_BUS_FAIL; + + return s8Ret; +} + +/* +* @fn nm_spi_write_reg +* @brief write register +* @param [in] u32Addr +* Register address +* @param [in] u32Val +* Value to be written to the register +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +sint8 nm_spi_write_reg(uint32 u32Addr, uint32 u32Val) +{ + sint8 s8Ret; + + s8Ret = spi_write_reg(u32Addr, u32Val); + + if(N_OK == s8Ret) s8Ret = M2M_SUCCESS; + else s8Ret = M2M_ERR_BUS_FAIL; + + return s8Ret; +} + +/* +* @fn nm_spi_read_block +* @brief Read block of data +* @param [in] u32Addr +* Start address +* @param [out] puBuf +* Pointer to a buffer used to return the read data +* @param [in] u16Sz +* Number of bytes to read. The buffer size must be >= u16Sz +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +sint8 nm_spi_read_block(uint32 u32Addr, uint8 *puBuf, uint16 u16Sz) +{ + sint8 s8Ret; + + s8Ret = nm_spi_read(u32Addr, puBuf, u16Sz); + + if(N_OK == s8Ret) s8Ret = M2M_SUCCESS; + else s8Ret = M2M_ERR_BUS_FAIL; + + return s8Ret; +} + +/* +* @fn nm_spi_write_block +* @brief Write block of data +* @param [in] u32Addr +* Start address +* @param [in] puBuf +* Pointer to the buffer holding the data to be written +* @param [in] u16Sz +* Number of bytes to write. The buffer size must be >= u16Sz +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author M. Abdelmawla +* @date 11 July 2012 +* @version 1.0 +*/ +sint8 nm_spi_write_block(uint32 u32Addr, uint8 *puBuf, uint16 u16Sz) +{ + sint8 s8Ret; + + s8Ret = nm_spi_write(u32Addr, puBuf, u16Sz); + + if(N_OK == s8Ret) s8Ret = M2M_SUCCESS; + else s8Ret = M2M_ERR_BUS_FAIL; + + return s8Ret; +} + +#endif diff --git a/lib/WiFi101/src/driver/source/nmspi.h b/lib/WiFi101/src/driver/source/nmspi.h new file mode 100644 index 0000000..a1bd4a9 --- /dev/null +++ b/lib/WiFi101/src/driver/source/nmspi.h @@ -0,0 +1,132 @@ +/** + * + * \file + * + * \brief This module contains NMC1000 SPI protocol bus APIs implementation. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _NMSPI_H_ +#define _NMSPI_H_ + +#include "common/include/nm_common.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/** +* @fn nm_spi_init +* @brief Initialize the SPI +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_spi_init(void); +/** +* @fn nm_spi_reset +* @brief reset the SPI +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_spi_reset(void); + +/** +* @fn nm_spi_deinit +* @brief DeInitialize the SPI +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_spi_deinit(void); + +/** +* @fn nm_spi_read_reg +* @brief Read register +* @param [in] u32Addr +* Register address +* @return Register value +*/ +uint32 nm_spi_read_reg(uint32 u32Addr); + +/** +* @fn nm_spi_read_reg_with_ret +* @brief Read register with error code return +* @param [in] u32Addr +* Register address +* @param [out] pu32RetVal +* Pointer to u32 variable used to return the read value +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_spi_read_reg_with_ret(uint32 u32Addr, uint32* pu32RetVal); + +/** +* @fn nm_spi_write_reg +* @brief write register +* @param [in] u32Addr +* Register address +* @param [in] u32Val +* Value to be written to the register +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_spi_write_reg(uint32 u32Addr, uint32 u32Val); + +/** +* @fn nm_spi_read_block +* @brief Read block of data +* @param [in] u32Addr +* Start address +* @param [out] puBuf +* Pointer to a buffer used to return the read data +* @param [in] u16Sz +* Number of bytes to read. The buffer size must be >= u16Sz +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_spi_read_block(uint32 u32Addr, uint8 *puBuf, uint16 u16Sz); + +/** +* @fn nm_spi_write_block +* @brief Write block of data +* @param [in] u32Addr +* Start address +* @param [in] puBuf +* Pointer to the buffer holding the data to be written +* @param [in] u16Sz +* Number of bytes to write. The buffer size must be >= u16Sz +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_spi_write_block(uint32 u32Addr, uint8 *puBuf, uint16 u16Sz); + +#ifdef __cplusplus + } +#endif + +#endif /* _NMSPI_H_ */ diff --git a/lib/WiFi101/src/driver/source/nmuart.c b/lib/WiFi101/src/driver/source/nmuart.c new file mode 100644 index 0000000..63541cf --- /dev/null +++ b/lib/WiFi101/src/driver/source/nmuart.c @@ -0,0 +1,536 @@ +/** + * + * \file + * + * \brief This module contains NMC1000 UART protocol bus APIs implementation. + * + * Copyright (c) 2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include "common/include/nm_common.h" + +#ifdef CONF_WINC_USE_UART + +#include "driver/source/nmuart.h" +#include "bus_wrapper/include/nm_bus_wrapper.h" + +#define HDR_SZ 12 + +static uint8 get_cs(uint8* b, uint8 sz){ + int i; + uint8 cs = 0; + for(i = 0; i < sz; i++) + cs ^= b[i]; + return cs; +} + +/* +* @fn nm_uart_sync_cmd +* @brief Check COM Port +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author Dina El Sissy +* @date 13 AUG 2012 +* @version 1.0 +*/ +sint8 nm_uart_sync_cmd(void) +{ + tstrNmUartDefault strUart; + sint8 s8Ret = -1; + uint8 b [HDR_SZ+1]; + uint8 rsz; + uint8 onchip = 0; + + /*read reg*/ + b[0] = 0x12; + + rsz = 1; + strUart.pu8Buf = b; + strUart.u16Sz = 1; + + if(M2M_SUCCESS == nm_bus_ioctl(NM_BUS_IOCTL_W, &strUart)) + { + strUart.u16Sz = rsz; + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_R, &strUart)) + { + s8Ret = M2M_ERR_BUS_FAIL; + } + } + else + { + M2M_ERR("failed to send cfg bytes\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + if (b[0] == 0x5a) + { + s8Ret = 0; + onchip = 1; + M2M_INFO("Built-in WINC1500 UART Found\n"); + } + else if(b[0] == 0x5b) + { + s8Ret = 0; + onchip = 0; + M2M_INFO("WINC1500 Serial Bridge Found\n"); + } + /*TODO: this should be the way we read the register since the cortus is little endian*/ + /**pu32RetVal = b[0] | ((uint32)b[1] << 8) | ((uint32)b[2] << 16) | ((uint32)b[3] << 24);*/ + if(s8Ret == M2M_SUCCESS) + s8Ret = (sint8)onchip; + return s8Ret; +} + sint8 nm_uart_read_reg_with_ret(uint32 u32Addr, uint32* pu32RetVal) +{ + tstrNmUartDefault strUart; + sint8 s8Ret = M2M_SUCCESS; + uint8 b [HDR_SZ+1]; + uint8 rsz; + + /*read reg*/ + b[0] = 0xa5; + b[1] = 0; + b[2] = 0; + b[3] = 0; + b[4] = 0; + b[5] = (uint8)(u32Addr & 0x000000ff); + b[6] = (uint8)((u32Addr & 0x0000ff00)>>8); + b[7] = (uint8)((u32Addr & 0x00ff0000)>>16); + b[8] = (uint8)((u32Addr & 0xff000000)>>24); + b[9] = 0; + b[10] = 0; + b[11] = 0; + b[12] = 0; + + b[2] = get_cs(&b[1],HDR_SZ); + + rsz = 4; + strUart.pu8Buf = b; + strUart.u16Sz = sizeof(b); + + if(M2M_SUCCESS == nm_bus_ioctl(NM_BUS_IOCTL_W, &strUart)) + { + if(!nm_bus_get_chip_type()) + { + strUart.u16Sz = 1; + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_R, &strUart)) + { + s8Ret = M2M_ERR_BUS_FAIL; + } + if(b[0] == 0xAC) + { + M2M_DBG("Successfully sent the command\n"); + strUart.u16Sz = rsz; + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_R, &strUart)) + { + s8Ret = M2M_ERR_BUS_FAIL; + } + } + else + { + s8Ret = M2M_ERR_BUS_FAIL; + } + } + else + { + strUart.u16Sz = rsz; + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_R, &strUart)) + { + s8Ret = M2M_ERR_BUS_FAIL; + } + } + } + else + { + M2M_ERR("failed to send cfg bytes\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + /*TODO: this should be the way we read the register since the cortus is little endian*/ + /**pu32RetVal = b[0] | ((uint32)b[1] << 8) | ((uint32)b[2] << 16) | ((uint32)b[3] << 24);*/ + + *pu32RetVal = ((uint32)b[0] << 24) | ((uint32)b[1] << 16) | ((uint32)b[2] << 8) | b[3]; + + return s8Ret; +} + +/* +* @fn nm_uart_read_reg +* @brief Read register +* @param [in] u32Addr +* Register address +* @return Register value +* @author Dina El Sissy +* @date 13 AUG 2012 +* @version 1.0 +*/ +uint32 nm_uart_read_reg(uint32 u32Addr) +{ + uint32 val; + nm_uart_read_reg_with_ret(u32Addr , &val); + return val; +} + +/* +* @fn nm_uart_write_reg +* @brief write register +* @param [in] u32Addr +* Register address +* @param [in] u32Val +* Value to be written to the register +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author Dina El Sissy +* @date 13 AUG 2012 +* @version 1.0 +*/ +sint8 nm_uart_write_reg(uint32 u32Addr, uint32 u32Val) +{ + tstrNmUartDefault strUart; + sint8 s8Ret = M2M_SUCCESS; + uint8 b[HDR_SZ+1]; + + /*write reg*/ + b[0] = 0xa5; + b[1] = 1; + b[2] = 0; + b[3] = 0; + b[4] = 0; + b[5] = (uint8)(u32Addr & 0x000000ff); + b[6] = (uint8)((u32Addr & 0x0000ff00)>>8); + b[7] = (uint8)((u32Addr & 0x00ff0000)>>16); + b[8] = (uint8)((u32Addr & 0xff000000)>>24); + b[9] = (uint8)(u32Val & 0x000000ff); + b[10] = (uint8)((u32Val & 0x0000ff00)>>8); + b[11] = (uint8)((u32Val & 0x00ff0000)>>16); + b[12] = (uint8)((u32Val & 0xff000000)>>24); + + b[2] = get_cs(&b[1],HDR_SZ); + + get_cs(&b[1],HDR_SZ); + + strUart.pu8Buf = b; + strUart.u16Sz = sizeof(b); + + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_W, &strUart)) + { + M2M_ERR("write error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + else + { + if(!nm_bus_get_chip_type()) + { + //check for the ack from the SAMD21 for the packet reception. + strUart.u16Sz = 1; + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_R, &strUart)) + { + s8Ret = M2M_ERR_BUS_FAIL; + } + if(b[0] == 0xAC) + { + M2M_DBG("Successfully sent the reg write command\n"); + } + else + { + M2M_ERR("write error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + } + } + + return s8Ret; +} + + +/** +* @fn nm_uart_read_block +* @brief Read block of data +* @param [in] u32Addr +* Start address +* @param [out] puBuf +* Pointer to a buffer used to return the read data +* @param [in] u16Sz +* Number of bytes to read. The buffer size must be >= u16Sz +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author Dina El Sissy +* @date 13 AUG 2012 +* @version 1.0 +*/ +sint8 nm_uart_read_block(uint32 u32Addr, uint8 *pu8Buf, uint16 u16Sz) +{ + tstrNmUartDefault strUart; + sint8 s8Ret = M2M_SUCCESS; + uint8 au8Buf[HDR_SZ+1]; + + au8Buf[0] = 0xa5; + au8Buf[1] = 2; + au8Buf[2] = 0; + au8Buf[3] = (uint8)(u16Sz & 0x00ff); + au8Buf[4] = (uint8)((u16Sz & 0xff00)>>8); + au8Buf[5] = (uint8)(u32Addr & 0x000000ff); + au8Buf[6] = (uint8)((u32Addr & 0x0000ff00)>>8); + au8Buf[7] = (uint8)((u32Addr & 0x00ff0000)>>16); + au8Buf[8] = (uint8)((u32Addr & 0xff000000)>>24); + au8Buf[9] = 0; + au8Buf[10] = 0; + au8Buf[11] = 0; + au8Buf[12] = 0; + + au8Buf[2] = get_cs(&au8Buf[1],HDR_SZ); + + strUart.pu8Buf = au8Buf; + strUart.u16Sz = sizeof(au8Buf); + + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_W, &strUart)) + { + M2M_ERR("write error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + else + { + if(!nm_bus_get_chip_type()) + { + //check for the ack from the SAMD21 for the packet reception. + strUart.u16Sz = 1; + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_R, &strUart)) + { + s8Ret = M2M_ERR_BUS_FAIL; + } + if(au8Buf[0] == 0xAC) + { + M2M_DBG("Successfully sent the block read command\n"); + strUart.pu8Buf = pu8Buf; + strUart.u16Sz = u16Sz; + + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_R, &strUart)) + { + M2M_ERR("read error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + } + else + { + M2M_ERR("write error (Error sending the block read command)\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + } + else + { + strUart.pu8Buf = pu8Buf; + strUart.u16Sz = u16Sz; + + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_R, &strUart)) + { + M2M_ERR("read error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + } + } + + return s8Ret; +} + +/** +* @fn nm_uart_write_block +* @brief Write block of data +* @param [in] u32Addr +* Start address +* @param [in] puBuf +* Pointer to the buffer holding the data to be written +* @param [in] u16Sz +* Number of bytes to write. The buffer size must be >= u16Sz +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author Dina El Sissy +* @date 13 AUG 2012 +* @version 1.0 +*/ +sint8 nm_uart_write_block(uint32 u32Addr, uint8 *puBuf, uint16 u16Sz) +{ + tstrNmUartDefault strUart; + sint8 s8Ret = M2M_SUCCESS; + static uint8 au8Buf[HDR_SZ+1]; + + au8Buf[0] = 0xa5; + au8Buf[1] = 3; + au8Buf[2] = 0; + au8Buf[3] = (uint8)(u16Sz & 0x00ff); + au8Buf[4] = (uint8)((u16Sz & 0xff00)>>8); + au8Buf[5] = (uint8)(u32Addr & 0x000000ff); + au8Buf[6] = (uint8)((u32Addr & 0x0000ff00)>>8); + au8Buf[7] = (uint8)((u32Addr & 0x00ff0000)>>16); + au8Buf[8] = (uint8)((u32Addr & 0xff000000)>>24); + au8Buf[9] = 0; + au8Buf[10] = 0; + au8Buf[11] = 0; + au8Buf[12] = 0; + + au8Buf[2] = get_cs(&au8Buf[1],HDR_SZ); + + strUart.pu8Buf = au8Buf; + strUart.u16Sz = sizeof(au8Buf); + + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_W, &strUart)) + { + M2M_ERR("write error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + else + { + if(!nm_bus_get_chip_type()) + { + //check for the ack from the SAMD21 for the packet reception. + strUart.u16Sz = 1; + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_R, &strUart)) + { + s8Ret = M2M_ERR_BUS_FAIL; + } + if(au8Buf[0] == 0xAC) + { + M2M_DBG("Successfully sent the block Write command\n"); + strUart.pu8Buf = puBuf; + strUart.u16Sz = u16Sz; + + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_W, &strUart)) + { + M2M_ERR("write error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + else + { + //check for the ack from the SAMD21 for the payload reception. + strUart.pu8Buf = au8Buf; + strUart.u16Sz = 1; + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_R, &strUart)) + { + s8Ret = M2M_ERR_BUS_FAIL; + } + if(au8Buf[0] == 0xAC) + { + M2M_DBG("Successfully sent the data payload\n"); + } + else + { + M2M_ERR("write error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + } + } + else + { + M2M_ERR("write error (Error sending the block write command)\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + } + else + { + strUart.pu8Buf = puBuf; + strUart.u16Sz = u16Sz; + + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_W, &strUart)) + { + M2M_ERR("write error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + } + } + return s8Ret; +} + +/** +* @fn nm_uart_reconfigure +* @brief Reconfigures the UART interface +* @param [in] ptr +* Pointer to a DWORD containing baudrate at this moment. +* @return M2M_SUCCESS in case of success and M2M_ERR_BUS_FAIL in case of failure +* @author Viswanathan Murugesan +* @date 22 OCT 2014 +* @version 1.0 +*/ +sint8 nm_uart_reconfigure(void *ptr) +{ + tstrNmUartDefault strUart; + sint8 s8Ret = M2M_SUCCESS; + uint8 b[HDR_SZ+1]; + + /*write reg*/ + b[0] = 0xa5; + b[1] = 5; + b[2] = 0; + b[3] = 0; + b[4] = 0; + b[5] = 0; + b[6] = 0; + b[7] = 0; + b[8] = 0; + b[9] = (uint8)((*(unsigned long *)ptr) & 0x000000ff); + b[10] = (uint8)(((*(unsigned long *)ptr) & 0x0000ff00)>>8); + b[11] = (uint8)(((*(unsigned long *)ptr) & 0x00ff0000)>>16); + b[12] = (uint8)(((*(unsigned long *)ptr) & 0xff000000)>>24); + + b[2] = get_cs(&b[1],HDR_SZ); + + get_cs(&b[1],HDR_SZ); + + strUart.pu8Buf = b; + strUart.u16Sz = sizeof(b); + + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_W, &strUart)) + { + M2M_ERR("write error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + else + { + if(!nm_bus_get_chip_type()) + { + //check for the ack from the SAMD21 for the packet reception. + strUart.u16Sz = 1; + if(M2M_SUCCESS != nm_bus_ioctl(NM_BUS_IOCTL_R, &strUart)) + { + s8Ret = M2M_ERR_BUS_FAIL; + } + if(b[0] == 0xAC) + { + M2M_DBG("Successfully sent the UART reconfigure command\n"); + } + else + { + M2M_ERR("write error\n"); + s8Ret = M2M_ERR_BUS_FAIL; + } + } + } + + return s8Ret; +} +#endif +/* EOF */ diff --git a/lib/WiFi101/src/driver/source/nmuart.h b/lib/WiFi101/src/driver/source/nmuart.h new file mode 100644 index 0000000..8f07d39 --- /dev/null +++ b/lib/WiFi101/src/driver/source/nmuart.h @@ -0,0 +1,118 @@ +/** + * + * \file + * + * \brief This module contains NMC1000 UART protocol bus APIs implementation. + * + * Copyright (c) 2016 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef _NMUART_H_ +#define _NMUART_H_ + +#include "common/include/nm_common.h" + +/* +* @fn nm_uart_sync_cmd +* @brief Check COM Port +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_uart_sync_cmd(void); +/** +* @fn nm_uart_read_reg +* @brief Read register +* @param [in] u32Addr +* Register address +* @return Register value +*/ +uint32 nm_uart_read_reg(uint32 u32Addr); + +/** +* @fn nm_uart_read_reg_with_ret +* @brief Read register with error code return +* @param [in] u32Addr +* Register address +* @param [out] pu32RetVal +* Pointer to u32 variable used to return the read value +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_uart_read_reg_with_ret(uint32 u32Addr, uint32* pu32RetVal); + +/** +* @fn nm_uart_write_reg +* @brief write register +* @param [in] u32Addr +* Register address +* @param [in] u32Val +* Value to be written to the register +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_uart_write_reg(uint32 u32Addr, uint32 u32Val); + +/** +* @fn nm_uart_read_block +* @brief Read block of data +* @param [in] u32Addr +* Start address +* @param [out] puBuf +* Pointer to a buffer used to return the read data +* @param [in] u16Sz +* Number of bytes to read. The buffer size must be >= u16Sz +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_uart_read_block(uint32 u32Addr, uint8 *puBuf, uint16 u16Sz); + +/** +* @fn nm_uart_write_block +* @brief Write block of data +* @param [in] u32Addr +* Start address +* @param [in] puBuf +* Pointer to the buffer holding the data to be written +* @param [in] u16Sz +* Number of bytes to write. The buffer size must be >= u16Sz +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_uart_write_block(uint32 u32Addr, uint8 *puBuf, uint16 u16Sz); + +/** +* @fn nm_uart_reconfigure +* @brief Reconfigures the UART interface +* @param [in] ptr +* Pointer to a DWORD containing baudrate at this moment. +* @return ZERO in case of success and M2M_ERR_BUS_FAIL in case of failure +*/ +sint8 nm_uart_reconfigure(void *ptr); +#endif /* _NMI2C_H_ */ diff --git a/lib/WiFi101/src/socket/include/m2m_socket_host_if.h b/lib/WiFi101/src/socket/include/m2m_socket_host_if.h new file mode 100644 index 0000000..933ad67 --- /dev/null +++ b/lib/WiFi101/src/socket/include/m2m_socket_host_if.h @@ -0,0 +1,461 @@ +/** + * + * \file + * + * \brief BSD compatible socket interface internal types. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef __M2M_SOCKET_HOST_IF_H__ +#define __M2M_SOCKET_HOST_IF_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +#ifndef _BOOT_ +#ifndef _FIRMWARE_ +#include "socket/include/socket.h" +#else +#include "m2m_types.h" +#endif +#endif + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +MACROS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +/* + * HOSTNAME_MAX_SIZE is defined here and also in host_drv/socket/include/socket.h + * The two definitions must match. +*/ +#ifdef _FIRMWARE_ +#define HOSTNAME_MAX_SIZE (64) +#endif + +#define SSL_MAX_OPT_LEN HOSTNAME_MAX_SIZE + + + +#define SOCKET_CMD_INVALID 0x00 +/*!< + Invlaid Socket command value. +*/ + + +#define SOCKET_CMD_BIND 0x41 +/*!< + Socket Binding command value. +*/ + + +#define SOCKET_CMD_LISTEN 0x42 +/*!< + Socket Listening command value. +*/ + + +#define SOCKET_CMD_ACCEPT 0x43 +/*!< + Socket Accepting command value. +*/ + + +#define SOCKET_CMD_CONNECT 0x44 +/*!< + Socket Connecting command value. +*/ + + +#define SOCKET_CMD_SEND 0x45 +/*!< + Socket send command value. +*/ + + +#define SOCKET_CMD_RECV 0x46 +/*!< + Socket Recieve command value. +*/ + + +#define SOCKET_CMD_SENDTO 0x47 +/*!< + Socket sendTo command value. +*/ + + +#define SOCKET_CMD_RECVFROM 0x48 +/*!< + Socket RecieveFrom command value. +*/ + + +#define SOCKET_CMD_CLOSE 0x49 +/*!< + Socket Close command value. +*/ + + +#define SOCKET_CMD_DNS_RESOLVE 0x4A +/*!< + Socket DNS Resolve command value. +*/ + + +#define SOCKET_CMD_SSL_CONNECT 0x4B +/*!< + SSL-Socket Connect command value. +*/ + + +#define SOCKET_CMD_SSL_SEND 0x4C +/*!< + SSL-Socket Send command value. +*/ + + +#define SOCKET_CMD_SSL_RECV 0x4D +/*!< + SSL-Socket Recieve command value. +*/ + + +#define SOCKET_CMD_SSL_CLOSE 0x4E +/*!< + SSL-Socket Close command value. +*/ + + +#define SOCKET_CMD_SET_SOCKET_OPTION 0x4F +/*!< + Set Socket Option command value. +*/ + + +#define SOCKET_CMD_SSL_CREATE 0x50 +/*!< +*/ + + +#define SOCKET_CMD_SSL_SET_SOCK_OPT 0x51 +/*!< +*/ + + +#define SOCKET_CMD_PING 0x52 +/*!< +*/ + + +#define SOCKET_CMD_SSL_SET_CS_LIST 0x53 +/*!< + Recommend instead using @ref M2M_SSL_REQ_SET_CS_LIST and + associated response @ref M2M_SSL_RESP_SET_CS_LIST +*/ + + +#define SOCKET_CMD_SSL_BIND 0x54 +/*!< +*/ + + +#define SOCKET_CMD_SSL_EXP_CHECK 0x55 +/*!< +*/ + + + +#define PING_ERR_SUCCESS 0 +#define PING_ERR_DEST_UNREACH 1 +#define PING_ERR_TIMEOUT 2 + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +DATA TYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + + +/*! +* @brief +*/ +typedef struct{ + uint16 u16Family; + uint16 u16Port; + uint32 u32IPAddr; +}tstrSockAddr; + + +typedef sint8 SOCKET; +typedef tstrSockAddr tstrUIPSockAddr; + + + +/*! +@struct \ + tstrDnsReply + +@brief + DNS Reply, contains hostName and HostIP. +*/ +typedef struct{ + char acHostName[HOSTNAME_MAX_SIZE]; + uint32 u32HostIP; +}tstrDnsReply; + + +/*! +@brief +*/ +typedef struct{ + tstrSockAddr strAddr; + SOCKET sock; + uint8 u8Void; + uint16 u16SessionID; +}tstrBindCmd; + + +/*! +@brief +*/ +typedef struct{ + SOCKET sock; + sint8 s8Status; + uint16 u16SessionID; +}tstrBindReply; + + +/*! +* @brief +*/ +typedef struct{ + SOCKET sock; + uint8 u8BackLog; + uint16 u16SessionID; +}tstrListenCmd; + + +/*! +@struct \ + tstrSocketRecvMsg + +@brief Socket recv status. + + It is passed to the APPSocketEventHandler with SOCKET_MSG_RECV or SOCKET_MSG_RECVFROM message type + in a response to a user call to the recv or recvfrom. + If the received data from the remote peer is larger than the USER Buffer size (given at recv call), the data is + delivered to the user in a number of consecutive chunks according to the USER Buffer size. +*/ +typedef struct{ + SOCKET sock; + sint8 s8Status; + uint16 u16SessionID; +}tstrListenReply; + + +/*! +* @brief +*/ +typedef struct{ + tstrSockAddr strAddr; + SOCKET sListenSock; + SOCKET sConnectedSock; + uint16 u16AppDataOffset; + /*!< + In further packet send requests the host interface should put the user application + data at this offset in the allocated shared data packet. + */ +}tstrAcceptReply; + + +/*! +* @brief +*/ +typedef struct{ + tstrSockAddr strAddr; + SOCKET sock; + uint8 u8SslFlags; + uint16 u16SessionID; +}tstrConnectCmd; + + +/*! +@struct \ + tstrConnectReply + +@brief + Connect Reply, contains sock number and error value +*/ +typedef struct{ + SOCKET sock; + sint8 s8Error; + uint16 u16AppDataOffset; + /*!< + In further packet send requests the host interface should put the user application + data at this offset in the allocated shared data packet. + */ +}tstrConnectReply; + + +/*! +@brief +*/ +typedef struct{ + SOCKET sock; + uint8 u8Void; + uint16 u16DataSize; + tstrSockAddr strAddr; + uint16 u16SessionID; + uint16 u16Void; +}tstrSendCmd; + + +/*! +@struct \ + tstrSendReply + +@brief + Send Reply, contains socket number and number of sent bytes. +*/ +typedef struct{ + SOCKET sock; + uint8 u8Void; + sint16 s16SentBytes; + uint16 u16SessionID; + uint16 u16Void; +}tstrSendReply; + + +/*! +* @brief +*/ +typedef struct{ + uint32 u32Timeoutmsec; + SOCKET sock; + uint8 u8Void; + uint16 u16SessionID; +}tstrRecvCmd; + + +/*! +@struct +@brief +*/ +typedef struct{ + tstrSockAddr strRemoteAddr; + sint16 s16RecvStatus; + uint16 u16DataOffset; + SOCKET sock; + uint8 u8Void; + uint16 u16SessionID; +}tstrRecvReply; + + +/*! +* @brief +*/ +typedef struct{ + uint32 u32OptionValue; + SOCKET sock; + uint8 u8Option; + uint16 u16SessionID; +}tstrSetSocketOptCmd; + + +typedef struct{ + SOCKET sslSock; + uint8 __PAD24__[3]; +}tstrSSLSocketCreateCmd; + + +/*! +* @brief +*/ +typedef struct{ + SOCKET sock; + uint8 u8Option; + uint16 u16SessionID; + uint32 u32OptLen; + uint8 au8OptVal[SSL_MAX_OPT_LEN]; +}tstrSSLSetSockOptCmd; + + +/*! +*/ +typedef struct{ + uint32 u32DestIPAddr; + uint32 u32CmdPrivate; + uint16 u16PingCount; + uint8 u8TTL; + uint8 __PAD8__; +}tstrPingCmd; + + +typedef struct{ + uint32 u32IPAddr; + uint32 u32CmdPrivate; + uint32 u32RTT; + uint16 u16Success; + uint16 u16Fail; + uint8 u8ErrorCode; + uint8 __PAD24__[3]; +}tstrPingReply; + + +/*! +@struct\ + tstrSslCertExpSettings + +@brief SSL Certificate Expiry Validation Settings + +@sa tenuSslCertExpSettings +*/ +typedef struct{ + uint32 u32CertExpValidationOpt; + /*!< + See @tenuSslCertExpSettings for possible values. + */ +}tstrSslCertExpSettings; + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __M2M_SOCKET_HOST_IF_H__ */ diff --git a/lib/WiFi101/src/socket/include/socket.h b/lib/WiFi101/src/socket/include/socket.h new file mode 100644 index 0000000..1c7b05b --- /dev/null +++ b/lib/WiFi101/src/socket/include/socket.h @@ -0,0 +1,2061 @@ +/** + * + * \file + * + * \brief WINC BSD compatible Socket Interface. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef __SOCKET_H__ +#define __SOCKET_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup SocketHeader Socket + * BSD compatible socket interface beftween the host layer and the network + * protocol stacks in the firmware. + * These functions are used by the host application to send or receive + * packets and to do other socket operations. + */ + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +#include "common/include/nm_common.h" +#include "driver/include/m2m_types.h" + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +MACROS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/** + * @defgroup SocketDefines Defines + * @ingroup SocketHeader + */ + +/** @defgroup IPDefines TCP/IP Defines + * @ingroup SocketDefines + * The following list of macros are used to define constants used throughout the socket layer. + * @{ + */ + +/* + * HOSTNAME_MAX_SIZE is defined here and also in host_drv/socket/include/m2m_socket_host_if.h + * The two definitions must match. +*/ +#define HOSTNAME_MAX_SIZE 64 +/*!< + Maximum allowed size for a host domain name passed to the function gethostbyname @ref gethostbyname. + command value. Used with the setsockopt function. + +*/ + +#define SOCKET_BUFFER_MAX_LENGTH 1400 +/*!< + Maximum allowed size for a socket data buffer. Used with @ref send socket + function to ensure that the buffer sent is within the allowed range. +*/ + +#define AF_INET 2 +/*!< + The AF_INET is the address family used for IPv4. An IPv4 transport address is specified with the @ref sockaddr_in structure. + (It is the only supported type for the current implementation.) +*/ + + +#define SOCK_STREAM 1 +/*!< + One of the IPv4 supported socket types for reliable connection-oriented stream connection. + Passed to the @ref socket function for the socket creation operation. +*/ + +#define SOCK_DGRAM 2 +/*!< + One of the IPv4 supported socket types for unreliable connectionless datagram connection. + Passed to the @ref socket function for the socket creation operation. +*/ + + +#define SOCKET_FLAGS_SSL 0x01 +/*!< + This flag shall be passed to the socket API for SSL session. +*/ + +#define TCP_SOCK_MAX (7) +/*!< + Maximum number of simultaneous TCP sockets. +*/ + +#define UDP_SOCK_MAX 4 +/*!< + Maximum number of simultaneous UDP sockets. +*/ + +#define MAX_SOCKET (TCP_SOCK_MAX + UDP_SOCK_MAX) +/*!< + Maximum number of Sockets. +*/ + +#define SOL_SOCKET 1 +/*!< + Socket option. + Used with the @ref setsockopt function +*/ + +#define SOL_SSL_SOCKET 2 +/*!< + SSL Socket option level. + Used with the @ref setsockopt function +*/ + +#define SO_SET_UDP_SEND_CALLBACK 0x00 +/*!< + Socket option used by the application to enable/disable + the use of UDP send callbacks. + Used with the @ref setsockopt function. +*/ + +#define IP_ADD_MEMBERSHIP 0x01 +/*!< + Set Socket Option Add Membership command value (to join a multicast group). + Used with the @ref setsockopt function. +*/ + + +#define IP_DROP_MEMBERSHIP 0x02 +/*!< + Set Socket Option Drop Membership command value (to leave a multicast group). + Used with the @ref setsockopt function. +*/ + //@} + + + +/** + * @defgroup TLSDefines TLS Defines + * @ingroup SocketDefines + */ + + + +/** @defgroup SSLSocketOptions TLS Socket Options + * @ingroup TLSDefines + * The following list of macros are used to define SSL Socket options. + * @{ + * @sa setsockopt + */ + +#define SO_SSL_BYPASS_X509_VERIF 0x01 +/*!< + Allow an opened SSL socket to bypass the X509 certificate + verification process. + It is highly required NOT to use this socket option in production + software applications. It is supported for debugging and testing + purposes. + The option value should be casted to int type and it is handled + as a boolean flag. +*/ + + +#define SO_SSL_SNI 0x02 +/*!< + Set the Server Name Indicator (SNI) for an SSL socket. The + SNI is a NULL terminated string containing the server name + associated with the connection. It must not exceed the size + of HOSTNAME_MAX_SIZE. +*/ + + +#define SO_SSL_ENABLE_SESSION_CACHING 0x03 +/*!< + This option allow the TLS to cache the session information for fast + TLS session establishment in future connections using the + TLS Protocol session resume features. +*/ + + +#define SO_SSL_ENABLE_SNI_VALIDATION 0x04 +/*!< + Enable SNI validation against the server's certificate subject + common name. If there is no SNI provided (via the SO_SSL_SNI + option), setting this option does nothing. +*/ + + +//@} + + + +/** @defgroup LegacySSLCipherSuite Legacy names for TLS Cipher Suite IDs + * @ingroup TLSDefines + * The following list of macros MUST NOT be used. Instead use the new names under SSLCipherSuiteID + * @sa sslSetActiveCipherSuites + * @{ + */ + +#define SSL_ENABLE_RSA_SHA_SUITES 0x01 +/*!< + Enable RSA Hmac_SHA based Cipher suites. For example, + TLS_RSA_WITH_AES_128_CBC_SHA +*/ + + +#define SSL_ENABLE_RSA_SHA256_SUITES 0x02 +/*!< + Enable RSA Hmac_SHA256 based Cipher suites. For example, + TLS_RSA_WITH_AES_128_CBC_SHA256 +*/ + + +#define SSL_ENABLE_DHE_SHA_SUITES 0x04 +/*!< + Enable DHE Hmac_SHA based Cipher suites. For example, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA +*/ + + +#define SSL_ENABLE_DHE_SHA256_SUITES 0x08 +/*!< + Enable DHE Hmac_SHA256 based Cipher suites. For example, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 +*/ + + +#define SSL_ENABLE_RSA_GCM_SUITES 0x10 +/*!< + Enable RSA AEAD based Cipher suites. For example, + TLS_RSA_WITH_AES_128_GCM_SHA256 +*/ + + +#define SSL_ENABLE_DHE_GCM_SUITES 0x20 +/*!< + Enable DHE AEAD based Cipher suites. For example, + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 +*/ + + +#define SSL_ENABLE_ALL_SUITES 0x0000003F +/*!< + Enable all possible supported cipher suites. +*/ + +//@} + + + +/** @defgroup SSLCipherSuiteID TLS Cipher Suite IDs + * @ingroup TLSDefines + * The following list of macros defined the list of supported TLS Cipher suites. + * Each MACRO defines a single Cipher suite. + * @sa m2m_ssl_set_active_ciphersuites + * @{ + */ + +#define SSL_CIPHER_RSA_WITH_AES_128_CBC_SHA NBIT0 +#define SSL_CIPHER_RSA_WITH_AES_128_CBC_SHA256 NBIT1 +#define SSL_CIPHER_DHE_RSA_WITH_AES_128_CBC_SHA NBIT2 +#define SSL_CIPHER_DHE_RSA_WITH_AES_128_CBC_SHA256 NBIT3 +#define SSL_CIPHER_RSA_WITH_AES_128_GCM_SHA256 NBIT4 +#define SSL_CIPHER_DHE_RSA_WITH_AES_128_GCM_SHA256 NBIT5 +#define SSL_CIPHER_RSA_WITH_AES_256_CBC_SHA NBIT6 +#define SSL_CIPHER_RSA_WITH_AES_256_CBC_SHA256 NBIT7 +#define SSL_CIPHER_DHE_RSA_WITH_AES_256_CBC_SHA NBIT8 +#define SSL_CIPHER_DHE_RSA_WITH_AES_256_CBC_SHA256 NBIT9 +#define SSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA NBIT10 +#define SSL_CIPHER_ECDHE_RSA_WITH_AES_256_CBC_SHA NBIT11 +#define SSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA256 NBIT12 +#define SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 NBIT13 +#define SSL_CIPHER_ECDHE_RSA_WITH_AES_128_GCM_SHA256 NBIT14 +#define SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 NBIT15 + + + +#define SSL_ECC_ONLY_CIPHERS \ +(\ + SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 | \ + SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 \ +) +/*!< + All ciphers that use ECC crypto only. This execuldes ciphers that use RSA. They use ECDSA instead. + These ciphers are turned off by default at startup. + The application may enable them if it has an ECC math engine (like ATECC508). +*/ +#define SSL_ECC_ALL_CIPHERS \ +(\ + SSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA | \ + SSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA256 | \ + SSL_CIPHER_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | \ + SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 | \ + SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 \ +) +/*!< + All supported ECC Ciphers including those ciphers that depend on RSA and ECC. + These ciphers are turned off by default at startup. + The application may enable them if it has an ECC math engine (like ATECC508). +*/ + +#define SSL_NON_ECC_CIPHERS_AES_128 \ +(\ + SSL_CIPHER_RSA_WITH_AES_128_CBC_SHA | \ + SSL_CIPHER_RSA_WITH_AES_128_CBC_SHA256 | \ + SSL_CIPHER_DHE_RSA_WITH_AES_128_CBC_SHA | \ + SSL_CIPHER_DHE_RSA_WITH_AES_128_CBC_SHA256 | \ + SSL_CIPHER_RSA_WITH_AES_128_GCM_SHA256 | \ + SSL_CIPHER_DHE_RSA_WITH_AES_128_GCM_SHA256 \ +) +/*!< + All supported AES-128 Ciphers (ECC ciphers are not counted). This is the default active group after startup. +*/ + + +#define SSL_ECC_CIPHERS_AES_256 \ +(\ + SSL_CIPHER_ECDHE_RSA_WITH_AES_256_CBC_SHA \ +) +/*!< + ECC AES-256 supported ciphers. +*/ + + +#define SSL_NON_ECC_CIPHERS_AES_256 \ +(\ + SSL_CIPHER_RSA_WITH_AES_256_CBC_SHA | \ + SSL_CIPHER_RSA_WITH_AES_256_CBC_SHA256 | \ + SSL_CIPHER_DHE_RSA_WITH_AES_256_CBC_SHA | \ + SSL_CIPHER_DHE_RSA_WITH_AES_256_CBC_SHA256 \ +) +/*!< + AES-256 Ciphers. + This group is disabled by default at startup because the WINC1500 HW Accelerator + supports only AES-128. If the application needs to force AES-256 cipher support, + it could enable them (or any of them) explicitly by calling sslSetActiveCipherSuites. +*/ + + +#define SSL_CIPHER_ALL \ +(\ + SSL_CIPHER_RSA_WITH_AES_128_CBC_SHA | \ + SSL_CIPHER_RSA_WITH_AES_128_CBC_SHA256 | \ + SSL_CIPHER_DHE_RSA_WITH_AES_128_CBC_SHA | \ + SSL_CIPHER_DHE_RSA_WITH_AES_128_CBC_SHA256 | \ + SSL_CIPHER_RSA_WITH_AES_128_GCM_SHA256 | \ + SSL_CIPHER_DHE_RSA_WITH_AES_128_GCM_SHA256 | \ + SSL_CIPHER_RSA_WITH_AES_256_CBC_SHA | \ + SSL_CIPHER_RSA_WITH_AES_256_CBC_SHA256 | \ + SSL_CIPHER_DHE_RSA_WITH_AES_256_CBC_SHA | \ + SSL_CIPHER_DHE_RSA_WITH_AES_256_CBC_SHA256 | \ + SSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA | \ + SSL_CIPHER_ECDHE_RSA_WITH_AES_128_CBC_SHA256 | \ + SSL_CIPHER_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | \ + SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 | \ + SSL_CIPHER_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 | \ + SSL_CIPHER_ECDHE_RSA_WITH_AES_256_CBC_SHA \ +) +/*!< + Turn On All TLS Ciphers. +*/ + + + //@} + + + + +/************** +Socket Errors +**************/ +/**@defgroup SocketErrorCode Error Codes + * @ingroup SocketHeader + * The following list of macros are used to define the possible error codes returned as a result of a call to a socket function. + * Errors are listed in numerical order with the error macro name. + * @{ + */ +#define SOCK_ERR_NO_ERROR 0 +/*!< + Successful socket operation +*/ + + +#define SOCK_ERR_INVALID_ADDRESS -1 +/*!< + Socket address is invalid. The socket operation cannot be completed successfully without specifying a specific address + For example: bind is called without specifying a port number +*/ + + +#define SOCK_ERR_ADDR_ALREADY_IN_USE -2 +/*!< + Socket operation cannot bind on the given address. With socket operations, only one IP address per socket is permitted. + Any attempt for a new socket to bind with an IP address already bound to another open socket, + will return the following error code. States that bind operation failed. +*/ + + +#define SOCK_ERR_MAX_TCP_SOCK -3 +/*!< + Exceeded the maximum number of TCP sockets. A maximum number of TCP sockets opened simultaneously is defined through TCP_SOCK_MAX. + It is not permitted to exceed that number at socket creation. Identifies that @ref socket operation failed. +*/ + + +#define SOCK_ERR_MAX_UDP_SOCK -4 +/*!< + Exceeded the maximum number of UDP sockets. A maximum number of UDP sockets opened simultaneously is defined through UDP_SOCK_MAX. + It is not permitted to exceed that number at socket creation. Identifies that @ref socket operation failed +*/ + + +#define SOCK_ERR_INVALID_ARG -6 +/*!< + An invalid argument is passed to a function. +*/ + + +#define SOCK_ERR_MAX_LISTEN_SOCK -7 +/*!< + Exceeded the maximum number of TCP passive listening sockets. + Identifies Identifies that @ref listen operation failed. +*/ + + +#define SOCK_ERR_INVALID -9 +/*!< + The requested socket operation is not valid in the + current socket state. + For example: @ref accept is called on a TCP socket before @ref bind or @ref listen. +*/ + + +#define SOCK_ERR_ADDR_IS_REQUIRED -11 +/*!< + Destination address is required. Failure to provide the socket address required for the socket operation to be completed. + It is generated as an error to the @ref sendto function when the address required to send the data to is not known. +*/ + + +#define SOCK_ERR_CONN_ABORTED -12 +/*!< + The socket is closed by the peer. The local socket is + closed also. +*/ + + +#define SOCK_ERR_TIMEOUT -13 +/*!< + The socket pending operation has Timedout. +*/ + + +#define SOCK_ERR_BUFFER_FULL -14 +/*!< + No buffer space available to be used for the requested socket operation. +*/ + +#ifdef _NM_BSP_BIG_END + +#define _htonl(m) (m) +#define _htons(A) (A) + +#else + +#define _htonl(m) \ + (uint32)(((uint32)(m << 24)) | ((uint32)((m & 0x0000FF00) << 8)) | ((uint32)((m & 0x00FF0000) >> 8)) | ((uint32)(m >> 24))) +/*!< + Convert a 4-byte integer from the host representation to the Network byte order representation. +*/ + + +#define _htons(A) (uint16)((((uint16) (A)) << 8) | (((uint16) (A)) >> 8)) +/*!< + Convert a 2-byte integer (short) from the host representation to the Network byte order representation. +*/ + + +#endif + + +#define _ntohl _htonl +/*!< + Convert a 4-byte integer from the Network byte order representation to the host representation . +*/ + + +#define _ntohs _htons +/*!< + Convert a 2-byte integer from the Network byte order representation to the host representation . +*/ + //@} + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +DATA TYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/** @defgroup SocketEnums DataTypes + * @ingroup SocketHeader + * Specific Enumeration-typedefs used for socket operations + * @{ */ + +/*! +@typedef \ + SOCKET + +@brief + Definition for socket handler data type. + Socket ID,used with all socket operations to uniquely identify the socket handler. + Such an ID is uniquely assigned at socket creation when calling @ref socket operation. +*/ +typedef sint8 SOCKET; + + + +/*! +@struct \ + in_addr + +@brief + IPv4 address representation. + + This structure is used as a placeholder for IPV4 address in other structures. +@see + sockaddr_in +*/ +typedef struct{ + uint32 s_addr; + /*!< + Network Byte Order representation of the IPv4 address. For example, + the address "192.168.0.10" is represented as 0x0A00A8C0. + */ +}in_addr; + + +/*! +@struct \ + sockaddr + +@brief + Generic socket address structure. + +@see + sockaddr_in +*/ +struct sockaddr{ + uint16 sa_family; + /*!< +Socket address family. + */ + uint8 sa_data[14]; + /*!< + Maximum size of all the different socket address structures. + */ +}; + + +/*! +@struct \ + sockaddr_in + +@brief + Socket address structure for IPV4 addresses. Used to specify socket address information to which to connect to. + Can be cast to @ref sockaddr structure. +*/ +struct sockaddr_in{ + uint16 sin_family; + /*!< + Specifies the address family(AF). + Members of AF_INET address family are IPv4 addresses. + Hence,the only supported value for this is AF_INET. + */ + uint16 sin_port; + /*!< + Port number of the socket. + Network sockets are identified by a pair of IP addresses and port number. + It must be set in the Network Byte Order format , @ref _htons (e.g. _htons(80)). + Can NOT have zero value. + */ + in_addr sin_addr; + /*!< + IP Address of the socket. + The IP address is of type @ref in_addr structure. + Can be set to "0" to accept any IP address for server operation. non zero otherwise. + */ + uint8 sin_zero[8]; + /*!< + Padding to make structure the same size as @ref sockaddr. + */ +}; + //@} +/**@defgroup AsyncCalback Asynchronous Events + * @ingroup SocketEnums + * Specific Enumeration used for asynchronous operations + * @{ */ +/*! +@enum \ + tenuSocketCallbackMsgType + +@brief + Asynchronous APIs, make use of callback functions, in-order to return back the results once the corresponding socket operation is completed. + Hence resuming the normal execution of the application code while the socket operation returns the results. + Callback functions expect event messages to be passed in, in-order to identify the operation they're returning the results for. + The following enum identifies the type of events that are received in the callback function. + + Application Use: + In order for application developers to handle the pending events from the network controller through the callback functions. + A function call must be made to the function @ref m2m_wifi_handle_events at least once for each socket operation. + +@see + bind + listen + accept + connect + send + recv + +*/ +typedef enum{ + SOCKET_MSG_BIND = 1, + /*!< + Bind socket event. + */ + SOCKET_MSG_LISTEN, + /*!< + Listen socket event. + */ + SOCKET_MSG_DNS_RESOLVE, + /*!< + DNS Resolution event. + */ + SOCKET_MSG_ACCEPT, + /*!< + Accept socket event. + */ + SOCKET_MSG_CONNECT, + /*!< + Connect socket event. + */ + SOCKET_MSG_RECV, + /*!< + Receive socket event. + */ + SOCKET_MSG_SEND, + /*!< + Send socket event. + */ + SOCKET_MSG_SENDTO, + /*!< + sendto socket event. + */ + SOCKET_MSG_RECVFROM + /*!< + Recvfrom socket event. + */ +}tenuSocketCallbackMsgType; + + +/*! +@struct \ + tstrSocketBindMsg + +@brief Socket bind status. + + An asynchronous call to the @ref bind socket operation, returns information through this structure in response. + This structure together with the event @ref SOCKET_MSG_BIND are passed in paramters to the callback function. +@see + bind + +*/ +typedef struct{ + sint8 status; + /*!< + The result of the bind operation. + Holding a value of ZERO for a successful bind or otherwise a negative + error code corresponding to the type of error. + */ +}tstrSocketBindMsg; + + +/*! +@struct \ + tstrSocketListenMsg + +@brief Socket listen status. + + Socket listen information is returned through this structure in response to the asynchronous call to the @ref listen function. + This structure together with the event @ref SOCKET_MSG_LISTEN are passed-in parameters to the callback function. +@see + listen +*/ +typedef struct{ + sint8 status; + /*!< + Holding a value of ZERO for a successful listen or otherwise a negative + error code corresponding to the type of error. + */ +}tstrSocketListenMsg; + + + +/*! +@struct \ + tstrSocketAcceptMsg + +@brief Socket accept status. + + Socket accept information is returned through this structure in response to the asynchronous call to the @ref accept function. + This structure together with the event @ref SOCKET_MSG_ACCEPT are passed-in parameters to the callback function. +*/ +typedef struct{ + SOCKET sock; + /*!< + On a successful @ref accept operation, the return information is the socket ID for the accepted connection with the remote peer. + Otherwise a negative error code is returned to indicate failure of the accept operation. + */ + struct sockaddr_in strAddr; + /*!< + Socket address structure for the remote peer. + */ +}tstrSocketAcceptMsg; + + +/*! +@struct \ + tstrSocketConnectMsg + +@brief Socket connect status. + + Socket connect information is returned through this structure in response to the asynchronous call to the @ref connect socket function. + This structure together with the event @ref SOCKET_MSG_CONNECT are passed-in parameters to the callback function. +*/ +typedef struct{ + SOCKET sock; + /*!< + Socket ID referring to the socket passed to the connect function call. + */ + sint8 s8Error; + /*!< + Connect error code. + Holding a value of ZERO for a successful connect or otherwise a negative + error code corresponding to the type of error. + */ +}tstrSocketConnectMsg; + + +/*! +@struct \ + tstrSocketRecvMsg + +@brief Socket recv status. + + Socket receive information is returned through this structure in response to the asynchronous call to the recv or recvfrom socket functions. + This structure together with the events @ref SOCKET_MSG_RECV or @ref SOCKET_MSG_RECVFROM are passed-in parameters to the callback function. +@remark + In case the received data from the remote peer is larger than the USER buffer size defined during the asynchronous call to the @ref recv function, the data is + delivered to the user in a number of consecutive chunks according to the USER Buffer size. + a negative or zero buffer size indicates an error with the following code: + @ref SOCK_ERR_NO_ERROR : Socket connection closed + @ref SOCK_ERR_CONN_ABORTED : Socket connection aborted + @SOCK_ERR_TIMEOUT : Socket receive timed out +*/ +typedef struct{ +#ifdef ARDUINO + uint32 pu8Buffer; +#else + uint8 *pu8Buffer; +#endif + /*!< + Pointer to the USER buffer (passed to @ref recv and @ref recvfrom function) containing the received data chunk. + */ + sint16 s16BufferSize; + /*!< + The received data chunk size. + Holds a negative value if there is a receive error or ZERO on success upon reception of close socket message. + */ + uint16 u16RemainingSize; + /*!< + The number of bytes remaining in the current @ref recv operation. + */ + struct sockaddr_in strRemoteAddr; + /*!< + Socket address structure for the remote peer. It is valid for @ref SOCKET_MSG_RECVFROM event. + */ +}tstrSocketRecvMsg; + + +/*! +@typedef \ + tpfAppSocketCb + +@brief + The main socket application callback function. Applications register their main socket application callback through this function by calling @ref registerSocketCallback. + In response to events received, the following callback function is called to handle the corresponding asynchronous function called. Example: @ref bind, @ref connect,...etc. + +@param [in] sock + Socket ID for the callback. + + The socket callback function is called whenever a new event is recived in response + to socket operations. + +@param [in] u8Msg + Socket event type. Possible values are: + - @ref SOCKET_MSG_BIND + - @ref SOCKET_MSG_LISTEN + - @ref SOCKET_MSG_ACCEPT + - @ref SOCKET_MSG_CONNECT + - @ref SOCKET_MSG_RECV + - @ref SOCKET_MSG_SEND + - @ref SOCKET_MSG_SENDTO + - @ref SOCKET_MSG_RECVFROM + +@param [in] pvMsg + Pointer to message structure. Existing types are: + - tstrSocketBindMsg + - tstrSocketListenMsg + - tstrSocketAcceptMsg + - tstrSocketConnectMsg + - tstrSocketRecvMsg + +@see + tenuSocketCallbackMsgType + tstrSocketRecvMsg + tstrSocketConnectMsg + tstrSocketAcceptMsg + tstrSocketListenMsg + tstrSocketBindMsg +*/ +typedef void (*tpfAppSocketCb) (SOCKET sock, uint8 u8Msg, void * pvMsg); + + +/*! +@typedef \ + tpfAppResolveCb + +@brief + DNS resolution callback function. + Applications requiring DNS resolution should register their callback through this function by calling @ref registerSocketCallback. + The following callback is triggered in response to asynchronous call to the @ref gethostbyname function (DNS Resolution callback). + +@param [in] pu8DomainName + Domain name of the host. + +@param [in] u32ServerIP + Server IPv4 address encoded in NW byte order format. If it is Zero, then the DNS resolution failed. +*/ +typedef void (*tpfAppResolveCb) (uint8* pu8DomainName, uint32 u32ServerIP); + +/*! +@typedef \ + tpfPingCb + +@brief PING Callback + + The function delivers the ping statistics for the sent ping triggered by calling + m2m_ping_req. + +@param [in] u32IPAddr + Destination IP. + +@param [in] u32RTT + Round Trip Time. + +@param [in] u8ErrorCode + Ping error code. It may be one of: + - PING_ERR_SUCCESS + - PING_ERR_DEST_UNREACH + - PING_ERR_TIMEOUT +*/ +typedef void (*tpfPingCb)(uint32 u32IPAddr, uint32 u32RTT, uint8 u8ErrorCode); + + /**@}*/ +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +FUNCTION PROTOTYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +/** \defgroup SocketAPI Function + * @ingroup SocketHeader + */ + +/** @defgroup SocketInitalizationFn socketInit + * @ingroup SocketAPI + * The function performs the necessary initializations for the socket library through the following steps: + - A check made by the global variable gbSocketInit, ensuring that initialization for sockets is performed only once, + in-order to prevent reseting the socket instances already created in the global socket array (gastrSockets). + - Zero initializations to the global socket array (gastrSockets), which holds the list of TCP sockets. + - Registers the socket (Host Interface)hif callback function through the call to the hif_register_cb function. + This facilitates handling all of the socket related functions received through interrupts from the firmware. + + */ + /**@{*/ +/*! +@fn \ + NMI_API void socketInit(void); + +@param [in] void + +@return void + +@remarks + This initialization function must be invoked before any socket operation is performed. + No error codes from this initialization function since the socket array is statically allocated based in the maximum number of + sockets @ref MAX_SOCKET based on the systems capability. +\section Example +This example demonstrates the use of the socketinit for socket initialization for an mqtt chat application. + \code + tstrWifiInitParam param; + int8_t ret; + char topic[strlen(MAIN_CHAT_TOPIC) + MAIN_CHAT_USER_NAME_SIZE + 1]; + + //Initialize the board. + system_init(); + + //Initialize the UART console. + configure_console(); + + // Initialize the BSP. + nm_bsp_init(); + + ---------- + + // Initialize socket interface. + socketInit(); + registerSocketCallback(socket_event_handler, socket_resolve_handler); + + // Connect to router. + m2m_wifi_connect((char *)MAIN_WLAN_SSID, sizeof(MAIN_WLAN_SSID), + MAIN_WLAN_AUTH, (char *)MAIN_WLAN_PSK, M2M_WIFI_CH_ALL); + +\endcode +*/ +NMI_API void socketInit(void); + + +/*! +@fn \ + NMI_API void socketDeinit(void); + +@brief Socket Layer De-initialization + + The function performs the necessary cleanup for the socket library static data + It must be invoked as the last any socket operation is performed on any active sockets. +*/ +NMI_API void socketDeinit(void); + + +/** @} */ +/** @defgroup SocketCallbackFn registerSocketCallback + * @ingroup SocketAPI + Register two callback functions one for asynchronous socket events and the other one for DNS callback registering function. + The registered callback functions are used to retrieve information in response to the asynchronous socket functions called. + */ + /**@{*/ + + +/*! +@fn \ + NMI_API void registerSocketCallback(tpfAppSocketCb socket_cb, tpfAppResolveCb resolve_cb); + +@param [in] tpfAppSocketCb + Assignment of callback function to the global callback @ref tpfAppSocketCb gpfAppSocketCb. Delivers + socket messages to the host application. In response to the asynchronous function calls, such as @ref bind + @ref listen @ref accept @ref connect + +@param [in] tpfAppResolveCb + Assignment of callback function to the global callback @ref tpfAppResolveCb gpfAppResolveCb. + Used for DNS resolving functionalities. The DNS resolving technique is determined by the application + registering the callback. + NULL is assigned when, DNS resolution is not required. + +@return void +@remarks + If any of the socket functionalities is not to be used, NULL is passed in as a parameter. + It must be invoked after socketinit and before other socket layer operations. + +\section Example + This example demonstrates the use of the registerSocketCallback to register a socket callback function with DNS resolution CB set to null + for a simple UDP server example. + \code + tstrWifiInitParam param; + int8_t ret; + struct sockaddr_in addr; + + // Initialize the board + system_init(); + + //Initialize the UART console. + configure_console(); + + // Initialize the BSP. + nm_bsp_init(); + + // Initialize socket address structure. + addr.sin_family = AF_INET; + addr.sin_port = _htons(MAIN_WIFI_M2M_SERVER_PORT); + addr.sin_addr.s_addr = _htonl(MAIN_WIFI_M2M_SERVER_IP); + + // Initialize Wi-Fi parameters structure. + memset((uint8_t *)¶m, 0, sizeof(tstrWifiInitParam)); + + // Initialize Wi-Fi driver with data and status callbacks. + param.pfAppWifiCb = wifi_cb; + ret = m2m_wifi_init(¶m); + if (M2M_SUCCESS != ret) { + printf("main: m2m_wifi_init call error!(%d)\r\n", ret); + while (1) { + } + } + + // Initialize socket module + socketInit(); + registerSocketCallback(socket_cb, NULL); + + // Connect to router. + m2m_wifi_connect((char *)MAIN_WLAN_SSID, sizeof(MAIN_WLAN_SSID), MAIN_WLAN_AUTH, (char *)MAIN_WLAN_PSK, M2M_WIFI_CH_ALL); + \endcode +*/ +NMI_API void registerSocketCallback(tpfAppSocketCb socket_cb, tpfAppResolveCb resolve_cb); + + +/** @} */ + +/** @defgroup SocketFn socket + * @ingroup SocketAPI + * Synchronous socket allocation function based on the specified socket type. Created sockets are non-blocking and their possible types are either TCP or a UDP sockets. + * The maximum allowed number of TCP sockets is @ref TCP_SOCK_MAX sockets while the maximum number of UDP sockets that can be created simultaneously is @ref UDP_SOCK_MAX sockets. + * +*/ + /**@{*/ +/*! +@fn \ + NMI_API SOCKET socket(uint16 u16Domain, uint8 u8Type, uint8 u8Flags); + + +@param [in] u16Domain + Socket family. The only allowed value is AF_INET (IPv4.0) for TCP/UDP sockets. + +@param [in] u8Type + Socket type. Allowed values are: + - [SOCK_STREAM](@ref SOCK_STREAM) + - [SOCK_DGRAM](@ref SOCK_DGRAM) + +@param [in] u8Flags + Used to specify the socket creation flags. It shall be set to zero for normal TCP/UDP sockets. + It could be @ref SOCKET_FLAGS_SSL if the socket is used for SSL session. The use of the flag + @ref SOCKET_FLAGS_SSL has no meaning in case of UDP sockets. + +@pre + The @ref socketInit function must be called once at the beginning of the application to initialize the socket handler. + before any call to the socket function can be made. + +@see + connect + bind + listen + accept + recv + recvfrom + send + sendto + close + setsockopt + getsockopt + +@return + On successful socket creation, a non-blocking socket type is created and a socket ID is returned + In case of failure the function returns a negative value, identifying one of the socket error codes defined. + For example: @ref SOCK_ERR_INVALID for invalid argument or + @ref SOCK_ERR_MAX_TCP_SOCK if the number of TCP allocated sockets exceeds the number of available sockets. + +@remarks + The socket function must be called a priori to any other related socket functions "e.g. send, recv, close ..etc" +\section Example + This example demonstrates the use of the socket function to allocate the socket, returning the socket handler to be used for other +socket operations. Socket creation is dependent on the socket type. +\subsection sub1 UDP example +@code + SOCKET UdpServerSocket = -1; + + UdpServerSocket = socket(AF_INET, SOCK_DGRAM, 0); + +@endcode +\subsection sub2 TCP example +@code + static SOCKET tcp_client_socket = -1; + + tcp_client_socket = socket(AF_INET, SOCK_STREAM, 0)); +@endcode +\subsection sub3 SSL example +@code +static SOCKET ssl_socket = -1; + +ssl_socket = socket(AF_INET, SOCK_STREAM, SOCK_FLAGS_SSL)); +@endcode +*/ +NMI_API SOCKET socket(uint16 u16Domain, uint8 u8Type, uint8 u8Flags); + + +/** @} */ +/** @defgroup BindFn bind + * @ingroup SocketAPI +* Asynchronous bind function associates the provided address and local port to the socket. +* The function can be used with both TCP and UDP sockets it's mandatory to call the @ref bind function before starting any UDP or TCP server operation. +* Upon socket bind completion, the application will receive a @ref SOCKET_MSG_BIND message in the socket callback. +*/ + /**@{*/ +/*! +\fn \ + NMI_API sint8 bind(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen); + + +@param [in] sock + Socket ID, must hold a non negative value. + A negative value will return a socket error @ref SOCK_ERR_INVALID_ARG. Indicating that an invalid argument is passed in. + +@param [in] pstrAddr + Pointer to socket address structure "sockaddr_in" + [sockaddr_in](@ref sockaddr_in) + + +@param [in] u8AddrLen + Size of the given socket address structure in bytes. + +@pre + The socket function must be called to allocate a socket before passing the socket ID to the bind function. + +@see + socket + connect + listen + accept + recv + recvfrom + send + sendto + +@return + The function returns ZERO for successful operations and a negative value otherwise. + The possible error values are: + - [SOCK_ERR_NO_ERROR](@ref SOCK_ERR_NO_ERROR) + Indicating that the operation was successful. + + - [SOCK_ERR_INVALID_ARG](@ref SOCK_ERR_INVALID_ARG) + Indicating passing invalid arguments such as negative socket ID or NULL socket address structure. + + - [SOCK_ERR_INVALID](@ref SOCK_ERR_INVALID) + Indicate socket bind failure. +\section Example + This example demonstrates the call of the bind socket operation after a successful socket operation. +@code + struct sockaddr_in addr; + SOCKET udpServerSocket =-1; + int ret = -1; + + if(udpServerSocket == -1) + { + udpServerSocket = socket(AF_INET, SOCK_DGRAM, 0); + if(udpServerSocket >= 0) + { + addr.sin_family = AF_INET; + addr.sin_port = _htons(1234); + addr.sin_addr.s_addr = 0; + ret = bind(udpServerSocket,(struct sockaddr*)&addr,sizeof(addr)); + + if(ret != 0) + { + printf("Bind Failed. Error code = %d\n",ret); + close(udpServerSocket); + } + } + else + { + printf("UDP Server Socket Creation Failed\n"); + return; + } + } +@endcode +*/ +NMI_API sint8 bind(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen); +/** @} */ + +/** @defgroup ListenFn listen + * @ingroup SocketAPI + * After successful socket binding to an IP address and port on the system, start listening on a passive socket for incoming connections. + The socket must be bound on a local port or the listen operation fails. + Upon the call to the asynchronous listen function, response is received through the event [SOCKET_MSG_BIND](@ref SOCKET_MSG_BIND) + in the socket callback. + A successful listen means the TCP server operation is active. If a connection is accepted, then the application socket callback function is + notified with the new connected socket through the event @ref SOCKET_MSG_ACCEPT. Hence there is no need to call the @ref accept function + after calling @ref listen. + + After a connection is accepted, the user is then required to call the @ref recv to receive any packets transmitted by the remote host or to receive notification of socket connection + termination. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 listen(SOCKET sock, uint8 backlog); + +@param [in] sock + Socket ID, must hold a non negative value. + A negative value will return a socket error @ref SOCK_ERR_INVALID_ARG. Indicating that an invalid argument is passed in. + +@param [in] backlog + Not used by the current implementation. + +@pre + The bind function must be called to assign the port number and IP address to the socket before the listen operation. + +@see + bind + accept + recv + recvfrom + send + sendto + +@return + The function returns ZERO for successful operations and a negative value otherwise. + The possible error values are: + - [SOCK_ERR_NO_ERROR](@ref SOCK_ERR_NO_ERROR) + Indicating that the operation was successful. + + - [SOCK_ERR_INVALID_ARG](@ref SOCK_ERR_INVALID_ARG) + Indicating passing invalid arguments such as negative socket ID. + + - [SOCK_ERR_INVALID](@ref SOCK_ERR_INVALID) + Indicate socket listen failure. +\section Example +This example demonstrates the call of the listen socket operation after a successful socket operation. +@code + static void TCP_Socketcallback(SOCKET sock, uint8 u8Msg, void * pvMsg) + { + int ret =-1; + + switch(u8Msg) + { + case SOCKET_MSG_BIND: + { + tstrSocketBindMsg *pstrBind = (tstrSocketBindMsg*)pvMsg; + if(pstrBind != NULL) + { + if(pstrBind->status == 0) + { + ret = listen(sock, 0); + + if(ret <0) + printf("Listen failure! Error = %d\n",ret); + } + else + { + M2M_ERR("bind Failure!\n"); + close(sock); + } + } + } + break; + + case SOCKET_MSG_LISTEN: + { + + tstrSocketListenMsg *pstrListen = (tstrSocketListenMsg*)pvMsg; + if(pstrListen != NULL) + { + if(pstrListen->status == 0) + { + ret = accept(sock,NULL,0); + } + else + { + M2M_ERR("listen Failure!\n"); + close(sock); + } + } + } + break; + + case SOCKET_MSG_ACCEPT: + { + tstrSocketAcceptMsg *pstrAccept = (tstrSocketAcceptMsg*)pvMsg; + + if(pstrAccept->sock >= 0) + { + TcpNotificationSocket = pstrAccept->sock; + recv(pstrAccept->sock,gau8RxBuffer,sizeof(gau8RxBuffer),TEST_RECV_TIMEOUT); + } + else + { + M2M_ERR("accept failure\n"); + } + } + break; + + default: + break; + } + } + +@endcode +*/ +NMI_API sint8 listen(SOCKET sock, uint8 backlog); +/** @} */ +/** @defgroup AcceptFn accept + * @ingroup SocketAPI + * The function has no current implementation. An empty deceleration is used to prevent errors when legacy application code is used. + * For recent application use, the accept function can be safer as it has no effect and could be safely removed from any application using it. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 accept(SOCKET sock, struct sockaddr *addr, uint8 *addrlen); + +@param [in] sock + Socket ID, must hold a non negative value. + A negative value will return a socket error @ref SOCK_ERR_INVALID_ARG. Indicating that an invalid argument is passed in. +@param [in] addr + Not used in the current implementation. + +@param [in] addrlen + Not used in the current implementation. + +@return + The function returns ZERO for successful operations and a negative value otherwise. + The possible error values are: + - [SOCK_ERR_NO_ERROR](@ref SOCK_ERR_NO_ERROR) + Indicating that the operation was successful. + + - [SOCK_ERR_INVALID_ARG](@ref SOCK_ERR_INVALID_ARG) + Indicating passing invalid arguments such as negative socket ID. +*/ +NMI_API sint8 accept(SOCKET sock, struct sockaddr *addr, uint8 *addrlen); +/** @} */ +/** @defgroup ConnectFn connect + * @ingroup SocketAPI + * Establishes a TCP connection with a remote server. + The asynchronous connect function must be called after receiving a valid socket ID from the @ref socket function. + The application socket callback function is notified of a successful new socket connection through the event @ref SOCKET_MSG_CONNECT. + A successful connect means the TCP session is active. The application is then required to make a call to the @ref recv + to receive any packets transmitted by the remote server, unless the application is interrupted by a notification of socket connection + termination. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 connect(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen); + +@param [in] sock + Socket ID, must hold a non negative value. + A negative value will return a socket error @ref SOCK_ERR_INVALID_ARG. Indicating that an invalid argument is passed in. + +@param [in] pstrAddr + Address of the remote server. +@param [in] pstrAddr + Pointer to socket address structure "sockaddr_in" + [sockaddr_in](@ref sockaddr_in) + +@param [in] u8AddrLen + Size of the given socket address structure in bytes. + Not currently used, implemented for BSD compatibility only. +@pre + The socket function must be called to allocate a TCP socket before passing the socket ID to the bind function. + If the socket is not bound, you do NOT have to call bind before the "connect" function. + +@see + socket + recv + send + close + +@return + The function returns ZERO for successful operations and a negative value otherwise. + The possible error values are: + - [SOCK_ERR_NO_ERROR](@ref SOCK_ERR_NO_ERROR) + Indicating that the operation was successful. + + - [SOCK_ERR_INVALID_ARG](@ref SOCK_ERR_INVALID_ARG) + Indicating passing invalid arguments such as negative socket ID or NULL socket address structure. + + - [SOCK_ERR_INVALID](@ref SOCK_ERR_INVALID) + Indicate socket connect failure. +\section Example + The example demonstrates a TCP application, showing how the asynchronous call to the connect function is made through the main function and how the + callback function handles the @ref SOCKET_MSG_CONNECT event. +\subsection sub1 Main Function +@code + struct sockaddr_in Serv_Addr; + SOCKET TcpClientSocket =-1; + int ret = -1 + + TcpClientSocket = socket(AF_INET,SOCK_STREAM,0); + Serv_Addr.sin_family = AF_INET; + Serv_Addr.sin_port = _htons(1234); + Serv_Addr.sin_addr.s_addr = inet_addr(SERVER); + printf("Connected to server via socket %u\n",TcpClientSocket); + + do + { + ret = connect(TcpClientSocket,(sockaddr_in*)&Serv_Addr,sizeof(Serv_Addr)); + if(ret != 0) + { + printf("Connection Error\n"); + } + else + { + printf("Connection successful.\n"); + break; + } + }while(1) +@endcode +\subsection sub2 Socket Callback +@code + if(u8Msg == SOCKET_MSG_CONNECT) + { + tstrSocketConnectMsg *pstrConnect = (tstrSocketConnectMsg*)pvMsg; + if(pstrConnect->s8Error == 0) + { + uint8 acBuffer[GROWL_MSG_SIZE]; + uint16 u16MsgSize; + + printf("Connect success!\n"); + + u16MsgSize = FormatMsg(u8ClientID, acBuffer); + send(sock, acBuffer, u16MsgSize, 0); + recv(pstrNotification->Socket, (void*)au8Msg,GROWL_DESCRIPTION_MAX_LENGTH, GROWL_RX_TIMEOUT); + u8Retry = GROWL_CONNECT_RETRY; + } + else + { + M2M_DBG("Connection Failed, Error: %d\n",pstrConnect->s8Error"); + close(pstrNotification->Socket); + } + } +@endcode +*/ +NMI_API sint8 connect(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen); +/** @} */ +/** @defgroup ReceiveFn recv + * @ingroup SocketAPI + * An asynchronous receive function, used to retrieve data from a TCP stream. + Before calling the recv function, a successful socket connection status must have been received through any of the two socket events + [SOCKET_MSG_CONNECT] or [SOCKET_MSG_ACCEPT], from the socket callback. Hence, indicating that the socket is already connected to a remote + host. + The application receives the required data in response to this asynchronous call through the reception of the event @ref SOCKET_MSG_RECV in the + socket callback. + + Receiving the SOCKET_MSG_RECV message in the callback with zero or negative buffer length indicates the following: + - SOCK_ERR_NO_ERROR : Socket connection closed + - SOCK_ERR_CONN_ABORTED : Socket connection aborted + - SOCK_ERR_TIMEOUT : Socket receive timed out + The application code is expected to close the socket through the call to the @ref close function upon the appearance of the above mentioned errors. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint16 recv(SOCKET sock, void *pvRecvBuf, uint16 u16BufLen, uint32 u32Timeoutmsec); + +@param [in] sock + Socket ID, must hold a non negative value. + A negative value will return a socket error @ref SOCK_ERR_INVALID_ARG. Indicating that an invalid argument is passed in. + + +@param [in] pvRecvBuf + Pointer to a buffer that will hold the received data. The buffer is used + in the recv callback to deliver the received data to the caller. The buffer must + be resident in memory (heap or global buffer). + +@param [in] u16BufLen + The buffer size in bytes. + +@param [in] u32Timeoutmsec + Timeout for the recv function in milli-seconds. If the value is set to ZERO, the timeout + will be set to infinite (the recv function waits forever). If the timeout period is + elapsed with no data received, the socket will get a timeout error. +@pre + - The socket function must be called to allocate a TCP socket before passing the socket ID to the recv function. + - The socket in a connected state is expected to receive data through the socket interface. + +@see + socket + connect + bind + listen + recvfrom + close + + +@return + The function returns ZERO for successful operations and a negative value otherwise. + The possible error values are: + - [SOCK_ERR_NO_ERROR](@ref SOCK_ERR_NO_ERROR) + Indicating that the operation was successful. + + - [SOCK_ERR_INVALID_ARG](@ref SOCK_ERR_INVALID_ARG) + Indicating passing invalid arguments such as negative socket ID or NULL Recieve buffer. + + - [SOCK_ERR_BUFFER_FULL](@ref SOCK_ERR_BUFFER_FULL) + Indicate socket receive failure. +\section Example + The example demonstrates a code snippet for the calling of the recv function in the socket callback upon notification of the accept or connect events, and the parsing of the + received data when the SOCKET_MSG_RECV event is received. +@code + + switch(u8Msg) + { + + case SOCKET_MSG_ACCEPT: + { + tstrSocketAcceptMsg *pstrAccept = (tstrSocketAcceptMsg*)pvMsg; + + if(pstrAccept->sock >= 0) + { + recv(pstrAccept->sock,gau8RxBuffer,sizeof(gau8RxBuffer),TEST_RECV_TIMEOUT); + } + else + { + M2M_ERR("accept\n"); + } + } + break; + + + case SOCKET_MSG_RECV: + { + tstrSocketRecvMsg *pstrRx = (tstrSocketRecvMsg*)pvMsg; + + if(pstrRx->s16BufferSize > 0) + { + + recv(sock,gau8RxBuffer,sizeof(gau8RxBuffer),TEST_RECV_TIMEOUT); + } + else + { + printf("Socet recv Error: %d\n",pstrRx->s16BufferSize); + close(sock); + } + } + break; + + default: + break; + } +} +@endcode +*/ +NMI_API sint16 recv(SOCKET sock, void *pvRecvBuf, uint16 u16BufLen, uint32 u32Timeoutmsec); +/** @} */ +/** @defgroup ReceiveFromSocketFn recvfrom + * @ingroup SocketAPI + * Receives data from a UDP Socket. +* +* The asynchronous recvfrom function is used to retrieve data from a UDP socket. The socket must already be bound to +* a local port before a call to the recvfrom function is made (i.e message @ref SOCKET_MSG_BIND is received +* with successful status in the socket callback). +* +* Upon calling the recvfrom function with a successful return code, the application is expected to receive a notification +* in the socket callback whenever a message is received through the @ref SOCKET_MSG_RECVFROM event. +* +* Receiving the SOCKET_MSG_RECVFROM message in the callback with zero, indicates that the socket is closed. +* Whereby a negative buffer length indicates one of the socket error codes such as socket timeout error @SOCK_ERR_TIMEOUT: +* +* The recvfrom callback can also be used to show the IP address of the remote host that sent the frame by +* using the "strRemoteAddr" element in the @ref tstrSocketRecvMsg structure. (refer to the code example) + */ + /**@{*/ +/*! +@fn \ + NMI_API sint16 recvfrom(SOCKET sock, void *pvRecvBuf, uint16 u16BufLen, uint32 u32TimeoutSeconds); + +@param [in] sock + Socket ID, must hold a non negative value. + A negative value will return a socket error @ref SOCK_ERR_INVALID_ARG. Indicating that an invalid argument is passed in. + +@param [in] pvRecvBuf + Pointer to a buffer that will hold the received data. The buffer shall be used + in the recv callback to deliver the received data to the caller. The buffer must + be resident in memory (heap or global buffer). + +@param [in] u16BufLen + The buffer size in bytes. + +@param [in] u32TimeoutSeconds + Timeout for the recv function in milli-seconds. If the value is set to ZERO, the timeout + will be set to infinite (the recv function waits forever). + +@pre + - The socket function must be called to allocate a UDP socket before passing the socket ID to the recvfrom function. + - The socket corresponding to the socket ID must be successfully bound to a local port through the call to a @ref bind function. + +@see + socket + bind + close + +@return + The function returns ZERO for successful operations and a negative value otherwise. + The possible error values are: + - [SOCK_ERR_NO_ERROR](@ref SOCK_ERR_NO_ERROR) + Indicating that the operation was successful. + + - [SOCK_ERR_INVALID_ARG](@ref SOCK_ERR_INVALID_ARG) + Indicating passing invalid arguments such as negative socket ID or NULL Receive buffer. + + - [SOCK_ERR_BUFFER_FULL](@ref SOCK_ERR_BUFFER_FULL) + Indicate socket receive failure. +\section Example + The example demonstrates a code snippet for the calling of the recvfrom function in the socket callback upon notification of a successful bind event, and the parsing of the + received data when the SOCKET_MSG_RECVFROM event is received. +@code + switch(u8Msg) + { + + case SOCKET_MSG_BIND: + { + tstrSocketBindMsg *pstrBind = (tstrSocketBindMsg*)pvMsg; + + if(pstrBind != NULL) + { + if(pstrBind->status == 0) + { + recvfrom(sock, gau8SocketTestBuffer, TEST_BUFFER_SIZE, 0); + } + else + { + M2M_ERR("bind\n"); + } + } + } + break; + + + case SOCKET_MSG_RECVFROM: + { + tstrSocketRecvMsg *pstrRx = (tstrSocketRecvMsg*)pvMsg; + + if(pstrRx->s16BufferSize > 0) + { + //get the remote host address and port number + uint16 u16port = pstrRx->strRemoteAddr.sin_port; + uint32 strRemoteHostAddr = pstrRx->strRemoteAddr.sin_addr.s_addr; + + printf("Recieved frame with size = %d.\tHost address=%x, Port number = %d\n\n",pstrRx->s16BufferSize,strRemoteHostAddr, u16port); + + ret = recvfrom(sock,gau8SocketTestBuffer,sizeof(gau8SocketTestBuffer),TEST_RECV_TIMEOUT); + } + else + { + printf("Socet recv Error: %d\n",pstrRx->s16BufferSize); + ret = close(sock); + } + } + break; + + default: + break; + } +} +@endcode +*/ +NMI_API sint16 recvfrom(SOCKET sock, void *pvRecvBuf, uint16 u16BufLen, uint32 u32Timeoutmsec); +/** @} */ +/** @defgroup SendFn send + * @ingroup SocketAPI +* Asynchronous sending function, used to send data on a TCP/UDP socket. + +* Called by the application code when there is outgoing data available required to be sent on a specific socket handler. +* The only difference between this function and the similar @ref sendto function, is the type of socket the data is sent on and the parameters passed in. +* @ref send function is most commonly called for sockets in a connected state. +* After the data is sent, the socket callback function registered using registerSocketCallback(), is expected to receive an event of type +* @ref SOCKET_MSG_SEND holding information containing the number of data bytes sent. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint16 send(SOCKET sock, void *pvSendBuffer, uint16 u16SendLength, uint16 u16Flags); + +@param [in] sock + Socket ID, must hold a non negative value. + A negative value will return a socket error @ref SOCK_ERR_INVALID_ARG. Indicating that an invalid argument is passed in. + +@param [in] pvSendBuffer + Pointer to a buffer holding data to be transmitted. + +@param [in] u16SendLength + The buffer size in bytes. + +@param [in] u16Flags + Not used in the current implementation. + +@pre + Sockets must be initialized using socketInit. \n + + For TCP Socket:\n + Must use a successfully connected Socket (so that the intended recipient address is known ahead of sending the data). + Hence this function is expected to be called after a successful socket connect operation(in client case or accept in the + the server case).\n + + For UDP Socket:\n + UDP sockets most commonly use @ref sendto function, where the destination address is defined. However, in-order to send outgoing data + using the @ref send function, at least one successful call must be made to the @ref sendto function a priori the consecutive calls to the @ref send function, + to ensure that the destination address is saved in the firmware. + +@see + socketInit + recv + sendto + socket + connect + accept + sendto + +@warning + u16SendLength must not exceed @ref SOCKET_BUFFER_MAX_LENGTH. \n + Use a valid socket identifier through the a prior call to the @ref socket function. + Must use a valid buffer pointer. + Successful completion of a call to send() does not guarantee delivery of the message, + A negative return value indicates only locally-detected errors + + +@return + The function shall return @ref SOCK_ERR_NO_ERROR for successful operation and a negative value (indicating the error) otherwise. +*/ +NMI_API sint16 send(SOCKET sock, void *pvSendBuffer, uint16 u16SendLength, uint16 u16Flags); +/** @} */ +/** @defgroup SendToSocketFn sendto + * @ingroup SocketAPI +* Asynchronous sending function, used to send data on a UDP socket. +* Called by the application code when there is data required to be sent on a UDP socket handler. +* The application code is expected to receive data from a successful bounded socket node. +* The only difference between this function and the similar @ref send function, is the type of socket the data is received on. This function works +* only with UDP sockets. +* After the data is sent, the socket callback function registered using registerSocketCallback(), is expected to receive an event of type +* @ref SOCKET_MSG_SENDTO. +*/ + /**@{*/ +/*! +@fn \ + NMI_API sint16 sendto(SOCKET sock, void *pvSendBuffer, uint16 u16SendLength, uint16 flags, struct sockaddr *pstrDestAddr, uint8 u8AddrLen); + +@param [in] sock + Socket ID, must hold a non negative value. + A negative value will return a socket error @ref SOCK_ERR_INVALID_ARG. Indicating that an invalid argument is passed in. + +@param [in] pvSendBuffer + Pointer to a buffer holding data to be transmitted. + A NULL value will return a socket error @ref SOCK_ERR_INVALID_ARG. Indicating that an invalid argument is passed in. + +@param [in] u16SendLength + The buffer size in bytes. It must not exceed @ref SOCKET_BUFFER_MAX_LENGTH. + +@param [in] flags + Not used in the current implementation + +@param [in] pstrDestAddr + The destination address. + +@param [in] u8AddrLen + Destination address length in bytes. + Not used in the current implementation, only included for BSD compatibility. +@pre + Sockets must be initialized using socketInit. + +@see + socketInit + recvfrom + sendto + socket + connect + accept + send + +@warning + u16SendLength must not exceed @ref SOCKET_BUFFER_MAX_LENGTH. \n + Use a valid socket (returned from socket ). + A valid buffer pointer must be used (not NULL). \n + Successful completion of a call to sendto() does not guarantee delivery of the message, + A negative return value indicates only locally-detected errors + +@return + The function returns @ref SOCK_ERR_NO_ERROR for successful operation and a negative value (indicating the error) otherwise. +*/ +NMI_API sint16 sendto(SOCKET sock, void *pvSendBuffer, uint16 u16SendLength, uint16 flags, struct sockaddr *pstrDestAddr, uint8 u8AddrLen); +/** @} */ +/** @defgroup CloseSocketFn close + * @ingroup SocketAPI + * Synchronous close function, releases all the socket assigned resources. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 close(SOCKET sock); + +@param [in] sock + Socket ID, must hold a non negative value. + A negative value will return a socket error @ref SOCK_ERR_INVALID_ARG. Indicating that an invalid argument is passed in. + +@pre + Sockets must be initialized through the call of the socketInit function. + @ref close is called only for valid socket identifiers created through the @ref socket function. + +@warning + If @ref close is called while there are still pending messages (sent or received ) they will be discarded. + +@see + socketInit + socket + +@return + The function returned @ref SOCK_ERR_NO_ERROR for successful operation and a negative value (indicating the error) otherwise. +*/ +NMI_API sint8 close(SOCKET sock); +/** @} */ +/** @defgroup InetAddressFn nmi_inet_addr +* @ingroup SocketAPI +* Synchronous function which returns a BSD socket compliant Internet Protocol (IPv4) socket address. +* This IPv4 address in the input string parameter could either be specified as a host name, or as a numeric string representation like n.n.n.n known as the IPv4 dotted-decimal format +* (i.e. "192.168.10.1"). +* This function is used whenever an ip address needs to be set in the proper format +* (i.e. for the @ref tstrM2MIPConfig structure). +*/ + /**@{*/ +/*! +@fn \ + NMI_API uint32 nmi_inet_addr(char *pcIpAddr); + +@param [in] pcIpAddr + A null terminated string containing the IP address in IPv4 dotted-decimal address. + +@return + Unsigned 32-bit integer representing the IP address in Network byte order + (eg. "192.168.10.1" will be expressed as 0x010AA8C0). + +*/ +NMI_API uint32 nmi_inet_addr(char *pcIpAddr); + + +/** @} */ +/** @defgroup gethostbynameFn gethostbyname + * @ingroup SocketAPI +* Asynchronous DNS resolving function. This function use DNS to resolve a domain name into the corresponding IP address. +* A call to this function will cause a DNS request to be sent and the response will be delivered to the DNS callback function registered using registerSocketCallback() + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 gethostbyname(uint8 * pcHostName); + +@param [in] pcHostName + NULL terminated string containing the domain name for the remote host. + Its size must not exceed [HOSTNAME_MAX_SIZE](@ref HOSTNAME_MAX_SIZE). + +@see + registerSocketCallback + +@warning + Successful completion of a call to gethostbyname() does not guarantee success of the DNS request, + a negative return value indicates only locally-detected errors + +@return + - [SOCK_ERR_NO_ERROR](@ref SOCK_ERR_NO_ERROR) + - [SOCK_ERR_INVALID_ARG](@ref SOCK_ERR_INVALID_ARG) +*/ +NMI_API sint8 gethostbyname(uint8 * pcHostName); + + +/** @} */ +/** @defgroup sslEnableCertExpirationCheckFn sslEnableCertExpirationCheck + * @ingroup SocketAPI +* Configure the behavior of the SSL Library for Certificate Expiry Validation. + */ + /**@{*/ +/*! +@fn \ +NMI_API sint8 sslEnableCertExpirationCheck(tenuSslCertExpSettings enuValidationSetting); + +@param [in] enuValidationSetting + See @ref tenuSslCertExpSettings for details. + +@return + - [SOCK_ERR_NO_ERROR](@ref SOCK_ERR_NO_ERROR) for successful operation and negative error code otherwise. + +@sa tenuSslCertExpSettings +*/ +NMI_API sint8 sslEnableCertExpirationCheck(tenuSslCertExpSettings enuValidationSetting); + + +/** @} */ + +/** @defgroup SetSocketOptionFn setsockopt + * @ingroup SocketAPI +*The setsockopt() function shall set the option specified by the option_name +* argument, at the protocol level specified by the level argument, to the value +* pointed to by the option_value argument for the socket specified by the socket argument. +* +*

Possible protocol level values supported are @ref SOL_SOCKET and @ref SOL_SSL_SOCKET. +* Possible options when the protocol level is @ref SOL_SOCKET :

+* +* +* +* +* +* +* +* +* +* +* +* +* +*
@ref SO_SET_UDP_SEND_CALLBACKEnable/Disable callback messages for sendto(). +* Since UDP is unreliable by default the user maybe interested (or not) in +* receiving a message of @ref SOCKET_MSG_SENDTO for each call of sendto(). +* Enabled if option value equals @ref TRUE, disabled otherwise.
@ref IP_ADD_MEMBERSHIPValid for UDP sockets. This option is used to receive frames sent to +* a multicast group. option_value shall be a pointer to Unsigned 32-bit +* integer containing the multicast IPv4 address.
@ref IP_DROP_MEMBERSHIPValid for UDP sockets. This option is used to stop receiving frames +* sent to a multicast group. option_value shall be a pointer to Unsigned +* 32-bit integer containing the multicast IPv4 address.
+*

Possible options when the protcol leve  is @ref SOL_SSL_SOCKET

+* +* +* +* +* +* +* +* +* +* +* +* +* +*
+* @ref SO_SSL_BYPASS_X509_VERIFAllow an opened SSL socket to bypass the X509 +* certificate verification process. It is highly recommended NOT to use +* this socket option in production software applications. The option is +* supported for debugging and testing purposes. The option value should be +* casted to int type and it is handled as a boolean flag.
@ref SO_SSL_SNISet the Server Name Indicator (SNI) for an SSL socket. The SNI is a +* null terminated string containing the server name associated with the +* connection. It must not exceed the size of @ref HOSTNAME_MAX_SIZE.
@ref SO_SSL_ENABLE_SESSION_CACHINGThis option allow the TLS to cache the session information for fast +* TLS session establishment in future connections using the TLS Protocol +* session resume features.
+ */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 setsockopt(SOCKET socket, uint8 u8Level, uint8 option_name, + const void *option_value, uint16 u16OptionLen); + +@param [in] sock + Socket handler. + +@param [in] level + protocol level. See description above. + +@param [in] option_name + option to be set. See description above. + +@param [in] option_value + pointer to user provided value. + +@param [in] option_len + length of the option value in bytes. +@return + The function shall return \ref SOCK_ERR_NO_ERROR for successful operation + and a negative value (indicating the error) otherwise. +@sa SOL_SOCKET, SOL_SSL_SOCKET, IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP +*/ +NMI_API sint8 setsockopt(SOCKET socket, uint8 u8Level, uint8 option_name, + const void *option_value, uint16 u16OptionLen); + + +/** @} */ +/** @defgroup GetSocketOptionsFn getsockopt + * @ingroup SocketAPI + * Get socket options retrieves +* This Function isn't implemented yet but this is the form that will be released later. + */ + /**@{*/ +/*! +@fn \ + sint8 getsockopt(SOCKET sock, uint8 u8Level, uint8 u8OptName, const void *pvOptValue, uint8 * pu8OptLen); + +@brief + +@param [in] sock + Socket Identifie. +@param [in] u8Level + The protocol level of the option. +@param [in] u8OptName + The u8OptName argument specifies a single option to get. +@param [out] pvOptValue + The pvOptValue argument contains pointer to a buffer containing the option value. +@param [out] pu8OptLen + Option value buffer length. +@return + The function shall return ZERO for successful operation and a negative value otherwise. +*/ +NMI_API sint8 getsockopt(SOCKET sock, uint8 u8Level, uint8 u8OptName, const void *pvOptValue, uint8* pu8OptLen); +/** @} */ + +/**@}*/ +/** @defgroup PingFn m2m_ping_req + * @ingroup SocketAPI + * The function sends ping request to the given IP Address. + */ + /**@{*/ +/*! +@fn \ + NMI_API sint8 m2m_ping_req(uint32 u32DstIP, uint8 u8TTL, tpfPingCb fpPingCb); + +@param [in] u32DstIP + Target Destination IP Address for the ping request. It must be represented in Network byte order. + The function nmi_inet_addr could be used to translate the dotted decimal notation IP + to its Network bytes order integer represntative. + +@param [in] u8TTL + IP TTL value for the ping request. If set to ZERO, the dfault value SHALL be used. + +@param [in] fpPingCb + Callback will be called to deliver the ping statistics. + +@see nmi_inet_addr +@return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. +*/ +NMI_API sint8 m2m_ping_req(uint32 u32DstIP, uint8 u8TTL, tpfPingCb fpPingCb); +/**@}*/ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __SOCKET_H__ */ diff --git a/lib/WiFi101/src/socket/source/socket.c b/lib/WiFi101/src/socket/source/socket.c new file mode 100644 index 0000000..e651133 --- /dev/null +++ b/lib/WiFi101/src/socket/source/socket.c @@ -0,0 +1,1383 @@ +/** + * + * \file + * + * \brief BSD compatible socket interface. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ +#include + +#include "bsp/include/nm_bsp.h" +#include "socket/include/socket.h" +#include "driver/source/m2m_hif.h" +#include "socket/source/socket_internal.h" +#include "driver/include/m2m_types.h" + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +MACROS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + + +#define TLS_RECORD_HEADER_LENGTH (5) +#define ETHERNET_HEADER_OFFSET (34) +#define ETHERNET_HEADER_LENGTH (14) +#define TCP_IP_HEADER_LENGTH (40) +#define UDP_IP_HEADER_LENGTH (28) + +#define IP_PACKET_OFFSET (ETHERNET_HEADER_LENGTH + ETHERNET_HEADER_OFFSET - M2M_HIF_HDR_OFFSET) + +#define TCP_TX_PACKET_OFFSET (IP_PACKET_OFFSET + TCP_IP_HEADER_LENGTH) +#define UDP_TX_PACKET_OFFSET (IP_PACKET_OFFSET + UDP_IP_HEADER_LENGTH) +#define SSL_TX_PACKET_OFFSET (TCP_TX_PACKET_OFFSET + TLS_RECORD_HEADER_LENGTH) + +#define SOCKET_REQUEST(reqID, reqArgs, reqSize, reqPayload, reqPayloadSize, reqPayloadOffset) \ + hif_send(M2M_REQ_GROUP_IP, reqID, reqArgs, reqSize, reqPayload, reqPayloadSize, reqPayloadOffset) + + +#define SSL_FLAGS_ACTIVE NBIT0 +#define SSL_FLAGS_BYPASS_X509 NBIT1 +#define SSL_FLAGS_2_RESERVD NBIT2 +#define SSL_FLAGS_3_RESERVD NBIT3 +#define SSL_FLAGS_CACHE_SESSION NBIT4 +#define SSL_FLAGS_NO_TX_COPY NBIT5 +#define SSL_FLAGS_CHECK_SNI NBIT6 + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +PRIVATE DATA TYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + + +/*! +* @brief +*/ +typedef struct{ + SOCKET sock; + uint8 u8Dummy; + uint16 u16SessionID; +}tstrCloseCmd; + + +/*! +* @brief +*/ +typedef struct{ + uint8 *pu8UserBuffer; + uint16 u16UserBufferSize; + uint16 u16SessionID; + uint16 u16DataOffset; + uint8 bIsUsed; + uint8 u8SSLFlags; + uint8 bIsRecvPending; +}tstrSocket; + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +GLOBALS +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +volatile sint8 gsockerrno; +volatile tstrSocket gastrSockets[MAX_SOCKET]; +volatile uint8 gu8OpCode; +volatile uint16 gu16BufferSize; +volatile uint16 gu16SessionID = 0; + +volatile tpfAppSocketCb gpfAppSocketCb; +volatile tpfAppResolveCb gpfAppResolveCb; +volatile uint8 gbSocketInit = 0; +volatile tpfPingCb gfpPingCb; + +/********************************************************************* +Function + Socket_ReadSocketData + +Description + Callback function used by the NMC1500 driver to deliver messages + for socket layer. + +Return + None. + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 17 July 2012 +*********************************************************************/ +#ifndef ARDUINO +NMI_API void Socket_ReadSocketData(SOCKET sock, tstrSocketRecvMsg *pstrRecv,uint8 u8SocketMsg, + uint32 u32StartAddress,uint16 u16ReadCount) +{ + if((u16ReadCount > 0) && (gastrSockets[sock].pu8UserBuffer != NULL) && (gastrSockets[sock].u16UserBufferSize > 0) && (gastrSockets[sock].bIsUsed == 1)) + { + uint32 u32Address = u32StartAddress; + uint16 u16Read; + sint16 s16Diff; + uint8 u8SetRxDone; + pstrRecv->u16RemainingSize = u16ReadCount; + do + { + u8SetRxDone = 1; + u16Read = u16ReadCount; + s16Diff = u16Read - gastrSockets[sock].u16UserBufferSize; + if(s16Diff > 0) + { + u8SetRxDone = 0; + u16Read = gastrSockets[sock].u16UserBufferSize; + } + + if(hif_receive(u32Address, gastrSockets[sock].pu8UserBuffer, u16Read, u8SetRxDone) == M2M_SUCCESS) + { + pstrRecv->pu8Buffer = gastrSockets[sock].pu8UserBuffer; + pstrRecv->s16BufferSize = u16Read; + pstrRecv->u16RemainingSize -= u16Read; + + if (gpfAppSocketCb) + gpfAppSocketCb(sock,u8SocketMsg, pstrRecv); + + u16ReadCount -= u16Read; + u32Address += u16Read; + + if((!gastrSockets[sock].bIsUsed) && (u16ReadCount)) + { + M2M_DBG("Application Closed Socket While Rx Is not Complete\n"); + if(hif_receive(0, NULL, 0, 1) == M2M_SUCCESS) + M2M_DBG("hif_receive Success\n"); + else + M2M_DBG("hif_receive Fail\n"); + break; + } + } + else + { + M2M_INFO("(ERRR)Current <%d>\n", u16ReadCount); + break; + } + }while(u16ReadCount != 0); + } +} +#endif +/********************************************************************* +Function + m2m_ip_cb + +Description + Callback function used by the NMC1000 driver to deliver messages + for socket layer. + +Return + None. + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 17 July 2012 +*********************************************************************/ +#ifdef ARDUINO +extern uint8 hif_receive_blocked; +#endif +static void m2m_ip_cb(uint8 u8OpCode, uint16 u16BufferSize,uint32 u32Address) +{ + if((u8OpCode == SOCKET_CMD_BIND) || (u8OpCode == SOCKET_CMD_SSL_BIND)) + { + tstrBindReply strBindReply; + tstrSocketBindMsg strBind; + + if(hif_receive(u32Address, (uint8*)&strBindReply, sizeof(tstrBindReply), 0) == M2M_SUCCESS) + { + strBind.status = strBindReply.s8Status; + if(gpfAppSocketCb) + gpfAppSocketCb(strBindReply.sock,SOCKET_MSG_BIND,&strBind); + } + } + else if(u8OpCode == SOCKET_CMD_LISTEN) + { + tstrListenReply strListenReply; + tstrSocketListenMsg strListen; + if(hif_receive(u32Address, (uint8*)&strListenReply, sizeof(tstrListenReply), 0) == M2M_SUCCESS) + { + strListen.status = strListenReply.s8Status; + if(gpfAppSocketCb) + gpfAppSocketCb(strListenReply.sock,SOCKET_MSG_LISTEN, &strListen); + } + } + else if(u8OpCode == SOCKET_CMD_ACCEPT) + { + tstrAcceptReply strAcceptReply; + tstrSocketAcceptMsg strAccept; + if(hif_receive(u32Address, (uint8*)&strAcceptReply, sizeof(tstrAcceptReply), 0) == M2M_SUCCESS) + { + if(strAcceptReply.sConnectedSock >= 0) + { + gastrSockets[strAcceptReply.sConnectedSock].u8SSLFlags = gastrSockets[strAcceptReply.sListenSock].u8SSLFlags; + gastrSockets[strAcceptReply.sConnectedSock].bIsUsed = 1; + gastrSockets[strAcceptReply.sConnectedSock].u16DataOffset = strAcceptReply.u16AppDataOffset - M2M_HIF_HDR_OFFSET; + + /* The session ID is used to distinguish different socket connections + by comparing the assigned session ID to the one reported by the firmware*/ + ++gu16SessionID; + if(gu16SessionID == 0) + ++gu16SessionID; + + gastrSockets[strAcceptReply.sConnectedSock].u16SessionID = gu16SessionID; + M2M_DBG("Socket %d session ID = %d\r\n",strAcceptReply.sConnectedSock , gu16SessionID ); + } + strAccept.sock = strAcceptReply.sConnectedSock; + strAccept.strAddr.sin_family = AF_INET; + strAccept.strAddr.sin_port = strAcceptReply.strAddr.u16Port; + strAccept.strAddr.sin_addr.s_addr = strAcceptReply.strAddr.u32IPAddr; + if(gpfAppSocketCb) + gpfAppSocketCb(strAcceptReply.sListenSock, SOCKET_MSG_ACCEPT, &strAccept); + } + } + else if((u8OpCode == SOCKET_CMD_CONNECT) || (u8OpCode == SOCKET_CMD_SSL_CONNECT)) + { + tstrConnectReply strConnectReply; + tstrSocketConnectMsg strConnMsg; + if(hif_receive(u32Address, (uint8*)&strConnectReply, sizeof(tstrConnectReply), 0) == M2M_SUCCESS) + { + strConnMsg.sock = strConnectReply.sock; + strConnMsg.s8Error = strConnectReply.s8Error; + if(strConnectReply.s8Error == SOCK_ERR_NO_ERROR) + { + gastrSockets[strConnectReply.sock].u16DataOffset = strConnectReply.u16AppDataOffset - M2M_HIF_HDR_OFFSET; + } + if(gpfAppSocketCb) + gpfAppSocketCb(strConnectReply.sock,SOCKET_MSG_CONNECT, &strConnMsg); + } + } + else if(u8OpCode == SOCKET_CMD_DNS_RESOLVE) + { + tstrDnsReply strDnsReply; + if(hif_receive(u32Address, (uint8*)&strDnsReply, sizeof(tstrDnsReply), 0) == M2M_SUCCESS) + { + if(gpfAppResolveCb) + gpfAppResolveCb((uint8*)strDnsReply.acHostName, strDnsReply.u32HostIP); + } + } + else if((u8OpCode == SOCKET_CMD_RECV) || (u8OpCode == SOCKET_CMD_RECVFROM) || (u8OpCode == SOCKET_CMD_SSL_RECV)) + { + SOCKET sock; + sint16 s16RecvStatus; + tstrRecvReply strRecvReply; + uint16 u16ReadSize; + tstrSocketRecvMsg strRecvMsg; + uint8 u8CallbackMsgID = SOCKET_MSG_RECV; + uint16 u16DataOffset; + + if(u8OpCode == SOCKET_CMD_RECVFROM) + u8CallbackMsgID = SOCKET_MSG_RECVFROM; + + /* Read RECV REPLY data structure. + */ + u16ReadSize = sizeof(tstrRecvReply); + if(hif_receive(u32Address, (uint8*)&strRecvReply, u16ReadSize, 0) == M2M_SUCCESS) + { + uint16 u16SessionID = 0; + + sock = strRecvReply.sock; + u16SessionID = strRecvReply.u16SessionID; + M2M_DBG("recv callback session ID = %d\r\n",u16SessionID); + + /* Reset the Socket RX Pending Flag. + */ + gastrSockets[sock].bIsRecvPending = 0; + + s16RecvStatus = NM_BSP_B_L_16(strRecvReply.s16RecvStatus); + u16DataOffset = NM_BSP_B_L_16(strRecvReply.u16DataOffset); + strRecvMsg.strRemoteAddr.sin_port = strRecvReply.strRemoteAddr.u16Port; + strRecvMsg.strRemoteAddr.sin_addr.s_addr = strRecvReply.strRemoteAddr.u32IPAddr; + + if(u16SessionID == gastrSockets[sock].u16SessionID) + { +#ifdef ARDUINO + if((s16RecvStatus > 0) && (s16RecvStatus < (sint32)u16BufferSize)) +#else + if((s16RecvStatus > 0) && (s16RecvStatus < u16BufferSize)) +#endif + { + /* Skip incoming bytes until reaching the Start of Application Data. + */ + u32Address += u16DataOffset; +#ifdef ARDUINO + // Avoid calling Socket_ReadSocketData because it pulls all the socket data + // from the WINC1500 at once. + // + // Call the callback with the recv address and recv data info. Later, + // the data will be pulled from the address using hif_receive. + hif_receive_blocked = 1; + + strRecvMsg.s16BufferSize = s16RecvStatus; + strRecvMsg.pu8Buffer = u32Address; + strRecvMsg.u16RemainingSize = 0; + if(gpfAppSocketCb) { + gpfAppSocketCb(sock,u8CallbackMsgID, &strRecvMsg); + } +#else + /* Read the Application data and deliver it to the application callback in + the given application buffer. If the buffer is smaller than the received data, + the data is passed to the application in chunks according to its buffer size. + */ + u16ReadSize = (uint16)s16RecvStatus; + Socket_ReadSocketData(sock, &strRecvMsg, u8CallbackMsgID, u32Address, u16ReadSize); +#endif + } + else + { + strRecvMsg.s16BufferSize = s16RecvStatus; +#ifdef ARDUINO + strRecvMsg.pu8Buffer = 0; +#else + strRecvMsg.pu8Buffer = NULL; +#endif + if(gpfAppSocketCb) + gpfAppSocketCb(sock,u8CallbackMsgID, &strRecvMsg); + } + } + else + { + M2M_DBG("Discard recv callback %d %d \r\n",u16SessionID , gastrSockets[sock].u16SessionID); + if(u16ReadSize < u16BufferSize) + { + if(hif_receive(0, NULL, 0, 1) == M2M_SUCCESS) + M2M_DBG("hif_receive Success\n"); + else +#ifdef ARDUINO + { +#endif + M2M_DBG("hif_receive Fail\n"); +#ifdef ARDUINO + } +#endif + } + } + } + } + else if((u8OpCode == SOCKET_CMD_SEND) || (u8OpCode == SOCKET_CMD_SENDTO) || (u8OpCode == SOCKET_CMD_SSL_SEND)) + { + SOCKET sock; + sint16 s16Rcvd; + tstrSendReply strReply; + uint8 u8CallbackMsgID = SOCKET_MSG_SEND; + + if(u8OpCode == SOCKET_CMD_SENDTO) + u8CallbackMsgID = SOCKET_MSG_SENDTO; + + if(hif_receive(u32Address, (uint8*)&strReply, sizeof(tstrSendReply), 0) == M2M_SUCCESS) + { + uint16 u16SessionID = 0; + + sock = strReply.sock; + u16SessionID = strReply.u16SessionID; + M2M_DBG("send callback session ID = %d\r\n",u16SessionID); + + s16Rcvd = NM_BSP_B_L_16(strReply.s16SentBytes); + + if(u16SessionID == gastrSockets[sock].u16SessionID) + { + if(gpfAppSocketCb) + gpfAppSocketCb(sock,u8CallbackMsgID, &s16Rcvd); + } + else + { + M2M_DBG("Discard send callback %d %d \r\n",u16SessionID , gastrSockets[sock].u16SessionID); + } + } + } + else if(u8OpCode == SOCKET_CMD_PING) + { + tstrPingReply strPingReply; + if(hif_receive(u32Address, (uint8*)&strPingReply, sizeof(tstrPingReply), 1) == M2M_SUCCESS) + { + gfpPingCb = (void (*)(uint32 , uint32 , uint8))(uintptr_t)strPingReply.u32CmdPrivate; + if(gfpPingCb != NULL) + { + gfpPingCb(strPingReply.u32IPAddr, strPingReply.u32RTT, strPingReply.u8ErrorCode); + } + } + } +} +/********************************************************************* +Function + socketInit + +Description + +Return + None. + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 4 June 2012 +*********************************************************************/ +void socketInit(void) +{ + if(gbSocketInit == 0) + { + m2m_memset((uint8*)gastrSockets, 0, MAX_SOCKET * sizeof(tstrSocket)); + hif_register_cb(M2M_REQ_GROUP_IP,m2m_ip_cb); + gbSocketInit = 1; + gu16SessionID = 0; + } +} +/********************************************************************* +Function + socketDeinit + +Description + +Return + None. + +Author + Samer Sarhan + +Version + 1.0 + +Date + 27 Feb 2015 +*********************************************************************/ +void socketDeinit(void) +{ + m2m_memset((uint8*)gastrSockets, 0, MAX_SOCKET * sizeof(tstrSocket)); + hif_register_cb(M2M_REQ_GROUP_IP, NULL); + gpfAppSocketCb = NULL; + gpfAppResolveCb = NULL; + gbSocketInit = 0; +} +/********************************************************************* +Function + registerSocketCallback + +Description + +Return + None. + +Author + Ahmed Ezzat + +Versio + 1.0 + +Date + 4 June 2012 +*********************************************************************/ +void registerSocketCallback(tpfAppSocketCb pfAppSocketCb, tpfAppResolveCb pfAppResolveCb) +{ + gpfAppSocketCb = pfAppSocketCb; + gpfAppResolveCb = pfAppResolveCb; +} + +/********************************************************************* +Function + socket + +Description + Creates a socket. + +Return + - Negative value for error. + - ZERO or positive value as a socket ID if successful. + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 4 June 2012 +*********************************************************************/ +SOCKET socket(uint16 u16Domain, uint8 u8Type, uint8 u8Flags) +{ + SOCKET sock = -1; + uint8 u8SockID; + uint8 u8Count; + volatile tstrSocket *pstrSock; + static volatile uint8 u8NextTcpSock = 0; + static volatile uint8 u8NextUdpSock = 0; + + /* The only supported family is the AF_INET for UDP and TCP transport layer protocols. */ + if(u16Domain == AF_INET) + { + if(u8Type == SOCK_STREAM) + { + for(u8Count = 0; u8Count < TCP_SOCK_MAX; u8Count ++) + { + u8SockID = u8NextTcpSock; + pstrSock = &gastrSockets[u8NextTcpSock]; + u8NextTcpSock = (u8NextTcpSock + 1) % TCP_SOCK_MAX; + if(!pstrSock->bIsUsed) + { + sock = (SOCKET)u8SockID; + break; + } + } + } + else if(u8Type == SOCK_DGRAM) + { + volatile tstrSocket *pastrUDPSockets = &gastrSockets[TCP_SOCK_MAX]; + for(u8Count = 0; u8Count < UDP_SOCK_MAX; u8Count ++) + { + u8SockID = u8NextUdpSock; + pstrSock = &pastrUDPSockets[u8NextUdpSock]; + u8NextUdpSock = (u8NextUdpSock + 1) % UDP_SOCK_MAX; + if(!pstrSock->bIsUsed) + { + sock = (SOCKET)(u8SockID + TCP_SOCK_MAX); + break; + } + } + } + + if(sock >= 0) + { + m2m_memset((uint8*)pstrSock, 0, sizeof(tstrSocket)); + pstrSock->bIsUsed = 1; + + /* The session ID is used to distinguish different socket connections + by comparing the assigned session ID to the one reported by the firmware*/ + ++gu16SessionID; + if(gu16SessionID == 0) + ++gu16SessionID; + + pstrSock->u16SessionID = gu16SessionID; + M2M_INFO("Socket %d session ID = %d\r\n",sock, gu16SessionID ); + + if(u8Flags & SOCKET_FLAGS_SSL) + { + tstrSSLSocketCreateCmd strSSLCreate; + strSSLCreate.sslSock = sock; + pstrSock->u8SSLFlags = SSL_FLAGS_ACTIVE | SSL_FLAGS_NO_TX_COPY; + SOCKET_REQUEST(SOCKET_CMD_SSL_CREATE, (uint8*)&strSSLCreate, sizeof(tstrSSLSocketCreateCmd), 0, 0, 0); + } + } + } + return sock; +} +/********************************************************************* +Function + bind + +Description + Request to bind a socket on a local address. + +Return + + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 5 June 2012 +*********************************************************************/ +sint8 bind(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen) +{ + sint8 s8Ret = SOCK_ERR_INVALID_ARG; + if((pstrAddr != NULL) && (sock >= 0) && (gastrSockets[sock].bIsUsed == 1) && (u8AddrLen != 0)) + { + tstrBindCmd strBind; + uint8 u8CMD = SOCKET_CMD_BIND; + if(gastrSockets[sock].u8SSLFlags & SSL_FLAGS_ACTIVE) + { + u8CMD = SOCKET_CMD_SSL_BIND; + } + + /* Build the bind request. */ + strBind.sock = sock; + m2m_memcpy((uint8 *)&strBind.strAddr, (uint8 *)pstrAddr, sizeof(tstrSockAddr)); + strBind.u16SessionID = gastrSockets[sock].u16SessionID; + + /* Send the request. */ + s8Ret = SOCKET_REQUEST(u8CMD, (uint8*)&strBind,sizeof(tstrBindCmd) , NULL , 0, 0); + if(s8Ret != SOCK_ERR_NO_ERROR) + { + s8Ret = SOCK_ERR_INVALID; + } + } + return s8Ret; +} +/********************************************************************* +Function + listen + +Description + + +Return + + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 5 June 2012 +*********************************************************************/ +sint8 listen(SOCKET sock, uint8 backlog) +{ + sint8 s8Ret = SOCK_ERR_INVALID_ARG; + + if(sock >= 0 && (gastrSockets[sock].bIsUsed == 1)) + { + tstrListenCmd strListen; + + strListen.sock = sock; + strListen.u8BackLog = backlog; + strListen.u16SessionID = gastrSockets[sock].u16SessionID; + + s8Ret = SOCKET_REQUEST(SOCKET_CMD_LISTEN, (uint8*)&strListen, sizeof(tstrListenCmd), NULL, 0, 0); + if(s8Ret != SOCK_ERR_NO_ERROR) + { + s8Ret = SOCK_ERR_INVALID; + } + } + return s8Ret; +} +/********************************************************************* +Function + accept + +Description + +Return + + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 5 June 2012 +*********************************************************************/ +sint8 accept(SOCKET sock, struct sockaddr *addr, uint8 *addrlen) +{ +#ifdef ARDUINO + // Silence "unused" warning + (void)addr; + (void)addrlen; +#endif + sint8 s8Ret = SOCK_ERR_INVALID_ARG; + + if(sock >= 0 && (gastrSockets[sock].bIsUsed == 1) ) + { + s8Ret = SOCK_ERR_NO_ERROR; + } + return s8Ret; +} +/********************************************************************* +Function + connect + +Description + Connect to a remote TCP Server. + +Return + + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 5 June 2012 +*********************************************************************/ +sint8 connect(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen) +{ + sint8 s8Ret = SOCK_ERR_INVALID_ARG; + if((sock >= 0) && (pstrAddr != NULL) && (gastrSockets[sock].bIsUsed == 1) && (u8AddrLen != 0)) + { + tstrConnectCmd strConnect; + uint8 u8Cmd = SOCKET_CMD_CONNECT; + if((gastrSockets[sock].u8SSLFlags) & SSL_FLAGS_ACTIVE) + { + u8Cmd = SOCKET_CMD_SSL_CONNECT; + strConnect.u8SslFlags = gastrSockets[sock].u8SSLFlags; + } + strConnect.sock = sock; + m2m_memcpy((uint8 *)&strConnect.strAddr, (uint8 *)pstrAddr, sizeof(tstrSockAddr)); + + strConnect.u16SessionID = gastrSockets[sock].u16SessionID; + s8Ret = SOCKET_REQUEST(u8Cmd, (uint8*)&strConnect,sizeof(tstrConnectCmd), NULL, 0, 0); + if(s8Ret != SOCK_ERR_NO_ERROR) + { + s8Ret = SOCK_ERR_INVALID; + } + } + return s8Ret; +} +/********************************************************************* +Function + send + +Description + +Return + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 5 June 2012 +*********************************************************************/ +sint16 send(SOCKET sock, void *pvSendBuffer, uint16 u16SendLength, uint16 flags) +{ +#ifdef ARDUINO + (void)flags; // Silence "unused" warning +#endif + sint16 s16Ret = SOCK_ERR_INVALID_ARG; + + if((sock >= 0) && (pvSendBuffer != NULL) && (u16SendLength <= SOCKET_BUFFER_MAX_LENGTH) && (gastrSockets[sock].bIsUsed == 1)) + { + uint16 u16DataOffset; + tstrSendCmd strSend; + uint8 u8Cmd; + + u8Cmd = SOCKET_CMD_SEND; + u16DataOffset = TCP_TX_PACKET_OFFSET; + + strSend.sock = sock; + strSend.u16DataSize = NM_BSP_B_L_16(u16SendLength); + strSend.u16SessionID = gastrSockets[sock].u16SessionID; + + if(sock >= TCP_SOCK_MAX) + { + u16DataOffset = UDP_TX_PACKET_OFFSET; + } + if(gastrSockets[sock].u8SSLFlags & SSL_FLAGS_ACTIVE) + { + u8Cmd = SOCKET_CMD_SSL_SEND; + u16DataOffset = gastrSockets[sock].u16DataOffset; +#ifdef ARDUINO + extern uint32 nmdrv_firm_ver; + + if (nmdrv_firm_ver < M2M_MAKE_VERSION(19, 4, 0)) { + // firmware 19.3.0 and older only works with this specific offset + u16DataOffset = SSL_TX_PACKET_OFFSET; + } +#endif + } + + s16Ret = SOCKET_REQUEST(u8Cmd|M2M_REQ_DATA_PKT, (uint8*)&strSend, sizeof(tstrSendCmd), pvSendBuffer, u16SendLength, u16DataOffset); + if(s16Ret != SOCK_ERR_NO_ERROR) + { + s16Ret = SOCK_ERR_BUFFER_FULL; + } + } + return s16Ret; +} +/********************************************************************* +Function + sendto + +Description + +Return + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 4 June 2012 +*********************************************************************/ +sint16 sendto(SOCKET sock, void *pvSendBuffer, uint16 u16SendLength, uint16 flags, struct sockaddr *pstrDestAddr, uint8 u8AddrLen) +{ +#ifdef ARDUINO + // Silence "unused" warning + (void)flags; + (void)u8AddrLen; +#endif + sint16 s16Ret = SOCK_ERR_INVALID_ARG; + + if((sock >= 0) && (pvSendBuffer != NULL) && (u16SendLength <= SOCKET_BUFFER_MAX_LENGTH) && (gastrSockets[sock].bIsUsed == 1)) + { + if(gastrSockets[sock].bIsUsed) + { + tstrSendCmd strSendTo; + + m2m_memset((uint8*)&strSendTo, 0, sizeof(tstrSendCmd)); + + strSendTo.sock = sock; + strSendTo.u16DataSize = NM_BSP_B_L_16(u16SendLength); + strSendTo.u16SessionID = gastrSockets[sock].u16SessionID; + + if(pstrDestAddr != NULL) + { + struct sockaddr_in *pstrAddr; + pstrAddr = (void*)pstrDestAddr; + + strSendTo.strAddr.u16Family = pstrAddr->sin_family; + strSendTo.strAddr.u16Port = pstrAddr->sin_port; + strSendTo.strAddr.u32IPAddr = pstrAddr->sin_addr.s_addr; + } + s16Ret = SOCKET_REQUEST(SOCKET_CMD_SENDTO|M2M_REQ_DATA_PKT, (uint8*)&strSendTo, sizeof(tstrSendCmd), + pvSendBuffer, u16SendLength, UDP_TX_PACKET_OFFSET); + + if(s16Ret != SOCK_ERR_NO_ERROR) + { + s16Ret = SOCK_ERR_BUFFER_FULL; + } + } + } + return s16Ret; +} +/********************************************************************* +Function + recv + +Description + +Return + + +Author + Ahmed Ezzat + +Version + 1.0 + 2.0 9 April 2013 --> Add timeout for recv operation. + +Date + 5 June 2012 +*********************************************************************/ +sint16 recv(SOCKET sock, void *pvRecvBuf, uint16 u16BufLen, uint32 u32Timeoutmsec) +{ + sint16 s16Ret = SOCK_ERR_INVALID_ARG; +#ifdef ARDUINO + if((sock >= 0) && /*(pvRecvBuf != NULL) && (u16BufLen != 0) &&*/ (gastrSockets[sock].bIsUsed == 1)) +#else + if((sock >= 0) && (pvRecvBuf != NULL) && (u16BufLen != 0) && (gastrSockets[sock].bIsUsed == 1)) +#endif + { + s16Ret = SOCK_ERR_NO_ERROR; + gastrSockets[sock].pu8UserBuffer = (uint8*)pvRecvBuf; + gastrSockets[sock].u16UserBufferSize = u16BufLen; + + if(!gastrSockets[sock].bIsRecvPending) + { + tstrRecvCmd strRecv; + uint8 u8Cmd = SOCKET_CMD_RECV; + + gastrSockets[sock].bIsRecvPending = 1; + if(gastrSockets[sock].u8SSLFlags & SSL_FLAGS_ACTIVE) + { + u8Cmd = SOCKET_CMD_SSL_RECV; + } + + /* Check the timeout value. */ + if(u32Timeoutmsec == 0) + strRecv.u32Timeoutmsec = 0xFFFFFFFF; + else + strRecv.u32Timeoutmsec = NM_BSP_B_L_32(u32Timeoutmsec); + strRecv.sock = sock; + strRecv.u16SessionID = gastrSockets[sock].u16SessionID; + + s16Ret = SOCKET_REQUEST(u8Cmd, (uint8*)&strRecv, sizeof(tstrRecvCmd), NULL , 0, 0); + if(s16Ret != SOCK_ERR_NO_ERROR) + { + s16Ret = SOCK_ERR_BUFFER_FULL; + } + } + } + return s16Ret; +} +/********************************************************************* +Function + close + +Description + +Return + None. + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 4 June 2012 +*********************************************************************/ +sint8 close(SOCKET sock) +{ + sint8 s8Ret = SOCK_ERR_INVALID_ARG; + M2M_INFO("Sock to delete <%d>\n", sock); + if(sock >= 0 && (gastrSockets[sock].bIsUsed == 1)) + { + uint8 u8Cmd = SOCKET_CMD_CLOSE; + tstrCloseCmd strclose; + strclose.sock = sock; + strclose.u16SessionID = gastrSockets[sock].u16SessionID; + + gastrSockets[sock].bIsUsed = 0; + gastrSockets[sock].u16SessionID =0; + + if(gastrSockets[sock].u8SSLFlags & SSL_FLAGS_ACTIVE) + { + u8Cmd = SOCKET_CMD_SSL_CLOSE; + } + s8Ret = SOCKET_REQUEST(u8Cmd, (uint8*)&strclose, sizeof(tstrCloseCmd), NULL,0, 0); + if(s8Ret != SOCK_ERR_NO_ERROR) + { + s8Ret = SOCK_ERR_INVALID; + } + m2m_memset((uint8*)&gastrSockets[sock], 0, sizeof(tstrSocket)); + } + return s8Ret; +} +/********************************************************************* +Function + recvfrom + +Description + +Return + + +Author + Ahmed Ezzat + +Version + 1.0 + 2.0 9 April 2013 --> Add timeout for recv operation. + +Date + 5 June 2012 +*********************************************************************/ +sint16 recvfrom(SOCKET sock, void *pvRecvBuf, uint16 u16BufLen, uint32 u32Timeoutmsec) +{ + sint16 s16Ret = SOCK_ERR_NO_ERROR; +#ifdef ARDUINO + if((sock >= 0) && /*(pvRecvBuf != NULL) && (u16BufLen != 0) &&*/ (gastrSockets[sock].bIsUsed == 1)) +#else + if((sock >= 0) && (pvRecvBuf != NULL) && (u16BufLen != 0) && (gastrSockets[sock].bIsUsed == 1)) +#endif + { + if(gastrSockets[sock].bIsUsed) + { + s16Ret = SOCK_ERR_NO_ERROR; + gastrSockets[sock].pu8UserBuffer = (uint8*)pvRecvBuf; + gastrSockets[sock].u16UserBufferSize = u16BufLen; + + if(!gastrSockets[sock].bIsRecvPending) + { + tstrRecvCmd strRecv; + + gastrSockets[sock].bIsRecvPending = 1; + + /* Check the timeout value. */ + if(u32Timeoutmsec == 0) + strRecv.u32Timeoutmsec = 0xFFFFFFFF; + else + strRecv.u32Timeoutmsec = NM_BSP_B_L_32(u32Timeoutmsec); + strRecv.sock = sock; + strRecv.u16SessionID = gastrSockets[sock].u16SessionID; + + s16Ret = SOCKET_REQUEST(SOCKET_CMD_RECVFROM, (uint8*)&strRecv, sizeof(tstrRecvCmd), NULL , 0, 0); + if(s16Ret != SOCK_ERR_NO_ERROR) + { + s16Ret = SOCK_ERR_BUFFER_FULL; + } + } + } + } + else + { + s16Ret = SOCK_ERR_INVALID_ARG; + } + return s16Ret; +} +/********************************************************************* +Function + nmi_inet_addr + +Description + +Return + Unsigned 32-bit integer representing the IP address in Network + byte order. + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 4 June 2012 +*********************************************************************/ +uint32 nmi_inet_addr(char *pcIpAddr) +{ + uint8 tmp; + uint32 u32IP = 0; + uint8 au8IP[4]; + uint8 c; + uint8 i, j; + + tmp = 0; + + for(i = 0; i < 4; ++i) + { + j = 0; + do + { + c = *pcIpAddr; + ++j; + if(j > 4) + { + return 0; + } + if(c == '.' || c == 0) + { + au8IP[i] = tmp; + tmp = 0; + } + else if(c >= '0' && c <= '9') + { + tmp = (tmp * 10) + (c - '0'); + } + else + { + return 0; + } + ++pcIpAddr; + } while(c != '.' && c != 0); + } + m2m_memcpy((uint8*)&u32IP, au8IP, 4); + return u32IP; +} +/********************************************************************* +Function + gethostbyname + +Description + +Return + None. + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 4 June 2012 +*********************************************************************/ +sint8 gethostbyname(uint8 * pcHostName) +{ + sint8 s8Err = SOCK_ERR_INVALID_ARG; + uint8 u8HostNameSize = (uint8)m2m_strlen(pcHostName); + if(u8HostNameSize <= HOSTNAME_MAX_SIZE) + { + s8Err = SOCKET_REQUEST(SOCKET_CMD_DNS_RESOLVE, (uint8*)pcHostName, u8HostNameSize + 1, NULL,0, 0); + } + return s8Err; +} +/********************************************************************* +Function + setsockopt + +Description + +Return + None. + +Author + Abdelrahman Diab + +Version + 1.0 + +Date + 9 September 2014 +*********************************************************************/ +static sint8 sslSetSockOpt(SOCKET sock, uint8 u8Opt, const void *pvOptVal, uint16 u16OptLen) +{ + sint8 s8Ret = SOCK_ERR_INVALID_ARG; + if(sock < TCP_SOCK_MAX) + { + if(gastrSockets[sock].u8SSLFlags & SSL_FLAGS_ACTIVE) + { + if(u8Opt == SO_SSL_BYPASS_X509_VERIF) + { + int optVal = *((int*)pvOptVal); + if(optVal) + { + gastrSockets[sock].u8SSLFlags |= SSL_FLAGS_BYPASS_X509; + } + else + { + gastrSockets[sock].u8SSLFlags &= ~SSL_FLAGS_BYPASS_X509; + } + s8Ret = SOCK_ERR_NO_ERROR; + } + else if(u8Opt == SO_SSL_ENABLE_SESSION_CACHING) + { + int optVal = *((int*)pvOptVal); + if(optVal) + { + gastrSockets[sock].u8SSLFlags |= SSL_FLAGS_CACHE_SESSION; + } + else + { + gastrSockets[sock].u8SSLFlags &= ~SSL_FLAGS_CACHE_SESSION; + } + s8Ret = SOCK_ERR_NO_ERROR; + } + else if(u8Opt == SO_SSL_ENABLE_SNI_VALIDATION) + { + int optVal = *((int*)pvOptVal); + if(optVal) + { + gastrSockets[sock].u8SSLFlags |= SSL_FLAGS_CHECK_SNI; + } + else + { + gastrSockets[sock].u8SSLFlags &= ~SSL_FLAGS_CHECK_SNI; + } + s8Ret = SOCK_ERR_NO_ERROR; + } + else if(u8Opt == SO_SSL_SNI) + { + if(u16OptLen < HOSTNAME_MAX_SIZE) + { + uint8 *pu8SNI = (uint8*)pvOptVal; + tstrSSLSetSockOptCmd strCmd; + + strCmd.sock = sock; + strCmd.u16SessionID = gastrSockets[sock].u16SessionID; + strCmd.u8Option = u8Opt; + strCmd.u32OptLen = u16OptLen; + m2m_memcpy(strCmd.au8OptVal, pu8SNI, HOSTNAME_MAX_SIZE); + + if(SOCKET_REQUEST(SOCKET_CMD_SSL_SET_SOCK_OPT, (uint8*)&strCmd, sizeof(tstrSSLSetSockOptCmd), + 0, 0, 0) == M2M_ERR_MEM_ALLOC) + { + s8Ret = SOCKET_REQUEST(SOCKET_CMD_SSL_SET_SOCK_OPT | M2M_REQ_DATA_PKT, + (uint8*)&strCmd, sizeof(tstrSSLSetSockOptCmd), 0, 0, 0); + } + s8Ret = SOCK_ERR_NO_ERROR; + } + else + { + M2M_ERR("SNI Exceeds Max Length\n"); + } + } + else + { + M2M_ERR("Unknown SSL Socket Option %d\n",u8Opt); + } + } + else + { + M2M_ERR("Not SSL Socket\n"); + } + } + return s8Ret; +} +/********************************************************************* +Function + setsockopt + +Description + +Return + None. + +Author + Abdelrahman Diab + +Version + 1.0 + +Date + 9 September 2014 +*********************************************************************/ +sint8 setsockopt(SOCKET sock, uint8 u8Level, uint8 option_name, + const void *option_value, uint16 u16OptionLen) +{ + sint8 s8Ret = SOCK_ERR_INVALID_ARG; + if((sock >= 0) && (option_value != NULL) && (gastrSockets[sock].bIsUsed == 1)) + { + if(u8Level == SOL_SSL_SOCKET) + { + s8Ret = sslSetSockOpt(sock, option_name, option_value, u16OptionLen); + } + else + { + uint8 u8Cmd = SOCKET_CMD_SET_SOCKET_OPTION; + tstrSetSocketOptCmd strSetSockOpt; + strSetSockOpt.u8Option=option_name; + strSetSockOpt.sock = sock; + strSetSockOpt.u32OptionValue = *(uint32*)option_value; + strSetSockOpt.u16SessionID = gastrSockets[sock].u16SessionID; + + s8Ret = SOCKET_REQUEST(u8Cmd, (uint8*)&strSetSockOpt, sizeof(tstrSetSocketOptCmd), NULL,0, 0); + if(s8Ret != SOCK_ERR_NO_ERROR) + { + s8Ret = SOCK_ERR_INVALID; + } + } + } + return s8Ret; +} +/********************************************************************* +Function + getsockopt + +Description + +Return + None. + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 24 August 2014 +*********************************************************************/ +sint8 getsockopt(SOCKET sock, uint8 u8Level, uint8 u8OptName, const void *pvOptValue, uint8* pu8OptLen) +{ +#ifdef ARDUINO + // Silence "unused" warning + (void)sock; + (void)u8Level; + (void)u8OptName; + (void)pvOptValue; + (void)pu8OptLen; +#endif + /* TBD */ + return M2M_SUCCESS; +} +/********************************************************************* +Function + m2m_ping_req + +Description + Send Ping request. + +Return + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + 4 June 2015 +*********************************************************************/ +sint8 m2m_ping_req(uint32 u32DstIP, uint8 u8TTL, tpfPingCb fpPingCb) +{ + sint8 s8Ret = M2M_ERR_INVALID_ARG; + + if((u32DstIP != 0) && (fpPingCb != NULL)) + { + tstrPingCmd strPingCmd; + + strPingCmd.u16PingCount = 1; + strPingCmd.u32DestIPAddr = u32DstIP; +#ifdef ARDUINO + strPingCmd.u32CmdPrivate = (uint32)(uintptr_t)(fpPingCb); +#else + strPingCmd.u32CmdPrivate = (uint32)(fpPingCb); +#endif + strPingCmd.u8TTL = u8TTL; + + s8Ret = SOCKET_REQUEST(SOCKET_CMD_PING, (uint8*)&strPingCmd, sizeof(tstrPingCmd), NULL, 0, 0); + } + return s8Ret; +} +/********************************************************************* +Function + sslEnableCertExpirationCheck + +Description + Enable/Disable TLS Certificate Expiration Check. + +Return + +Author + Ahmed Ezzat + +Version + 1.0 + +Date + +*********************************************************************/ +sint8 sslEnableCertExpirationCheck(tenuSslCertExpSettings enuValidationSetting) +{ + tstrSslCertExpSettings strSettings; + strSettings.u32CertExpValidationOpt = (uint32)enuValidationSetting; + return SOCKET_REQUEST(SOCKET_CMD_SSL_EXP_CHECK, (uint8*)&strSettings, sizeof(tstrSslCertExpSettings), NULL, 0, 0); +} \ No newline at end of file diff --git a/lib/WiFi101/src/socket/source/socket_internal.h b/lib/WiFi101/src/socket/source/socket_internal.h new file mode 100644 index 0000000..1904c23 --- /dev/null +++ b/lib/WiFi101/src/socket/source/socket_internal.h @@ -0,0 +1,71 @@ +/** + * + * \file + * + * \brief BSD compatible socket interface internal types. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ +#ifndef __SOCKET_INTERNAL_H__ +#define __SOCKET_INTERNAL_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +INCLUDES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +#include "socket/include/socket.h" +#include "socket/include/m2m_socket_host_if.h" + + +/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +FUNCTION PROTOTYPES +*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/ + +NMI_API void Socket_ReadSocketData(SOCKET sock, tstrSocketRecvMsg *pstrRecv,uint8 u8SocketMsg, + uint32 u32StartAddress,uint16 u16ReadCount); +#ifdef ARDUINO +NMI_API void Socket_ReadSocketData_Small(void); +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __SOCKET_H__ */ diff --git a/lib/WiFi101/src/spi_flash/include/spi_flash.h b/lib/WiFi101/src/spi_flash/include/spi_flash.h new file mode 100644 index 0000000..a85aa72 --- /dev/null +++ b/lib/WiFi101/src/spi_flash/include/spi_flash.h @@ -0,0 +1,233 @@ +/** + * + * \file + * + * \brief WINC1500 SPI Flash. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +/** \defgroup SPIFLASH Spi Flash + * @file spi_flash.h + * @brief This file describe SPI flash APIs, how to use it and limitations with each one. + * @section Example + * This example illustrates a complete guide of how to use these APIs. + * @code{.c} + #include "spi_flash.h" + + #define DATA_TO_REPLACE "THIS IS A NEW SECTOR IN FLASH" + + int main() + { + uint8 au8FlashContent[FLASH_SECTOR_SZ] = {0}; + uint32 u32FlashTotalSize = 0; + uint32 u32FlashOffset = 0; + + ret = m2m_wifi_download_mode(); + if(M2M_SUCCESS != ret) + { + printf("Unable to enter download mode\r\n"); + } + else + { + u32FlashTotalSize = spi_flash_get_size(); + } + + while((u32FlashTotalSize > u32FlashOffset) && (M2M_SUCCESS == ret)) + { + ret = spi_flash_read(au8FlashContent, u32FlashOffset, FLASH_SECTOR_SZ); + if(M2M_SUCCESS != ret) + { + printf("Unable to read SPI sector\r\n"); + break; + } + memcpy(au8FlashContent, DATA_TO_REPLACE, strlen(DATA_TO_REPLACE)); + + ret = spi_flash_erase(u32FlashOffset, FLASH_SECTOR_SZ); + if(M2M_SUCCESS != ret) + { + printf("Unable to erase SPI sector\r\n"); + break; + } + + ret = spi_flash_write(au8FlashContent, u32FlashOffset, FLASH_SECTOR_SZ); + if(M2M_SUCCESS != ret) + { + printf("Unable to write SPI sector\r\n"); + break; + } + u32FlashOffset += FLASH_SECTOR_SZ; + } + + if(M2M_SUCCESS == ret) + { + printf("Successful operations\r\n"); + } + else + { + printf("Failed operations\r\n"); + } + + while(1); + return M2M_SUCCESS; + } + * @endcode + */ + +#ifndef __SPI_FLASH_H__ +#define __SPI_FLASH_H__ +#include "common/include/nm_common.h" +#include "bus_wrapper/include/nm_bus_wrapper.h" +#include "driver/source/nmbus.h" +#include "driver/source/nmasic.h" + +#ifdef ARDUINO +#ifdef __cplusplus +extern "C" { +#endif +#endif + +/** + * @fn spi_flash_enable + * @brief Enable spi flash operations + * @version 1.0 + */ +sint8 spi_flash_enable(uint8 enable); +/** \defgroup SPIFLASHAPI Function + * @ingroup SPIFLASH + */ + + /** @defgroup SPiFlashGetFn spi_flash_get_size + * @ingroup SPIFLASHAPI + */ + /**@{*/ +/*! + * @fn uint32 spi_flash_get_size(void); + * @brief Returns with \ref uint32 value which is total flash size\n + * @note Returned value in Mb (Mega Bit). + * @return SPI flash size in case of success and a ZERO value in case of failure. + */ +uint32 spi_flash_get_size(void); + /**@}*/ + + /** @defgroup SPiFlashRead spi_flash_read + * @ingroup SPIFLASHAPI + */ + /**@{*/ +/*! + * @fn sint8 spi_flash_read(uint8 *, uint32, uint32); + * @brief Read a specified portion of data from SPI Flash.\n + * @param [out] pu8Buf + * Pointer to data buffer which will fill in with data in case of successful operation. + * @param [in] u32Addr + * Address (Offset) to read from at the SPI flash. + * @param [in] u32Sz + * Total size of data to be read in bytes + * @warning + * - Address (offset) plus size of data must not exceed flash size.\n + * - No firmware is required for reading from SPI flash.\n + * - In case of there is a running firmware, it is required to pause your firmware first + * before any trial to access SPI flash to avoid any racing between host and running firmware on bus using + * @ref m2m_wifi_download_mode + * @note + * - It is blocking function\n + * @sa m2m_wifi_download_mode, spi_flash_get_size + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + */ +sint8 spi_flash_read(uint8 *pu8Buf, uint32 u32Addr, uint32 u32Sz); + /**@}*/ + + /** @defgroup SPiFlashWrite spi_flash_write + * @ingroup SPIFLASHAPI + */ + /**@{*/ +/*! + * @fn sint8 spi_flash_write(uint8 *, uint32, uint32); + * @brief Write a specified portion of data to SPI Flash.\n + * @param [in] pu8Buf + * Pointer to data buffer which contains the required to be written. + * @param [in] u32Offset + * Address (Offset) to write at the SPI flash. + * @param [in] u32Sz + * Total number of size of data bytes + * @note + * - It is blocking function\n + * - It is user's responsibility to verify that data has been written successfully + * by reading data again and compare it with the original. + * @warning + * - Address (offset) plus size of data must not exceed flash size.\n + * - No firmware is required for writing to SPI flash.\n + * - In case of there is a running firmware, it is required to pause your firmware first + * before any trial to access SPI flash to avoid any racing between host and running firmware on bus using + * @ref m2m_wifi_download_mode. + * - Before writing to any section, it is required to erase it first. + * @sa m2m_wifi_download_mode, spi_flash_get_size, spi_flash_erase + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + + */ +sint8 spi_flash_write(uint8* pu8Buf, uint32 u32Offset, uint32 u32Sz); + /**@}*/ + + /** @defgroup SPiFlashErase spi_flash_erase + * @ingroup SPIFLASHAPI + */ + /**@{*/ +/*! + * @fn sint8 spi_flash_erase(uint32, uint32); + * @brief Erase a specified portion of SPI Flash.\n + * @param [in] u32Offset + * Address (Offset) to erase from the SPI flash. + * @param [in] u32Sz + * Size of SPI flash required to be erased. + * @note It is blocking function \n +* @warning +* - Address (offset) plus size of data must not exceed flash size.\n +* - No firmware is required for writing to SPI flash.\n + * - In case of there is a running firmware, it is required to pause your firmware first + * before any trial to access SPI flash to avoid any racing between host and running firmware on bus using + * @ref m2m_wifi_download_mode + * - It is blocking function\n + * @sa m2m_wifi_download_mode, spi_flash_get_size + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + + */ +sint8 spi_flash_erase(uint32 u32Offset, uint32 u32Sz); + /**@}*/ +#ifdef ARDUINO +#ifdef __cplusplus +} +#endif +#endif +#endif //__SPI_FLASH_H__ diff --git a/lib/WiFi101/src/spi_flash/include/spi_flash_map.h b/lib/WiFi101/src/spi_flash/include/spi_flash_map.h new file mode 100644 index 0000000..3b0da53 --- /dev/null +++ b/lib/WiFi101/src/spi_flash/include/spi_flash_map.h @@ -0,0 +1,245 @@ +/** + * + * \file + * + * \brief WINC1500 SPI Flash. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +/** +* @file spi_flash_map.h +* @brief This module contains spi flash CONTENT +* @author M.S.M +* @date 17 SEPT 2013 +* @version 1.0 +*/ +#ifndef __SPI_FLASH_MAP_H__ +#define __SPI_FLASH_MAP_H__ + +#define FLASH_MAP_VER_0 (0) +#define FLASH_MAP_VER_1 (1) +#define FLASH_MAP_VER_2 (2) +#define FLASH_MAP_VER_3 (3) + +#define FLASH_MAP_VERSION FLASH_MAP_VER_3 + +//#define DOWNLOAD_ROLLBACK +//#define OTA_GEN +#define _PROGRAM_POWER_SAVE_ + +/* =======*=======*=======*=======*======= + * General Sizes for Flash Memory + * =======*=======*=======*=======*======= + */ + +#define FLASH_START_ADDR (0UL) +/*! location :xxxK + * "S:xxxK" -means-> Size is :xxxK + */ + +/* + * Boot Firmware: which used to select which firmware to run + * + */ +#define M2M_BOOT_FIRMWARE_STARTING_ADDR (FLASH_START_ADDR) +#define M2M_BOOT_FIRMWARE_FLASH_SZ (FLASH_SECTOR_SZ) + +/* + * Control Section: which used by Boot firmware + * + */ +#define M2M_CONTROL_FLASH_OFFSET (M2M_BOOT_FIRMWARE_STARTING_ADDR + M2M_BOOT_FIRMWARE_FLASH_SZ) +#define M2M_CONTROL_FLASH_BKP_OFFSET (M2M_CONTROL_FLASH_OFFSET + FLASH_SECTOR_SZ) +#define M2M_CONTROL_FLASH_SEC_SZ (FLASH_SECTOR_SZ) +#define M2M_CONTROL_FLASH_TOTAL_SZ (FLASH_SECTOR_SZ * 2) + +/* + * LUT for PLL and TX Gain settings: + * + */ +#define M2M_PLL_FLASH_OFFSET (M2M_CONTROL_FLASH_OFFSET + M2M_CONTROL_FLASH_TOTAL_SZ) +#define M2M_PLL_FLASH_SZ (1024 * 1) +#define M2M_GAIN_FLASH_OFFSET (M2M_PLL_FLASH_OFFSET + M2M_PLL_FLASH_SZ) +#define M2M_GAIN_FLASH_SZ (M2M_CONFIG_SECT_TOTAL_SZ - M2M_PLL_FLASH_SZ) +#define M2M_CONFIG_SECT_TOTAL_SZ (FLASH_SECTOR_SZ) + +/* + * Certificate: + * + */ +#define M2M_TLS_ROOTCER_FLASH_OFFSET (M2M_PLL_FLASH_OFFSET + M2M_CONFIG_SECT_TOTAL_SZ) +#define M2M_TLS_ROOTCER_FLASH_SIZE (FLASH_SECTOR_SZ * 1) + +/* + * TLS Server Key Files + * + */ +#define M2M_TLS_SERVER_FLASH_OFFSET (M2M_TLS_ROOTCER_FLASH_OFFSET + M2M_TLS_ROOTCER_FLASH_SIZE) +#define M2M_TLS_SERVER_FLASH_SIZE (FLASH_SECTOR_SZ * 2) + +/* + * HTTP Files + * + */ +#define M2M_HTTP_MEM_FLASH_OFFSET (M2M_TLS_SERVER_FLASH_OFFSET + M2M_TLS_SERVER_FLASH_SIZE) +#define M2M_HTTP_MEM_FLASH_SZ (FLASH_SECTOR_SZ * 2) + +/* + * Saved Connection Parameters: + * + */ +#define M2M_CACHED_CONNS_FLASH_OFFSET (M2M_HTTP_MEM_FLASH_OFFSET + M2M_HTTP_MEM_FLASH_SZ) +#define M2M_CACHED_CONNS_FLASH_SZ (FLASH_SECTOR_SZ * 1) + +/* + * + * Common section size + */ + +#define M2M_COMMON_DATA_SEC \ + (\ + M2M_BOOT_FIRMWARE_FLASH_SZ + \ + M2M_CONTROL_FLASH_TOTAL_SZ + \ + M2M_CONFIG_SECT_TOTAL_SZ + \ + M2M_TLS_ROOTCER_FLASH_SIZE + \ + M2M_TLS_SERVER_FLASH_SIZE + \ + M2M_HTTP_MEM_FLASH_SZ + \ + M2M_CACHED_CONNS_FLASH_SZ \ + ) + +/* + * + * OTA image1 Offset + */ + +#define M2M_OTA_IMAGE1_OFFSET (M2M_CACHED_CONNS_FLASH_OFFSET + M2M_CACHED_CONNS_FLASH_SZ) +/* + * Firmware Offset + * + */ +#if (defined _FIRMWARE_)||(defined OTA_GEN) +#define M2M_FIRMWARE_FLASH_OFFSET (0UL) +#else +#if (defined DOWNLOAD_ROLLBACK) +#define M2M_FIRMWARE_FLASH_OFFSET (M2M_OTA_IMAGE2_OFFSET) +#else +#define M2M_FIRMWARE_FLASH_OFFSET (M2M_OTA_IMAGE1_OFFSET) +#endif +#endif +/* + * + * Firmware + */ +#define M2M_FIRMWARE_FLASH_SZ (236 * 1024UL) +/** + * + * OTA image Size + */ +#define OTA_IMAGE_SIZE (M2M_FIRMWARE_FLASH_SZ) +/** + * + * Flash Total size + */ +#define FLASH_IMAGE1_CONTENT_SZ (M2M_COMMON_DATA_SEC + OTA_IMAGE_SIZE) + +/** + * + * OTA image 2 offset + */ +#define M2M_OTA_IMAGE2_OFFSET (FLASH_IMAGE1_CONTENT_SZ) + +/* + * App(Cortus App 4M): App. which runs over firmware + * + */ +#define M2M_APP_4M_MEM_FLASH_SZ (FLASH_SECTOR_SZ * 16) +#define M2M_APP_4M_MEM_FLASH_OFFSET (FLASH_4M_TOTAL_SZ - M2M_APP_4M_MEM_FLASH_SZ) +#define M2M_APP_8M_MEM_FLASH_OFFSET (M2M_OTA_IMAGE2_OFFSET + OTA_IMAGE_SIZE) +#define M2M_APP_8M_MEM_FLASH_SZ (FLASH_SECTOR_SZ * 32) +#define M2M_APP_OTA_MEM_FLASH_OFFSET (M2M_APP_8M_MEM_FLASH_OFFSET + M2M_APP_8M_MEM_FLASH_SZ) + +/* Check if total size of content + * don't exceed total size of memory allowed + **/ +#if (M2M_COMMON_DATA_SEC + (OTA_IMAGE_SIZE *2)> FLASH_4M_TOTAL_SZ) +#error "Excced 4M Flash Size" +#endif /* (FLASH_CONTENT_SZ > FLASH_TOTAL_SZ) */ + + +#endif /* __SPI_FLASH_MAP_H__ */ diff --git a/lib/WiFi101/src/spi_flash/source/spi_flash.c b/lib/WiFi101/src/spi_flash/source/spi_flash.c new file mode 100644 index 0000000..12eff59 --- /dev/null +++ b/lib/WiFi101/src/spi_flash/source/spi_flash.c @@ -0,0 +1,770 @@ +/** + * + * \file + * + * \brief WINC1500 SPI Flash. + * + * Copyright (c) 2016-2017 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifdef PROFILING +#include "windows.h" +#endif +#include "spi_flash/include/spi_flash.h" +#define DUMMY_REGISTER (0x1084) + +#ifdef ARDUINO +#define u32(x) ((uint32)x) +#endif + +#define TIMEOUT (-1) /*MS*/ + +//#define DISABLE_UNSED_FLASH_FUNCTIONS + +#define FLASH_BLOCK_SIZE (32UL * 1024) +/*!> 16); + cmd[2] = (uint8)(u32FlashAdr >> 8); + cmd[3] = (uint8)(u32FlashAdr); + cmd[4] = 0xA5; + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, u32Sz); +#ifdef ARDUINO + ret += nm_write_reg(SPI_FLASH_BUF1, u32(cmd[0])|u32(cmd[1]<<8)|u32(cmd[2]<<16)|u32(cmd[3]<<24)); +#else + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]|(cmd[1]<<8)|(cmd[2]<<16)|(cmd[3]<<24)); +#endif + ret += nm_write_reg(SPI_FLASH_BUF2, cmd[4]); + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x1f); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, u32MemAdr); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 5 | (1<<7)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val); + if(M2M_SUCCESS != ret) break; + } + while(val != 1); + + return ret; +} + +/** +* @fn spi_flash_sector_erase +* @brief Erase sector (4KB) +* @param[IN] u32FlashAdr +* Any memory address within the sector +* @return Status of execution +* @note Compatible with MX25L6465E and should be working with other types +* @author M. Abdelmawla +* @version 1.0 +*/ +static sint8 spi_flash_sector_erase(uint32 u32FlashAdr) +{ + uint8 cmd[4]; + uint32 val = 0; + sint8 ret = M2M_SUCCESS; + + cmd[0] = 0x20; + cmd[1] = (uint8)(u32FlashAdr >> 16); + cmd[2] = (uint8)(u32FlashAdr >> 8); + cmd[3] = (uint8)(u32FlashAdr); + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0); +#ifdef ARDUINO + ret += nm_write_reg(SPI_FLASH_BUF1, u32(cmd[0])|u32(cmd[1]<<8)|u32(cmd[2]<<16)|u32(cmd[3]<<24)); +#else + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]|(cmd[1]<<8)|(cmd[2]<<16)|(cmd[3]<<24)); +#endif + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x0f); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 4 | (1<<7)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val); + if(M2M_SUCCESS != ret) break; + } + while(val != 1); + + return ret; +} + +/** +* @fn spi_flash_write_enable +* @brief Send write enable command to SPI flash +* @return Status of execution +* @note Compatible with MX25L6465E and should be working with other types +* @author M. Abdelmawla +* @version 1.0 +*/ +static sint8 spi_flash_write_enable(void) +{ + uint8 cmd[1]; + uint32 val = 0; + sint8 ret = M2M_SUCCESS; + + cmd[0] = 0x06; + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0); + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]); + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val); + if(M2M_SUCCESS != ret) break; + } + while(val != 1); + + return ret; +} + +/** +* @fn spi_flash_write_disable +* @brief Send write disable command to SPI flash +* @note Compatible with MX25L6465E and should be working with other types +* @author M. Abdelmawla +* @version 1.0 +*/ +static sint8 spi_flash_write_disable(void) +{ + uint8 cmd[1]; + uint32 val = 0; + sint8 ret = M2M_SUCCESS; + cmd[0] = 0x04; + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0); + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]); + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val); + if(M2M_SUCCESS != ret) break; + } + while(val != 1); + + return ret; +} + +/** +* @fn spi_flash_page_program +* @brief Write data (less than page size) from cortus memory to SPI flash +* @param[IN] u32MemAdr +* Cortus data address. It must be set to its AHB access address +* @param[IN] u32FlashAdr +* Address to write to at the SPI flash +* @param[IN] u32Sz +* Data size +* @note Compatible with MX25L6465E and should be working with other types +* @author M. Abdelmawla +* @version 1.0 +*/ +static sint8 spi_flash_page_program(uint32 u32MemAdr, uint32 u32FlashAdr, uint32 u32Sz) +{ + uint8 cmd[4]; + uint32 val = 0; + sint8 ret = M2M_SUCCESS; + + cmd[0] = 0x02; + cmd[1] = (uint8)(u32FlashAdr >> 16); + cmd[2] = (uint8)(u32FlashAdr >> 8); + cmd[3] = (uint8)(u32FlashAdr); + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0); +#ifdef ARDUINO + ret += nm_write_reg(SPI_FLASH_BUF1, u32(cmd[0])|u32(cmd[1]<<8)|u32(cmd[2]<<16)|u32(cmd[3]<<24)); +#else + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]|(cmd[1]<<8)|(cmd[2]<<16)|(cmd[3]<<24)); +#endif + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x0f); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, u32MemAdr); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 4 | (1<<7) | ((u32Sz & 0xfffff) << 8)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val); + if(M2M_SUCCESS != ret) break; + } + while(val != 1); + + return ret; +} + +/** +* @fn spi_flash_read_internal +* @brief Read from data from SPI flash +* @param[OUT] pu8Buf +* Pointer to data buffer +* @param[IN] u32Addr +* Address to read from at the SPI flash +* @param[IN] u32Sz +* Data size +* @note Data size must be < 64KB (limitation imposed by the bus wrapper) +* @author M. Abdelmawla +* @version 1.0 +*/ +static sint8 spi_flash_read_internal(uint8 *pu8Buf, uint32 u32Addr, uint32 u32Sz) +{ + sint8 ret = M2M_SUCCESS; + /* read size must be < 64KB */ + ret = spi_flash_load_to_cortus_mem(HOST_SHARE_MEM_BASE, u32Addr, u32Sz); + if(M2M_SUCCESS != ret) goto ERR; + ret = nm_read_block(HOST_SHARE_MEM_BASE, pu8Buf, u32Sz); +ERR: + return ret; +} + +/** +* @fn spi_flash_pp +* @brief Program data of size less than a page (256 bytes) at the SPI flash +* @param[IN] u32Offset +* Address to write to at the SPI flash +* @param[IN] pu8Buf +* Pointer to data buffer +* @param[IN] u32Sz +* Data size +* @return Status of execution +* @author M. Abdelmawla +* @version 1.0 +*/ +static sint8 spi_flash_pp(uint32 u32Offset, uint8 *pu8Buf, uint16 u16Sz) +{ + sint8 ret = M2M_SUCCESS; + uint8 tmp; + spi_flash_write_enable(); + /* use shared packet memory as temp mem */ + ret += nm_write_block(HOST_SHARE_MEM_BASE, pu8Buf, u16Sz); + ret += spi_flash_page_program(HOST_SHARE_MEM_BASE, u32Offset, u16Sz); + ret += spi_flash_read_status_reg(&tmp); + do + { + if(ret != M2M_SUCCESS) goto ERR; + ret += spi_flash_read_status_reg(&tmp); + }while(tmp & 0x01); + ret += spi_flash_write_disable(); +ERR: + return ret; +} + +/** +* @fn spi_flash_rdid +* @brief Read SPI Flash ID +* @return SPI FLash ID +* @author M.S.M +* @version 1.0 +*/ +static uint32 spi_flash_rdid(void) +{ + unsigned char cmd[1]; + uint32 reg = 0; + uint32 cnt = 0; + sint8 ret = M2M_SUCCESS; + + cmd[0] = 0x9f; + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, 4); + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]); + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x1); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, DUMMY_REGISTER); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)®); + if(M2M_SUCCESS != ret) break; + if(++cnt > 500) + { + ret = M2M_ERR_INIT; + break; + } + } + while(reg != 1); + reg = (M2M_SUCCESS == ret)?(nm_read_reg(DUMMY_REGISTER)):(0); + M2M_PRINT("Flash ID %x \n",(unsigned int)reg); + return reg; +} + +/** +* @fn spi_flash_unlock +* @brief Unlock SPI Flash +* @author M.S.M +* @version 1.0 +*/ +#if 0 +static void spi_flash_unlock(void) +{ + uint8 tmp; + tmp = spi_flash_read_security_reg(); + spi_flash_clear_security_flags(); + if(tmp & 0x80) + { + spi_flash_write_enable(); + spi_flash_gang_unblock(); + } +} +#endif +static void spi_flash_enter_low_power_mode(void) { + volatile unsigned long tmp; + unsigned char* cmd = (unsigned char*) &tmp; + + cmd[0] = 0xb9; + + nm_write_reg(SPI_FLASH_DATA_CNT, 0); + nm_write_reg(SPI_FLASH_BUF1, cmd[0]); + nm_write_reg(SPI_FLASH_BUF_DIR, 0x1); + nm_write_reg(SPI_FLASH_DMA_ADDR, 0); + nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7)); + while(nm_read_reg(SPI_FLASH_TR_DONE) != 1); +} + + +static void spi_flash_leave_low_power_mode(void) { + volatile unsigned long tmp; + unsigned char* cmd = (unsigned char*) &tmp; + + cmd[0] = 0xab; + + nm_write_reg(SPI_FLASH_DATA_CNT, 0); + nm_write_reg(SPI_FLASH_BUF1, cmd[0]); + nm_write_reg(SPI_FLASH_BUF_DIR, 0x1); + nm_write_reg(SPI_FLASH_DMA_ADDR, 0); + nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7)); + while(nm_read_reg(SPI_FLASH_TR_DONE) != 1); +} +/*********************************************/ +/* GLOBAL FUNCTIONS */ +/*********************************************/ +/** + * @fn spi_flash_enable + * @brief Enable spi flash operations + * @author M. Abdelmawla + * @version 1.0 + */ +sint8 spi_flash_enable(uint8 enable) +{ + sint8 s8Ret = M2M_SUCCESS; + if(REV(nmi_get_chipid()) >= REV_3A0) { + uint32 u32Val; + + /* Enable pinmux to SPI flash. */ + s8Ret = nm_read_reg_with_ret(0x1410, &u32Val); + if(s8Ret != M2M_SUCCESS) { + goto ERR1; + } + /* GPIO15/16/17/18 */ + u32Val &= ~((0x7777ul) << 12); + u32Val |= ((0x1111ul) << 12); + nm_write_reg(0x1410, u32Val); + if(enable) { + spi_flash_leave_low_power_mode(); + } else { + spi_flash_enter_low_power_mode(); + } + /* Disable pinmux to SPI flash to minimize leakage. */ + u32Val &= ~((0x7777ul) << 12); + u32Val |= ((0x0010ul) << 12); + nm_write_reg(0x1410, u32Val); + } +ERR1: + return s8Ret; +} +/** +* @fn spi_flash_read +* @brief Read from data from SPI flash +* @param[OUT] pu8Buf +* Pointer to data buffer +* @param[IN] u32offset +* Address to read from at the SPI flash +* @param[IN] u32Sz +* Data size +* @return Status of execution +* @note Data size is limited by the SPI flash size only +* @author M. Abdelmawla +* @version 1.0 +*/ +sint8 spi_flash_read(uint8 *pu8Buf, uint32 u32offset, uint32 u32Sz) +{ + sint8 ret = M2M_SUCCESS; + if(u32Sz > FLASH_BLOCK_SIZE) + { + do + { + ret = spi_flash_read_internal(pu8Buf, u32offset, FLASH_BLOCK_SIZE); + if(M2M_SUCCESS != ret) goto ERR; + u32Sz -= FLASH_BLOCK_SIZE; + u32offset += FLASH_BLOCK_SIZE; + pu8Buf += FLASH_BLOCK_SIZE; + } while(u32Sz > FLASH_BLOCK_SIZE); + } + + ret = spi_flash_read_internal(pu8Buf, u32offset, u32Sz); + +ERR: + return ret; +} + +/** +* @fn spi_flash_write +* @brief Proram SPI flash +* @param[IN] pu8Buf +* Pointer to data buffer +* @param[IN] u32Offset +* Address to write to at the SPI flash +* @param[IN] u32Sz +* Data size +* @return Status of execution +* @author M. Abdelmawla +* @version 1.0 +*/ +sint8 spi_flash_write(uint8* pu8Buf, uint32 u32Offset, uint32 u32Sz) +{ +#ifdef PROFILING + uint32 t1 = 0; + uint32 percent =0; + uint32 tpercent =0; +#endif + sint8 ret = M2M_SUCCESS; + uint32 u32wsz; + uint32 u32off; + uint32 u32Blksz; + u32Blksz = FLASH_PAGE_SZ; + u32off = u32Offset % u32Blksz; +#ifdef PROFILING + tpercent = (u32Sz/u32Blksz)+((u32Sz%u32Blksz)>0); + t1 = GetTickCount(); + M2M_PRINT(">Start programming...\r\n"); +#endif + if(u32Sz<=0) + { + M2M_ERR("Data size = %d",(int)u32Sz); + ret = M2M_ERR_FAIL; + goto ERR; + } + + if (u32off)/*first part of data in the address page*/ + { + u32wsz = u32Blksz - u32off; + if(spi_flash_pp(u32Offset, pu8Buf, (uint16)BSP_MIN(u32Sz, u32wsz))!=M2M_SUCCESS) + { + ret = M2M_ERR_FAIL; + goto ERR; + } + if (u32Sz < u32wsz) goto EXIT; + pu8Buf += u32wsz; + u32Offset += u32wsz; + u32Sz -= u32wsz; + } + while (u32Sz > 0) + { + u32wsz = BSP_MIN(u32Sz, u32Blksz); + + /*write complete page or the remaining data*/ + if(spi_flash_pp(u32Offset, pu8Buf, (uint16)u32wsz)!=M2M_SUCCESS) + { + ret = M2M_ERR_FAIL; + goto ERR; + } + pu8Buf += u32wsz; + u32Offset += u32wsz; + u32Sz -= u32wsz; +#ifdef PROFILING + percent++; + printf("\r>Complete Percentage = %d%%.\r",((percent*100)/tpercent)); +#endif + } +EXIT: +#ifdef PROFILING + M2M_PRINT("\rDone\t\t\t\t\t\t"); + M2M_PRINT("\n#Programming time = %f sec\n\r",(GetTickCount() - t1)/1000.0); +#endif +ERR: + return ret; +} + +/** +* @fn spi_flash_erase +* @brief Erase from data from SPI flash +* @param[IN] u32Offset +* Address to write to at the SPI flash +* @param[IN] u32Sz +* Data size +* @return Status of execution +* @note Data size is limited by the SPI flash size only +* @author M. Abdelmawla +* @version 1.0 +*/ +sint8 spi_flash_erase(uint32 u32Offset, uint32 u32Sz) +{ + uint32 i = 0; + sint8 ret = M2M_SUCCESS; + uint8 tmp = 0; +#ifdef PROFILING + uint32 t; + t = GetTickCount(); +#endif + M2M_PRINT("\r\n>Start erasing...\r\n"); + for(i = u32Offset; i < (u32Sz +u32Offset); i += (16*FLASH_PAGE_SZ)) + { + ret += spi_flash_write_enable(); + ret += spi_flash_read_status_reg(&tmp); + ret += spi_flash_sector_erase(i + 10); + ret += spi_flash_read_status_reg(&tmp); + do + { + if(ret != M2M_SUCCESS) goto ERR; + ret += spi_flash_read_status_reg(&tmp); + }while(tmp & 0x01); + + } + M2M_PRINT("Done\r\n"); +#ifdef PROFILING + M2M_PRINT("#Erase time = %f sec\n", (GetTickCount()-t)/1000.0); +#endif +ERR: + return ret; +} + +/** +* @fn spi_flash_get_size +* @brief Get size of SPI Flash +* @return Size of Flash +* @author M.S.M +* @version 1.0 +*/ +uint32 spi_flash_get_size(void) +{ + uint32 u32FlashId = 0, u32FlashPwr = 0; + static uint32 gu32InernalFlashSize= 0; + + if(!gu32InernalFlashSize) + { + u32FlashId = spi_flash_rdid();//spi_flash_probe(); + if(u32FlashId != 0xffffffff) + { + /*flash size is the third byte from the FLASH RDID*/ + u32FlashPwr = ((u32FlashId>>16)&0xff) - 0x11; /*2MBIT is the min*/ + /*That number power 2 to get the flash size*/ + gu32InernalFlashSize = 1<= 0) { + _info[sock].state = SOCKET_STATE_IDLE; + _info[sock].parent = -1; + } + + return sock; +} + +sint8 WiFiSocketClass::bind(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen) +{ + if (::bind(sock, pstrAddr, u8AddrLen) < 0) { + return 0; + } + + _info[sock].state = SOCKET_STATE_BINDING; + + unsigned long start = millis(); + + while (_info[sock].state == SOCKET_STATE_BINDING && millis() - start < 2000) { + m2m_wifi_handle_events(NULL); + } + + if (_info[sock].state != SOCKET_STATE_BOUND) { + _info[sock].state = SOCKET_STATE_IDLE; + return 0; + } + + _info[sock].recvMsg.s16BufferSize = 0; + if (sock < TCP_SOCK_MAX) { + // TCP + } else { + // UDP + recvfrom(sock, NULL, 0, 0); + } + + return 1; +} + +sint8 WiFiSocketClass::listen(SOCKET sock, uint8 backlog) +{ + if (::listen(sock, backlog) < 0) { + return 0; + } + + _info[sock].state = SOCKET_STATE_LISTEN; + + unsigned long start = millis(); + + while (_info[sock].state == SOCKET_STATE_LISTEN && millis() - start < 2000) { + m2m_wifi_handle_events(NULL); + } + + if (_info[sock].state != SOCKET_STATE_LISTENING) { + _info[sock].state = SOCKET_STATE_IDLE; + return 0; + } + + return 1; +} + +sint8 WiFiSocketClass::setopt(SOCKET socket, uint8 u8Level, uint8 option_name, const void *option_value, uint16 u16OptionLen) +{ + return setsockopt(socket, u8Level, option_name, option_value, u16OptionLen); +} + +sint8 WiFiSocketClass::connect(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen) +{ + if (::connect(sock, pstrAddr, u8AddrLen) < 0) { + return 0; + } + + _info[sock].state = SOCKET_STATE_CONNECTING; + + unsigned long start = millis(); + + while (_info[sock].state == SOCKET_STATE_CONNECTING && millis() - start < 20000) { + m2m_wifi_handle_events(NULL); + } + + if (_info[sock].state != SOCKET_STATE_CONNECTED) { + _info[sock].state = SOCKET_STATE_IDLE; + return 0; + } + + _info[sock].recvMsg.s16BufferSize = 0; + _info[sock].recvMsg.strRemoteAddr.sin_port = ((struct sockaddr_in*)pstrAddr)->sin_port; + _info[sock].recvMsg.strRemoteAddr.sin_addr.s_addr = ((struct sockaddr_in*)pstrAddr)->sin_addr.s_addr; + recv(sock, NULL, 0, 0); + + return 1; +} + +uint8 WiFiSocketClass::connected(SOCKET sock) +{ + m2m_wifi_handle_events(NULL); + + return (_info[sock].state == SOCKET_STATE_CONNECTED); +} + +uint8 WiFiSocketClass::listening(SOCKET sock) +{ + m2m_wifi_handle_events(NULL); + + return (_info[sock].state == SOCKET_STATE_LISTENING); +} + +uint8 WiFiSocketClass::bound(SOCKET sock) +{ + m2m_wifi_handle_events(NULL); + + return (_info[sock].state == SOCKET_STATE_BOUND); +} + +int WiFiSocketClass::available(SOCKET sock) +{ + m2m_wifi_handle_events(NULL); + + if (_info[sock].state != SOCKET_STATE_CONNECTED && _info[sock].state != SOCKET_STATE_BOUND) { + return 0; + } + + return (_info[sock].buffer.length + _info[sock].recvMsg.s16BufferSize); +} + +int WiFiSocketClass::peek(SOCKET sock) +{ + m2m_wifi_handle_events(NULL); + + if (_info[sock].state != SOCKET_STATE_CONNECTED && _info[sock].state != SOCKET_STATE_BOUND) { + return -1; + } + + if (available(sock) == 0) { + return -1; + } + + if (_info[sock].buffer.length == 0 && _info[sock].recvMsg.s16BufferSize) { + if (!fillRecvBuffer(sock)) { + return -1; + } + } + + return *_info[sock].buffer.head; +} + +int WiFiSocketClass::read(SOCKET sock, uint8_t* buf, size_t size) +{ + m2m_wifi_handle_events(NULL); + + if (_info[sock].state != SOCKET_STATE_CONNECTED && _info[sock].state != SOCKET_STATE_BOUND) { + return 0; + } + + int avail = available(sock); + + if (avail <= 0) { + return 0; + } + + if ((int)size > avail) { + size = avail; + } + + int bytesRead = 0; + + while (size) { + if (_info[sock].buffer.length == 0 && _info[sock].recvMsg.s16BufferSize) { + if (!fillRecvBuffer(sock)) { + break; + } + } + + int toCopy = size; + + if (toCopy > _info[sock].buffer.length) { + toCopy = _info[sock].buffer.length; + } + + memcpy(buf, _info[sock].buffer.head, toCopy); + _info[sock].buffer.head += toCopy; + _info[sock].buffer.length -= toCopy; + + buf += toCopy; + size -= toCopy; + bytesRead += toCopy; + } + + if (_info[sock].buffer.length == 0 && _info[sock].recvMsg.s16BufferSize == 0) { + if (sock < TCP_SOCK_MAX) { + // TCP + recv(sock, NULL, 0, 0); + } else { + // UDP + recvfrom(sock, NULL, 0, 0); + } + m2m_wifi_handle_events(NULL); + } + + return bytesRead; +} + +IPAddress WiFiSocketClass::remoteIP(SOCKET sock) +{ + return _info[sock].recvMsg.strRemoteAddr.sin_addr.s_addr; +} + +uint16_t WiFiSocketClass::remotePort(SOCKET sock) +{ + return _info[sock].recvMsg.strRemoteAddr.sin_port; +} + +size_t WiFiSocketClass::write(SOCKET sock, const uint8_t *buf, size_t size) +{ + m2m_wifi_handle_events(NULL); + + if (_info[sock].state != SOCKET_STATE_CONNECTED) { + return 0; + } + +#ifdef CONF_PERIPH + // Network led ON (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO16, 0); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO5, 0); +#endif + + sint16 err; + + while ((err = send(sock, (void *)buf, size, 0)) < 0) { + // Exit on fatal error, retry if buffer not ready. + if (err != SOCK_ERR_BUFFER_FULL) { + size = 0; + break; + } else if (hif_receive_blocked) { + size = 0; + break; + } + m2m_wifi_handle_events(NULL); + } + +#ifdef CONF_PERIPH + // Network led OFF (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO16, 1); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO5, 1); +#endif + + return size; +} + +sint16 WiFiSocketClass::sendto(SOCKET sock, void *pvSendBuffer, uint16 u16SendLength, uint16 flags, struct sockaddr *pstrDestAddr, uint8 u8AddrLen) +{ + m2m_wifi_handle_events(NULL); + + if (_info[sock].state != SOCKET_STATE_BOUND) { + return -1; + } + + if (memcmp(&_info[sock]._lastSendtoAddr, pstrDestAddr, sizeof(_info[sock]._lastSendtoAddr)) != 0) { + memcpy(&_info[sock]._lastSendtoAddr, pstrDestAddr, sizeof(_info[sock]._lastSendtoAddr)); + + return ::sendto(sock, pvSendBuffer, u16SendLength, flags, pstrDestAddr, u8AddrLen); + } else { + return ::send(sock, pvSendBuffer, u16SendLength, 0); + } +} + +sint8 WiFiSocketClass::close(SOCKET sock) +{ + m2m_wifi_handle_events(NULL); + + if (_info[sock].state == SOCKET_STATE_CONNECTED || _info[sock].state == SOCKET_STATE_BOUND) { + if (_info[sock].recvMsg.s16BufferSize > 0) { + _info[sock].recvMsg.s16BufferSize = 0; + + // flush any data not processed + hif_receive(0, NULL, 0, 1); + } + } + + _info[sock].state = SOCKET_STATE_INVALID; + _info[sock].parent = -1; + + if (_info[sock].buffer.data != NULL) { + free(_info[sock].buffer.data); + } + _info[sock].buffer.data = NULL; + _info[sock].buffer.head = NULL; + _info[sock].buffer.length = 0; + _info[sock].recvMsg.s16BufferSize = 0; + memset(&_info[sock]._lastSendtoAddr, 0x00, sizeof(_info[sock]._lastSendtoAddr)); + + return ::close(sock); +} + +int WiFiSocketClass::hasParent(SOCKET sock, SOCKET child) +{ + if (_info[child].parent != sock) { + return 0; + } + + return 1; +} + +SOCKET WiFiSocketClass::accepted(SOCKET sock) +{ + m2m_wifi_handle_events(NULL); + + for (SOCKET s = 0; s < TCP_SOCK_MAX; s++) { + if (_info[s].parent == sock && _info[s].state == SOCKET_STATE_ACCEPTED) { + _info[s].state = SOCKET_STATE_CONNECTED; + + _info[s].recvMsg.s16BufferSize = 0; + recv(s, NULL, 0, 0); + + return s; + } + } + + return -1; +} + +void WiFiSocketClass::eventCallback(SOCKET sock, uint8 u8Msg, void *pvMsg) +{ + WiFiSocket.handleEvent(sock, u8Msg, pvMsg); +} + +void WiFiSocketClass::handleEvent(SOCKET sock, uint8 u8Msg, void *pvMsg) +{ + switch (u8Msg) { + /* Socket bind. */ + case SOCKET_MSG_BIND: { + tstrSocketBindMsg *pstrBind = (tstrSocketBindMsg *)pvMsg; + + if (pstrBind && pstrBind->status == 0) { + _info[sock].state = SOCKET_STATE_BOUND; + } else { + _info[sock].state = SOCKET_STATE_IDLE; + } + } + break; + + /* Socket listen. */ + case SOCKET_MSG_LISTEN: { + tstrSocketListenMsg *pstrListen = (tstrSocketListenMsg *)pvMsg; + + if (pstrListen && pstrListen->status == 0) { + _info[sock].state = SOCKET_STATE_LISTENING; + } else { + _info[sock].state = SOCKET_STATE_IDLE; + } + } + break; + + /* Socket accept. */ + case SOCKET_MSG_ACCEPT: { + tstrSocketAcceptMsg *pstrAccept = (tstrSocketAcceptMsg*)pvMsg; + + if (pstrAccept && pstrAccept->sock > -1) { + _info[pstrAccept->sock].state = SOCKET_STATE_ACCEPTED; + _info[pstrAccept->sock].parent = sock; + _info[pstrAccept->sock].recvMsg.strRemoteAddr = pstrAccept->strAddr; + } + } + break; + + /* Socket connected. */ + case SOCKET_MSG_CONNECT: { + tstrSocketConnectMsg *pstrConnect = (tstrSocketConnectMsg *)pvMsg; + + if (pstrConnect && pstrConnect->s8Error >= 0) { + _info[sock].state = SOCKET_STATE_CONNECTED; + } else { + _info[sock].state = SOCKET_STATE_IDLE; + } + } + break; + + /* Socket data received. */ + case SOCKET_MSG_RECV: + case SOCKET_MSG_RECVFROM: { + tstrSocketRecvMsg *pstrRecvMsg = (tstrSocketRecvMsg *)pvMsg; + +#ifdef CONF_PERIPH + // Network led ON (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO16, 0); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO5, 0); +#endif + + if (pstrRecvMsg->s16BufferSize <= 0) { + close(sock); + } else if (_info[sock].state == SOCKET_STATE_CONNECTED || _info[sock].state == SOCKET_STATE_BOUND) { + _info[sock].recvMsg.pu8Buffer = pstrRecvMsg->pu8Buffer; + _info[sock].recvMsg.s16BufferSize = pstrRecvMsg->s16BufferSize; + if (sock < TCP_SOCK_MAX) { + // TCP + } else { + // UDP + _info[sock].recvMsg.strRemoteAddr = pstrRecvMsg->strRemoteAddr; + } + + fillRecvBuffer(sock); + } else { + // not connected or bound, discard data + hif_receive(0, NULL, 0, 1); + } + +#ifdef CONF_PERIPH + // Network led OFF (rev A then rev B). + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO16, 1); + m2m_periph_gpio_set_val(M2M_PERIPH_GPIO5, 1); +#endif + } + break; + + /* Socket data sent. */ + case SOCKET_MSG_SEND: { + // sint16 *s16Sent = (sint16 *)pvMsg; + } + break; + + default: + break; + } +} + +int WiFiSocketClass::fillRecvBuffer(SOCKET sock) +{ + if (_info[sock].buffer.data == NULL) { + _info[sock].buffer.data = (uint8_t*)malloc(SOCKET_BUFFER_SIZE); + _info[sock].buffer.head = _info[sock].buffer.data; + _info[sock].buffer.length = 0; + } + + int size = _info[sock].recvMsg.s16BufferSize; + + if (size > SOCKET_BUFFER_SIZE) { + size = SOCKET_BUFFER_SIZE; + } + + uint8 lastTransfer = ((sint16)size == _info[sock].recvMsg.s16BufferSize); + + if (hif_receive(_info[sock].recvMsg.pu8Buffer, _info[sock].buffer.data, (sint16)size, lastTransfer) != M2M_SUCCESS) { + return 0; + } + + _info[sock].buffer.head = _info[sock].buffer.data; + _info[sock].buffer.length = size; + _info[sock].recvMsg.pu8Buffer += size; + _info[sock].recvMsg.s16BufferSize -= size; + + return 1; +} + +WiFiSocketClass WiFiSocket; diff --git a/lib/WiFi101/src/utility/WiFiSocket.h b/lib/WiFi101/src/utility/WiFiSocket.h new file mode 100644 index 0000000..28814f7 --- /dev/null +++ b/lib/WiFi101/src/utility/WiFiSocket.h @@ -0,0 +1,77 @@ +/* + WiFiSocket.h - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIFISOCKET_H +#define WIFISOCKET_H + +extern "C" { + #include "socket/include/socket.h" + #include "socket/include/m2m_socket_host_if.h" +} + +#include +#include + +class WiFiSocketClass { +public: + WiFiSocketClass(); + virtual ~WiFiSocketClass(); + + SOCKET create(uint16 u16Domain, uint8 u8Type, uint8 u8Flags); + sint8 bind(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen); + sint8 listen(SOCKET sock, uint8 backlog); + sint8 setopt(SOCKET socket, uint8 u8Level, uint8 option_name, const void *option_value, uint16 u16OptionLen); + sint8 connect(SOCKET sock, struct sockaddr *pstrAddr, uint8 u8AddrLen); + uint8 connected(SOCKET sock); + uint8 listening(SOCKET sock); + uint8 bound(SOCKET sock); + int available(SOCKET sock); + int peek(SOCKET sock); + int read(SOCKET sock, uint8_t* buf, size_t size); + size_t write(SOCKET sock, const uint8_t *buf, size_t size); + sint16 sendto(SOCKET sock, void *pvSendBuffer, uint16 u16SendLength, uint16 flags, struct sockaddr *pstrDestAddr, uint8 u8AddrLen); + IPAddress remoteIP(SOCKET sock); + uint16_t remotePort(SOCKET sock); + sint8 close(SOCKET sock); + SOCKET accepted(SOCKET sock); + int hasParent(SOCKET sock, SOCKET child); + + static void eventCallback(SOCKET sock, uint8 u8Msg, void *pvMsg); + +private: + void handleEvent(SOCKET sock, uint8 u8Msg, void *pvMsg); + int fillRecvBuffer(SOCKET sock); + + struct + { + uint8_t state; + SOCKET parent; + tstrSocketRecvMsg recvMsg; + struct { + uint8_t* data; + uint8_t* head; + int length; + } buffer; + struct sockaddr _lastSendtoAddr; + } _info[MAX_SOCKET]; +}; + +extern WiFiSocketClass WiFiSocket; + +#endif diff --git a/lib/WiFiEsp/CHANGES.txt b/lib/WiFiEsp/CHANGES.txt new file mode 100644 index 0000000..895b466 --- /dev/null +++ b/lib/WiFiEsp/CHANGES.txt @@ -0,0 +1,70 @@ +2.2.2 (2017-11-03) + * Make SSID a const char * in begin() #116 + * Replace NULL with 0 to avoid compilation warnings + * Changing _ESPLOGLEVEL_ requires editing debug.h #88 + +2.2.1 (2017-01-02) + * Fixing Issue #69 (Can't declare member function to have static linkage) + * Supporting ESP8266 firmware 2.X + +2.1.2 (2016-05-08) + * Added retry in EspDrv::wifiDriverInit method + * Clean buffer in ScanNetwork (bug #43) + +2.1.1 (2016-05-09) + * Implemented gatwayIP() and subnetMask() methods + +2.1 (2016-03-13) + * SSL connection support + * Implementation of config and configAP methods + * Fixed read methods WiFiEspClient.read(buf, size) and WiFiEspUDP::read(buf, size) + * Fixed possible buffer overflow in EspDrv.sendCmdGet + * Added beginAP methods similar to WiFi101 library - parameters order for beginAP is now different! + +1.6 (2016-02-21) + * Improved UDP support + * Added WiFiEspClient.remoteIP() method + * Consistent use use of uint16_t to manage port numbers + * Added AT+CIPDINFO=1 during init to return remote IP and port with IPD + * Added AT+CWAUTOCONN=0 during init to disable autoconnect + +1.5.1 (2016-02-11) + * Fix in EspDrv.getScanNetworks method + * Fix buffer overflow in getFwVersion + +1.5 (2016-01-25) + * Implemented scanNetworks method + * Increased ring buffer size to 32 to read long SSID names + +1.4.2 (2016-01-05) + * Fixed compilation problem when using WiFiEspClient.print + +1.4.1 (2016-01-05) + * Speed optimizations + +1.4 (2016-01-04) + * Reduced dynamic memory footprint + +1.3 (2016-01-03) + * UDP support (experimental) + * Fixed WiFiEspClient.connected and WiFi.status and methods + * Connection close detection + * Ring buffer optimization + * Client peek method fixed + +1.2 (2015-12-29) + * Redesigned WiFi.init method to accept a Stream object + * Use CUR when starting the AP + * Small improvements to samples + +1.1 (2015-12-20) + * Fix for receiving large data packets + * Access point mode support + * Ring buffer class is now used in EspDrv.cpp + * Removed not implemented methods + * Prints firmware version if not recognized + * Multiple exclamation marks fixed for Arduino Mega + * Cleaned up comments + +1.0 (2015-12-11) + * First stable release diff --git a/lib/WiFiEsp/LICENSE b/lib/WiFiEsp/LICENSE new file mode 100644 index 0000000..6b156fe --- /dev/null +++ b/lib/WiFiEsp/LICENSE @@ -0,0 +1,675 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + diff --git a/lib/WiFiEsp/README.md b/lib/WiFiEsp/README.md new file mode 100644 index 0000000..b3cc5fd --- /dev/null +++ b/lib/WiFiEsp/README.md @@ -0,0 +1,102 @@ +# WiFiEsp + +With an ESP8266 board, WiFiEsp library allows an Arduino board to connect to the internet. +It can serve as either a server accepting incoming connections or a client making outgoing ones. +The WiFiEsp library is very similar to the Arduino [WiFi](http://www.arduino.cc/en/Reference/WiFi) and [Ethernet](http://www.arduino.cc/en/Reference/Ethernet) libraries, and many of the function calls are the same. + +Supports ESP SDK version 1.1.1 and above (AT version 0.25 and above). + + +## Features + +- APIs compatible with standard Arduino WiFi library. +- Use AT commands of standard ESP firmware (no need to flash a custom firmware). +- Support hardware and software serial ports. +- Configurable tracing level. + +## Wiring + +The WiFiEsp library has been designed to work with the [ESP WiFi shield](http://www.instructables.com/id/Cheap-Arduino-WiFi-Shield-With-ESP8266/). +It is a cheap version of the Arduino WiFi shield that uses an ESP-01 module to provide networking capabilities to Arduino boards. + + +## Examples + +- [ConnectWPA](https://github.com/bportaluri/WiFiEsp/blob/master/examples/ConnectWPA/ConnectWPA.ino) - Demonstrates how to connect to a network that is encrypted with WPA2 Personal +- [WebClient](https://github.com/bportaluri/WiFiEsp/blob/master/examples/WebClient/WebClient.ino) - Connect to a remote webserver +- [WebClientRepeating](https://github.com/bportaluri/WiFiEsp/blob/master/examples/WebClientRepeating/WebClientRepeating.ino) - Make repeated HTTP calls to a webserver +- [WebServer](https://github.com/bportaluri/WiFiEsp/blob/master/examples/WebServer/WebServer.ino) - Serve a webpage from the WiFi shield +- [WebServerAP](https://github.com/bportaluri/WiFiEsp/blob/master/examples/WebServerAP/WebServerAP.ino) - Serve a webpage from the WiFi shield starting a local Access Point +- [WebServerLed](https://github.com/bportaluri/WiFiEsp/blob/master/examples/WebServerLed/WebServerLed.ino) - Turn on and off a led from a webpage +- [UdpNTPClient](https://github.com/bportaluri/WiFiEsp/blob/master/examples/UdpNTPClient/UdpNTPClient.ino) - Query a Network Time Protocol (NTP) server using UDP + + +## Supported APIs + +Most of the standard Arduino WiFi library methods are available. Refer to the [WiFi library page](http://www.arduino.cc/en/Reference/WiFi) for more details. + +### WiFiEsp class + +- begin() - Not all authentication types +- disconnect() - YES +- config() +- setDNS() - NO (no AT command available) +- SSID() - YES +- BSSID() - YES +- RSSI() - YES +- encryptionType() - NO (no AT command available) +- scanNetworks() - YES +- getSocket() +- macAddress() - YES + + +### WiFiEspServer class + +The WiFiEspServer class creates servers which can send data to and receive data from connected clients (programs running on other computers or devices). + +- WiFiEspServer() - YES +- begin() - YES +- available() - YES +- write() - YES +- print() - YES +- println() - YES + + +### Client class + +The WiFiEspClient class creates clients that can connect to servers and send and receive data. + +- WiFiEspClient() - YES +- connected() - YES +- connect() - YES +- write() - YES +- print() - YES +- println() - YES +- available() - YES +- read() - YES +- flush() - YES +- stop() - YES + + +### WiFiEspUDP class + +The UDP class enables UDP message to be sent and received. + +- WiFiUDP - YES +- begin() - YES +- available() - YES +- beginPacket() - YES +- endPacket() - YES +- write() - YES +- parsePacket() - YES +- peek() +- read() - YES +- flush() +- stop() +- remoteIP() - YES +- remotePort() - YES + + +## Contributing + +If you discover a bug or would like to propose a new feature, please open a new [issue](https://github.com/bportaluri/WiFiEsp/issues). diff --git a/lib/WiFiEsp/examples/ConnectWPA/ConnectWPA.ino b/lib/WiFiEsp/examples/ConnectWPA/ConnectWPA.ino new file mode 100644 index 0000000..c652963 --- /dev/null +++ b/lib/WiFiEsp/examples/ConnectWPA/ConnectWPA.ino @@ -0,0 +1,94 @@ +/* + WiFiEsp example: ConnectWPA + + This example connects to an encrypted WiFi network using an ESP8266 module. + Then it prints the MAC address of the WiFi shield, the IP address obtained + and other network details. + + For more details see: http://yaab-arduino.blogspot.com/p/wifiesp-example-connect.html +*/ + +#include "WiFiEsp.h" + +// Emulate Serial1 on pins 6/7 if not present +#ifndef HAVE_HWSERIAL1 +#include "SoftwareSerial.h" +SoftwareSerial Serial1(6, 7); // RX, TX +#endif + +char ssid[] = "Twim"; // your network SSID (name) +char pass[] = "12345678"; // your network password +int status = WL_IDLE_STATUS; // the Wifi radio's status + +void setup() +{ + // initialize serial for debugging + Serial.begin(115200); + // initialize serial for ESP module + Serial1.begin(9600); + // initialize ESP module + WiFi.init(&Serial1); + + // check for the presence of the shield + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue + while (true); + } + + // attempt to connect to WiFi network + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network + status = WiFi.begin(ssid, pass); + } + + Serial.println("You're connected to the network"); +} + +void loop() +{ + // print the network connection information every 10 seconds + Serial.println(); + printCurrentNet(); + printWifiData(); + + delay(10000); +} + +void printWifiData() +{ + // print your WiFi shield's IP address + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print your MAC address + byte mac[6]; + WiFi.macAddress(mac); + char buf[20]; + sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]); + Serial.print("MAC address: "); + Serial.println(buf); +} + +void printCurrentNet() +{ + // print the SSID of the network you're attached to + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print the MAC address of the router you're attached to + byte bssid[6]; + WiFi.BSSID(bssid); + char buf[20]; + sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", bssid[5], bssid[4], bssid[3], bssid[2], bssid[1], bssid[0]); + Serial.print("BSSID: "); + Serial.println(buf); + + // print the received signal strength + long rssi = WiFi.RSSI(); + Serial.print("Signal strength (RSSI): "); + Serial.println(rssi); +} diff --git a/lib/WiFiEsp/examples/ScanNetworks/ScanNetworks.ino b/lib/WiFiEsp/examples/ScanNetworks/ScanNetworks.ino new file mode 100644 index 0000000..664b331 --- /dev/null +++ b/lib/WiFiEsp/examples/ScanNetworks/ScanNetworks.ino @@ -0,0 +1,109 @@ +/* + WiFiEsp example: ScanNetworks + + This example prints the Wifi shield's MAC address, and + scans for available Wifi networks using the Wifi shield. + Every ten seconds, it scans again. It doesn't actually + connect to any network, so no encryption scheme is specified. + + For more details see: http://yaab-arduino.blogspot.com/p/wifiesp.html +*/ + +#include "WiFiEsp.h" + +// Emulate Serial1 on pins 6/7 if not present +#ifndef HAVE_HWSERIAL1 +#include "SoftwareSerial.h" +SoftwareSerial Serial1(6, 7); // RX, TX +#endif + +void setup() { + // initialize serial for debugging + Serial.begin(115200); + // initialize serial for ESP module + Serial1.begin(9600); + // initialize ESP module + WiFi.init(&Serial1); + + // check for the presence of the shield + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue + while (true); + } + + // Print WiFi MAC address + printMacAddress(); +} + +void loop() +{ + // scan for existing networks + Serial.println(); + Serial.println("Scanning available networks..."); + listNetworks(); + delay(10000); +} + + +void printMacAddress() +{ + // get your MAC address + byte mac[6]; + WiFi.macAddress(mac); + + // print MAC address + char buf[20]; + sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]); + Serial.print("MAC address: "); + Serial.println(buf); +} + +void listNetworks() +{ + // scan for nearby networks + int numSsid = WiFi.scanNetworks(); + if (numSsid == -1) { + Serial.println("Couldn't get a wifi connection"); + while (true); + } + + // print the list of networks seen + Serial.print("Number of available networks:"); + Serial.println(numSsid); + + // print the network number and name for each network found + for (int thisNet = 0; thisNet < numSsid; thisNet++) { + Serial.print(thisNet); + Serial.print(") "); + Serial.print(WiFi.SSID(thisNet)); + Serial.print("\tSignal: "); + Serial.print(WiFi.RSSI(thisNet)); + Serial.print(" dBm"); + Serial.print("\tEncryption: "); + printEncryptionType(WiFi.encryptionType(thisNet)); + } +} + +void printEncryptionType(int thisType) { + // read the encryption type and print out the name + switch (thisType) { + case ENC_TYPE_WEP: + Serial.print("WEP"); + break; + case ENC_TYPE_WPA_PSK: + Serial.print("WPA_PSK"); + break; + case ENC_TYPE_WPA2_PSK: + Serial.print("WPA2_PSK"); + break; + case ENC_TYPE_WPA_WPA2_PSK: + Serial.print("WPA_WPA2_PSK"); + break; + case ENC_TYPE_NONE: + Serial.print("None"); + break; + } + Serial.println(); +} + diff --git a/lib/WiFiEsp/examples/UdpNTPClient/UdpNTPClient.ino b/lib/WiFiEsp/examples/UdpNTPClient/UdpNTPClient.ino new file mode 100644 index 0000000..5f21b19 --- /dev/null +++ b/lib/WiFiEsp/examples/UdpNTPClient/UdpNTPClient.ino @@ -0,0 +1,154 @@ +/* + WiFiEsp example: UdpNTPClient + + Get the time from a Network Time Protocol (NTP) time server. + Demonstrates use of UDP to send and receive data packets + For more on NTP time servers and the messages needed to communicate with them, + see http://en.wikipedia.org/wiki/Network_Time_Protocol + + NOTE: The serial buffer size must be larger than 36 + packet size + In this example we use an UDP packet of 48 bytes so the buffer must be + at least 36+48=84 bytes that exceeds the default buffer size (64). + You must modify the serial buffer size to 128 + For HardwareSerial modify _SS_MAX_RX_BUFF in + Arduino\hardware\arduino\avr\cores\arduino\SoftwareSerial.h + For SoftwareSerial modify _SS_MAX_RX_BUFF in + Arduino\hardware\arduino\avr\libraries\SoftwareSerial\SoftwareSerial.h +*/ + +#include "WiFiEsp.h" +#include "WiFiEspUdp.h" + +// Emulate Serial1 on pins 6/7 if not present +#ifndef HAVE_HWSERIAL1 +#include "SoftwareSerial.h" +SoftwareSerial Serial1(6, 7); // RX, TX +#endif + +char ssid[] = "Twim"; // your network SSID (name) +char pass[] = "12345678"; // your network password +int status = WL_IDLE_STATUS; // the Wifi radio's status + +char timeServer[] = "time.nist.gov"; // NTP server +unsigned int localPort = 2390; // local port to listen for UDP packets + +const int NTP_PACKET_SIZE = 48; // NTP timestamp is in the first 48 bytes of the message +const int UDP_TIMEOUT = 2000; // timeout in miliseconds to wait for an UDP packet to arrive + +byte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets + +// A UDP instance to let us send and receive packets over UDP +WiFiEspUDP Udp; + +void setup() +{ + // initialize serial for debugging + Serial.begin(115200); + // initialize serial for ESP module + Serial1.begin(9600); + // initialize ESP module + WiFi.init(&Serial1); + + // check for the presence of the shield + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue + while (true); + } + + // attempt to connect to WiFi network + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network + status = WiFi.begin(ssid, pass); + } + + // you're connected now, so print out the data + Serial.println("You're connected to the network"); + + Udp.begin(localPort); +} + +void loop() +{ + sendNTPpacket(timeServer); // send an NTP packet to a time server + + // wait for a reply for UDP_TIMEOUT miliseconds + unsigned long startMs = millis(); + while (!Udp.available() && (millis() - startMs) < UDP_TIMEOUT) {} + + Serial.println(Udp.parsePacket()); + if (Udp.parsePacket()) { + Serial.println("packet received"); + // We've received a packet, read the data from it into the buffer + Udp.read(packetBuffer, NTP_PACKET_SIZE); + + // the timestamp starts at byte 40 of the received packet and is four bytes, + // or two words, long. First, esxtract the two words: + + unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); + unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); + // combine the four bytes (two words) into a long integer + // this is NTP time (seconds since Jan 1 1900): + unsigned long secsSince1900 = highWord << 16 | lowWord; + Serial.print("Seconds since Jan 1 1900 = "); + Serial.println(secsSince1900); + + // now convert NTP time into everyday time: + Serial.print("Unix time = "); + // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: + const unsigned long seventyYears = 2208988800UL; + // subtract seventy years: + unsigned long epoch = secsSince1900 - seventyYears; + // print Unix time: + Serial.println(epoch); + + + // print the hour, minute and second: + Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT) + Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) + Serial.print(':'); + if (((epoch % 3600) / 60) < 10) { + // In the first 10 minutes of each hour, we'll want a leading '0' + Serial.print('0'); + } + Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute) + Serial.print(':'); + if ((epoch % 60) < 10) { + // In the first 10 seconds of each minute, we'll want a leading '0' + Serial.print('0'); + } + Serial.println(epoch % 60); // print the second + } + // wait ten seconds before asking for the time again + delay(10000); +} + +// send an NTP request to the time server at the given address +void sendNTPpacket(char *ntpSrv) +{ + // set all bytes in the buffer to 0 + memset(packetBuffer, 0, NTP_PACKET_SIZE); + // Initialize values needed to form NTP request + // (see URL above for details on the packets) + + packetBuffer[0] = 0b11100011; // LI, Version, Mode + packetBuffer[1] = 0; // Stratum, or type of clock + packetBuffer[2] = 6; // Polling Interval + packetBuffer[3] = 0xEC; // Peer Clock Precision + // 8 bytes of zero for Root Delay & Root Dispersion + packetBuffer[12] = 49; + packetBuffer[13] = 0x4E; + packetBuffer[14] = 49; + packetBuffer[15] = 52; + + // all NTP fields have been given values, now + // you can send a packet requesting a timestamp: + Udp.beginPacket(ntpSrv, 123); //NTP requests are to port 123 + + Udp.write(packetBuffer, NTP_PACKET_SIZE); + + Udp.endPacket(); +} + diff --git a/lib/WiFiEsp/examples/UdpSendReceive/UdpSendReceive.ino b/lib/WiFiEsp/examples/UdpSendReceive/UdpSendReceive.ino new file mode 100644 index 0000000..58b638e --- /dev/null +++ b/lib/WiFiEsp/examples/UdpSendReceive/UdpSendReceive.ino @@ -0,0 +1,109 @@ +/* + WiFiEsp example: WiFi UDP Send and Receive String + + This sketch wait an UDP packet on localPort using a WiFi shield. + When a packet is received an 'ACK' packet is sent to the client on port remotePort. + + For more details see: http://yaab-arduino.blogspot.com/p/wifiesp-example-client.html +*/ + + +#include +#include + +// Emulate Serial1 on pins 6/7 if not present +#ifndef HAVE_HWSERIAL1 +#include "SoftwareSerial.h" +SoftwareSerial Serial1(6, 7); // RX, TX +#endif + +char ssid[] = "Twim"; // your network SSID (name) +char pass[] = "12345678"; // your network password +int status = WL_IDLE_STATUS; // the Wifi radio's status + +unsigned int localPort = 10002; // local port to listen on + +char packetBuffer[255]; // buffer to hold incoming packet +char ReplyBuffer[] = "ACK"; // a string to send back + +WiFiEspUDP Udp; + +void setup() { + // initialize serial for debugging + Serial.begin(115200); + // initialize serial for ESP module + Serial1.begin(9600); + // initialize ESP module + WiFi.init(&Serial1); + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + // attempt to connect to WiFi network + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network + status = WiFi.begin(ssid, pass); + } + + Serial.println("Connected to wifi"); + printWifiStatus(); + + Serial.println("\nStarting connection to server..."); + // if you get a connection, report back via serial: + Udp.begin(localPort); + + Serial.print("Listening on port "); + Serial.println(localPort); +} + +void loop() { + + // if there's data available, read a packet + int packetSize = Udp.parsePacket(); + if (packetSize) { + Serial.print("Received packet of size "); + Serial.println(packetSize); + Serial.print("From "); + IPAddress remoteIp = Udp.remoteIP(); + Serial.print(remoteIp); + Serial.print(", port "); + Serial.println(Udp.remotePort()); + + // read the packet into packetBufffer + int len = Udp.read(packetBuffer, 255); + if (len > 0) { + packetBuffer[len] = 0; + } + Serial.println("Contents:"); + Serial.println(packetBuffer); + + // send a reply, to the IP address and port that sent us the packet we received + Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); + Udp.write(ReplyBuffer); + Udp.endPacket(); + } +} + + +void printWifiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFiEsp/examples/WebClient/WebClient.ino b/lib/WiFiEsp/examples/WebClient/WebClient.ino new file mode 100644 index 0000000..7e8c802 --- /dev/null +++ b/lib/WiFiEsp/examples/WebClient/WebClient.ino @@ -0,0 +1,106 @@ +/* + WiFiEsp example: WebClient + + This sketch connects to google website using an ESP8266 module to + perform a simple web search. + + For more details see: http://yaab-arduino.blogspot.com/p/wifiesp-example-client.html +*/ + +#include "WiFiEsp.h" + +// Emulate Serial1 on pins 6/7 if not present +#ifndef HAVE_HWSERIAL1 +#include "SoftwareSerial.h" +SoftwareSerial Serial1(6, 7); // RX, TX +#endif + +char ssid[] = "Twim"; // your network SSID (name) +char pass[] = "12345678"; // your network password +int status = WL_IDLE_STATUS; // the Wifi radio's status + +char server[] = "arduino.cc"; + +// Initialize the Ethernet client object +WiFiEspClient client; + +void setup() +{ + // initialize serial for debugging + Serial.begin(115200); + // initialize serial for ESP module + Serial1.begin(9600); + // initialize ESP module + WiFi.init(&Serial1); + + // check for the presence of the shield + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue + while (true); + } + + // attempt to connect to WiFi network + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network + status = WiFi.begin(ssid, pass); + } + + // you're connected now, so print out the data + Serial.println("You're connected to the network"); + + printWifiStatus(); + + Serial.println(); + Serial.println("Starting connection to server..."); + // if you get a connection, report back via serial + if (client.connect(server, 80)) { + Serial.println("Connected to server"); + // Make a HTTP request + client.println("GET /asciilogo.txt HTTP/1.1"); + client.println("Host: arduino.cc"); + client.println("Connection: close"); + client.println(); + } +} + +void loop() +{ + // if there are incoming bytes available + // from the server, read them and print them + while (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if the server's disconnected, stop the client + if (!client.connected()) { + Serial.println(); + Serial.println("Disconnecting from server..."); + client.stop(); + + // do nothing forevermore + while (true); + } +} + + +void printWifiStatus() +{ + // print the SSID of the network you're attached to + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength + long rssi = WiFi.RSSI(); + Serial.print("Signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFiEsp/examples/WebClientRepeating/WebClientRepeating.ino b/lib/WiFiEsp/examples/WebClientRepeating/WebClientRepeating.ino new file mode 100644 index 0000000..11353c5 --- /dev/null +++ b/lib/WiFiEsp/examples/WebClientRepeating/WebClientRepeating.ino @@ -0,0 +1,121 @@ +/* + WiFiEsp example: WebClientRepeating + + This sketch connects to a web server and makes an HTTP request + using an Arduino ESP8266 module. + It repeats the HTTP call each 10 seconds. + + For more details see: http://yaab-arduino.blogspot.com/p/wifiesp.html +*/ + +#include "WiFiEsp.h" + +// Emulate Serial1 on pins 6/7 if not present +#ifndef HAVE_HWSERIAL1 +#include "SoftwareSerial.h" +SoftwareSerial Serial1(6, 7); // RX, TX +#endif + +char ssid[] = "Twim"; // your network SSID (name) +char pass[] = "12345678"; // your network password +int status = WL_IDLE_STATUS; // the Wifi radio's status + +char server[] = "arduino.cc"; + +unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds +const unsigned long postingInterval = 10000L; // delay between updates, in milliseconds + +// Initialize the Ethernet client object +WiFiEspClient client; + +void setup() +{ + // initialize serial for debugging + Serial.begin(115200); + // initialize serial for ESP module + Serial1.begin(9600); + // initialize ESP module + WiFi.init(&Serial1); + + // check for the presence of the shield + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue + while (true); + } + + // attempt to connect to WiFi network + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network + status = WiFi.begin(ssid, pass); + } + + Serial.println("You're connected to the network"); + + printWifiStatus(); +} + +void loop() +{ + // if there's incoming data from the net connection send it out the serial port + // this is for debugging purposes only + while (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if 10 seconds have passed since your last connection, + // then connect again and send data + if (millis() - lastConnectionTime > postingInterval) { + httpRequest(); + } +} + +// this method makes a HTTP connection to the server +void httpRequest() +{ + Serial.println(); + + // close any connection before send a new request + // this will free the socket on the WiFi shield + client.stop(); + + // if there's a successful connection + if (client.connect(server, 80)) { + Serial.println("Connecting..."); + + // send the HTTP PUT request + client.println(F("GET /asciilogo.txt HTTP/1.1")); + client.println(F("Host: arduino.cc")); + client.println("Connection: close"); + client.println(); + + // note the time that the connection was made + lastConnectionTime = millis(); + } + else { + // if you couldn't make a connection + Serial.println("Connection failed"); + } +} + + +void printWifiStatus() +{ + // print the SSID of the network you're attached to + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength + long rssi = WiFi.RSSI(); + Serial.print("Signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFiEsp/examples/WebClientSSL/WebClientSSL.ino b/lib/WiFiEsp/examples/WebClientSSL/WebClientSSL.ino new file mode 100644 index 0000000..1923dcd --- /dev/null +++ b/lib/WiFiEsp/examples/WebClientSSL/WebClientSSL.ino @@ -0,0 +1,106 @@ +/* + WiFiEsp example: WebClient + + This sketch connects to google website using an ESP8266 module to + perform a simple web search. + + For more details see: http://yaab-arduino.blogspot.com/p/wifiesp-example-client.html +*/ + +#include "WiFiEsp.h" + +// Emulate Serial1 on pins 6/7 if not present +#ifndef HAVE_HWSERIAL1 +#include "SoftwareSerial.h" +SoftwareSerial Serial1(6, 7); // RX, TX +#endif + +char ssid[] = "Twim"; // your network SSID (name) +char pass[] = "12345678"; // your network password +int status = WL_IDLE_STATUS; // the Wifi radio's status + +char server[] = "www.google.com"; + +// Initialize the Ethernet client object +WiFiEspClient client; + +void setup() +{ + // initialize serial for debugging + Serial.begin(115200); + // initialize serial for ESP module + Serial1.begin(9600); + // initialize ESP module + WiFi.init(&Serial1); + + // check for the presence of the shield + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue + while (true); + } + + // attempt to connect to WiFi network + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network + status = WiFi.begin(ssid, pass); + } + + // you're connected now, so print out the data + Serial.println("You're connected to the network"); + + printWifiStatus(); + + Serial.println(); + Serial.println("Starting connection to server..."); + // if you get a connection, report back via serial + if (client.connectSSL(server, 443)) { + Serial.println("Connected to server"); + // Make a HTTP request + client.println("GET / HTTP/1.1"); + client.println("Host: www.google.com"); + client.println("Connection: close"); + client.println(); + } +} + +void loop() +{ + // if there are incoming bytes available + // from the server, read them and print them + while (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if the server's disconnected, stop the client + if (!client.connected()) { + Serial.println(); + Serial.println("Disconnecting from server..."); + client.stop(); + + // do nothing forevermore + while (true); + } +} + + +void printWifiStatus() +{ + // print the SSID of the network you're attached to + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength + long rssi = WiFi.RSSI(); + Serial.print("Signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFiEsp/examples/WebServer/WebServer.ino b/lib/WiFiEsp/examples/WebServer/WebServer.ino new file mode 100644 index 0000000..7322e90 --- /dev/null +++ b/lib/WiFiEsp/examples/WebServer/WebServer.ino @@ -0,0 +1,136 @@ +/* + WiFiEsp example: WebServer + + A simple web server that shows the value of the analog input + pins via a web page using an ESP8266 module. + This sketch will print the IP address of your ESP8266 module (once connected) + to the Serial monitor. From there, you can open that address in a web browser + to display the web page. + The web page will be automatically refreshed each 20 seconds. + + For more details see: http://yaab-arduino.blogspot.com/p/wifiesp.html +*/ + +#include "WiFiEsp.h" + +// Emulate Serial1 on pins 6/7 if not present +#ifndef HAVE_HWSERIAL1 +#include "SoftwareSerial.h" +SoftwareSerial Serial1(6, 7); // RX, TX +#endif + +char ssid[] = "Twim"; // your network SSID (name) +char pass[] = "12345678"; // your network password +int status = WL_IDLE_STATUS; // the Wifi radio's status +int reqCount = 0; // number of requests received + +WiFiEspServer server(80); + + +void setup() +{ + // initialize serial for debugging + Serial.begin(115200); + // initialize serial for ESP module + Serial1.begin(9600); + // initialize ESP module + WiFi.init(&Serial1); + + // check for the presence of the shield + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue + while (true); + } + + // attempt to connect to WiFi network + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network + status = WiFi.begin(ssid, pass); + } + + Serial.println("You're connected to the network"); + printWifiStatus(); + + // start the web server on port 80 + server.begin(); +} + + +void loop() +{ + // listen for incoming clients + WiFiEspClient client = server.available(); + if (client) { + Serial.println("New client"); + // an http request ends with a blank line + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + Serial.write(c); + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the http request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + Serial.println("Sending response"); + + // send a standard http response header + // use \r\n instead of many println statements to speedup data send + client.print( + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n" + "Connection: close\r\n" // the connection will be closed after completion of the response + "Refresh: 20\r\n" // refresh the page automatically every 20 sec + "\r\n"); + client.print("\r\n"); + client.print("\r\n"); + client.print("

Hello World!

\r\n"); + client.print("Requests received: "); + client.print(++reqCount); + client.print("
\r\n"); + client.print("Analog input A0: "); + client.print(analogRead(0)); + client.print("
\r\n"); + client.print("\r\n"); + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } + else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + // give the web browser time to receive the data + delay(10); + + // close the connection: + client.stop(); + Serial.println("Client disconnected"); + } +} + + +void printWifiStatus() +{ + // print the SSID of the network you're attached to + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print where to go in the browser + Serial.println(); + Serial.print("To see this page in action, open a browser to http://"); + Serial.println(ip); + Serial.println(); +} diff --git a/lib/WiFiEsp/examples/WebServerAP/WebServerAP.ino b/lib/WiFiEsp/examples/WebServerAP/WebServerAP.ino new file mode 100644 index 0000000..4597557 --- /dev/null +++ b/lib/WiFiEsp/examples/WebServerAP/WebServerAP.ino @@ -0,0 +1,128 @@ +/* + WiFiEsp example: WebServerAP + + A simple web server that shows the value of the analog input + pins via a web page using an ESP8266 module. + This sketch will start an access point and print the IP address of your + ESP8266 module to the Serial monitor. From there, you can open + that address in a web browser to display the web page. + The web page will be automatically refreshed each 20 seconds. + + For more details see: http://yaab-arduino.blogspot.com/p/wifiesp.html +*/ + +#include "WiFiEsp.h" + +// Emulate Serial1 on pins 6/7 if not present +#ifndef HAVE_HWSERIAL1 +#include "SoftwareSerial.h" +SoftwareSerial Serial1(6, 7); // RX, TX +#endif + +char ssid[] = "TwimEsp"; // your network SSID (name) +char pass[] = "12345678"; // your network password +int status = WL_IDLE_STATUS; // the Wifi radio's status +int reqCount = 0; // number of requests received + +WiFiEspServer server(80); + +// use a ring buffer to increase speed and reduce memory allocation +RingBuffer buf(8); + +void setup() +{ + Serial.begin(115200); // initialize serial for debugging + Serial1.begin(9600); // initialize serial for ESP module + WiFi.init(&Serial1); // initialize ESP module + + // check for the presence of the shield + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + while (true); // don't continue + } + + Serial.print("Attempting to start AP "); + Serial.println(ssid); + + // uncomment these two lines if you want to set the IP address of the AP + //IPAddress localIp(192, 168, 111, 111); + //WiFi.configAP(localIp); + + // start access point + status = WiFi.beginAP(ssid, 10, pass, ENC_TYPE_WPA2_PSK); + + Serial.println("Access point started"); + printWifiStatus(); + + // start the web server on port 80 + server.begin(); + Serial.println("Server started"); +} + + +void loop() +{ + WiFiEspClient client = server.available(); // listen for incoming clients + + if (client) { // if you get a client, + Serial.println("New client"); // print a message out the serial port + buf.init(); // initialize the circular buffer + while (client.connected()) { // loop while the client's connected + if (client.available()) { // if there's bytes to read from the client, + char c = client.read(); // read a byte, then + buf.push(c); // push it to the ring buffer + + // you got two newline characters in a row + // that's the end of the HTTP request, so send a response + if (buf.endsWith("\r\n\r\n")) { + sendHttpResponse(client); + break; + } + } + } + + // give the web browser time to receive the data + delay(10); + + // close the connection + client.stop(); + Serial.println("Client disconnected"); + } +} + +void sendHttpResponse(WiFiEspClient client) +{ + client.print( + "HTTP/1.1 200 OK\r\n" + "Content-Type: text/html\r\n" + "Connection: close\r\n" // the connection will be closed after completion of the response + "Refresh: 20\r\n" // refresh the page automatically every 20 sec + "\r\n"); + client.print("\r\n"); + client.print("\r\n"); + client.print("

Hello World!

\r\n"); + client.print("Requests received: "); + client.print(++reqCount); + client.print("
\r\n"); + client.print("Analog input A0: "); + client.print(analogRead(0)); + client.print("
\r\n"); + client.print("\r\n"); +} + +void printWifiStatus() +{ + // print your WiFi shield's IP address + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print where to go in the browser + Serial.println(); + Serial.print("To see this page in action, connect to "); + Serial.print(ssid); + Serial.print(" and open a browser to http://"); + Serial.println(ip); + Serial.println(); +} + diff --git a/lib/WiFiEsp/examples/WebServerLed/WebServerLed.ino b/lib/WiFiEsp/examples/WebServerLed/WebServerLed.ino new file mode 100644 index 0000000..17e50c4 --- /dev/null +++ b/lib/WiFiEsp/examples/WebServerLed/WebServerLed.ino @@ -0,0 +1,142 @@ +/* + WiFiEsp example: WebServerLed + + A simple web server that lets you turn on and of an LED via a web page. + This sketch will print the IP address of your ESP8266 module (once connected) + to the Serial monitor. From there, you can open that address in a web browser + to turn on and off the LED on pin 13. + + For more details see: http://yaab-arduino.blogspot.com/p/wifiesp.html +*/ + +#include "WiFiEsp.h" + +// Emulate Serial1 on pins 6/7 if not present +#ifndef HAVE_HWSERIAL1 +#include "SoftwareSerial.h" +SoftwareSerial Serial1(6, 7); // RX, TX +#endif + +char ssid[] = "Twim"; // your network SSID (name) +char pass[] = "12345678"; // your network password +int status = WL_IDLE_STATUS; + +int ledStatus = LOW; + +WiFiEspServer server(80); + +// use a ring buffer to increase speed and reduce memory allocation +RingBuffer buf(8); + +void setup() +{ + pinMode(LED_BUILTIN, OUTPUT); // initialize digital pin LED_BUILTIN as an output. + Serial.begin(115200); // initialize serial for debugging + Serial1.begin(9600); // initialize serial for ESP module + WiFi.init(&Serial1); // initialize ESP module + + // check for the presence of the shield + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue + while (true); + } + + // attempt to connect to WiFi network + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network + status = WiFi.begin(ssid, pass); + } + + Serial.println("You're connected to the network"); + printWifiStatus(); + + // start the web server on port 80 + server.begin(); +} + + +void loop() +{ + WiFiEspClient client = server.available(); // listen for incoming clients + + if (client) { // if you get a client, + Serial.println("New client"); // print a message out the serial port + buf.init(); // initialize the circular buffer + while (client.connected()) { // loop while the client's connected + if (client.available()) { // if there's bytes to read from the client, + char c = client.read(); // read a byte, then + buf.push(c); // push it to the ring buffer + + // printing the stream to the serial monitor will slow down + // the receiving of data from the ESP filling the serial buffer + //Serial.write(c); + + // you got two newline characters in a row + // that's the end of the HTTP request, so send a response + if (buf.endsWith("\r\n\r\n")) { + sendHttpResponse(client); + break; + } + + // Check to see if the client request was "GET /H" or "GET /L": + if (buf.endsWith("GET /H")) { + Serial.println("Turn led ON"); + ledStatus = HIGH; + digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) + } + else if (buf.endsWith("GET /L")) { + Serial.println("Turn led OFF"); + ledStatus = LOW; + digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW + } + } + } + + // close the connection + client.stop(); + Serial.println("Client disconnected"); + } +} + + +void sendHttpResponse(WiFiEspClient client) +{ + // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) + // and a content-type so the client knows what's coming, then a blank line: + client.println("HTTP/1.1 200 OK"); + client.println("Content-type:text/html"); + client.println(); + + // the content of the HTTP response follows the header: + client.print("The LED is "); + client.print(ledStatus); + client.println("
"); + client.println("
"); + + client.println("Click here turn the LED on
"); + client.println("Click here turn the LED off
"); + + // The HTTP response ends with another blank line: + client.println(); +} + +void printWifiStatus() +{ + // print the SSID of the network you're attached to + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print where to go in the browser + Serial.println(); + Serial.print("To see this page in action, open a browser to http://"); + Serial.println(ip); + Serial.println(); +} diff --git a/lib/WiFiEsp/keywords.txt b/lib/WiFiEsp/keywords.txt new file mode 100644 index 0000000..3270a71 --- /dev/null +++ b/lib/WiFiEsp/keywords.txt @@ -0,0 +1,59 @@ +####################################### +# Syntax Coloring Map For WiFiEsp +####################################### + +####################################### +# Library (KEYWORD3) +####################################### + +WiFiEsp KEYWORD3 + + +####################################### +# Datatypes (KEYWORD1) +####################################### + +WiFiEspClient KEYWORD1 +WiFiEspServer KEYWORD1 +WiFiEspUDP KEYWORD1 +RingBuffer KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +firmwareVersion KEYWORD2 +status KEYWORD2 +connect KEYWORD2 +write KEYWORD2 +available KEYWORD2 +config KEYWORD2 +setDNS KEYWORD2 +read KEYWORD2 +flush KEYWORD2 +stop KEYWORD2 +connected KEYWORD2 +begin KEYWORD2 +disconnect KEYWORD2 +macAddress KEYWORD2 +localIP KEYWORD2 +subnetMask KEYWORD2 +gatewayIP KEYWORD2 +scanNetworks KEYWORD2 +SSID KEYWORD2 +BSSID KEYWORD2 +RSSI KEYWORD2 +encryptionType KEYWORD2 +getResult KEYWORD2 +getSocket KEYWORD2 +beginPacket KEYWORD2 +endPacket KEYWORD2 +parsePacket KEYWORD2 +remoteIP KEYWORD2 +remotePort KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/lib/WiFiEsp/library.properties b/lib/WiFiEsp/library.properties new file mode 100644 index 0000000..a8478ed --- /dev/null +++ b/lib/WiFiEsp/library.properties @@ -0,0 +1,9 @@ +name=WiFiEsp +version=2.2.2 +author=bportaluri +maintainer=Bruno Portaluri +sentence=Arduino WiFi library for ESP8266 +paragraph=Arduino WiFi library for ESP8266. Works only with SDK version 1.1.1 and above (AT version 0.25 and above). +category=Other +url=https://github.com/bportaluri/WiFiEsp +architectures=* \ No newline at end of file diff --git a/lib/WiFiEsp/src/WiFiEsp.cpp b/lib/WiFiEsp/src/WiFiEsp.cpp new file mode 100644 index 0000000..76073f5 --- /dev/null +++ b/lib/WiFiEsp/src/WiFiEsp.cpp @@ -0,0 +1,233 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library 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. + +The Arduino WiFiEsp library 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 The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#include "WiFiEsp.h" + + +int16_t WiFiEspClass::_state[MAX_SOCK_NUM] = { NA_STATE, NA_STATE, NA_STATE, NA_STATE }; +uint16_t WiFiEspClass::_server_port[MAX_SOCK_NUM] = { 0, 0, 0, 0 }; + + +uint8_t WiFiEspClass::espMode = 0; + + +WiFiEspClass::WiFiEspClass() +{ + +} + +void WiFiEspClass::init(Stream* espSerial) +{ + LOGINFO(F("Initializing ESP module")); + EspDrv::wifiDriverInit(espSerial); +} + + + +char* WiFiEspClass::firmwareVersion() +{ + return EspDrv::getFwVersion(); +} + + +int WiFiEspClass::begin(const char* ssid, const char* passphrase) +{ + espMode = 1; + if (EspDrv::wifiConnect(ssid, passphrase)) + return WL_CONNECTED; + + return WL_CONNECT_FAILED; +} + + +int WiFiEspClass::beginAP(const char* ssid, uint8_t channel, const char* pwd, uint8_t enc, bool apOnly) +{ + if(apOnly) + espMode = 2; + else + espMode = 3; + + if (EspDrv::wifiStartAP(ssid, pwd, channel, enc, espMode)) + return WL_CONNECTED; + + return WL_CONNECT_FAILED; +} + +int WiFiEspClass::beginAP(const char* ssid) +{ + return beginAP(ssid, 10, "", 0); +} + +int WiFiEspClass::beginAP(const char* ssid, uint8_t channel) +{ + return beginAP(ssid, channel, "", 0); +} + + +void WiFiEspClass::config(IPAddress ip) +{ + EspDrv::config(ip); +} + +void WiFiEspClass::configAP(IPAddress ip) +{ + EspDrv::configAP(ip); +} + + + +int WiFiEspClass::disconnect() +{ + return EspDrv::disconnect(); +} + +uint8_t* WiFiEspClass::macAddress(uint8_t* mac) +{ + // TODO we don't need _mac variable + uint8_t* _mac = EspDrv::getMacAddress(); + memcpy(mac, _mac, WL_MAC_ADDR_LENGTH); + return mac; +} + +IPAddress WiFiEspClass::localIP() +{ + IPAddress ret; + if(espMode==1) + EspDrv::getIpAddress(ret); + else + EspDrv::getIpAddressAP(ret); + return ret; +} + +IPAddress WiFiEspClass::subnetMask() +{ + IPAddress mask; + if(espMode==1) + EspDrv::getNetmask(mask); + return mask; +} + +IPAddress WiFiEspClass::gatewayIP() +{ + IPAddress gw; + if(espMode==1) + EspDrv::getGateway(gw); + return gw; +} + + +char* WiFiEspClass::SSID() +{ + return EspDrv::getCurrentSSID(); +} + +uint8_t* WiFiEspClass::BSSID(uint8_t* bssid) +{ + // TODO we don't need _bssid + uint8_t* _bssid = EspDrv::getCurrentBSSID(); + memcpy(bssid, _bssid, WL_MAC_ADDR_LENGTH); + return bssid; +} + +int32_t WiFiEspClass::RSSI() +{ + return EspDrv::getCurrentRSSI(); +} + + +int8_t WiFiEspClass::scanNetworks() +{ + return EspDrv::getScanNetworks(); +} + +char* WiFiEspClass::SSID(uint8_t networkItem) +{ + return EspDrv::getSSIDNetoworks(networkItem); +} + +int32_t WiFiEspClass::RSSI(uint8_t networkItem) +{ + return EspDrv::getRSSINetoworks(networkItem); +} + +uint8_t WiFiEspClass::encryptionType(uint8_t networkItem) +{ + return EspDrv::getEncTypeNetowrks(networkItem); +} + + +uint8_t WiFiEspClass::status() +{ + return EspDrv::getConnectionStatus(); +} + + + +//////////////////////////////////////////////////////////////////////////// +// Non standard methods +//////////////////////////////////////////////////////////////////////////// + +void WiFiEspClass::reset(void) +{ + EspDrv::reset(); +} + + +/* +void ESP8266::hardReset(void) +{ +connected = false; +strcpy(ip, ""); +digitalWrite(ESP8266_RST, LOW); +delay(ESP8266_HARD_RESET_DURATION); +digitalWrite(ESP8266_RST, HIGH); +delay(ESP8266_HARD_RESET_DURATION); +} +*/ + + +bool WiFiEspClass::ping(const char *host) +{ + return EspDrv::ping(host); +} + +uint8_t WiFiEspClass::getFreeSocket() +{ + // ESP Module assigns socket numbers in ascending order, so we will assign them in descending order + for (int i = MAX_SOCK_NUM - 1; i >= 0; i--) + { + if (_state[i] == NA_STATE) + { + return i; + } + } + return SOCK_NOT_AVAIL; +} + +void WiFiEspClass::allocateSocket(uint8_t sock) +{ + _state[sock] = sock; +} + +void WiFiEspClass::releaseSocket(uint8_t sock) +{ + _state[sock] = NA_STATE; +} + + +WiFiEspClass WiFi; diff --git a/lib/WiFiEsp/src/WiFiEsp.h b/lib/WiFiEsp/src/WiFiEsp.h new file mode 100644 index 0000000..0ad0984 --- /dev/null +++ b/lib/WiFiEsp/src/WiFiEsp.h @@ -0,0 +1,274 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library 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. + +The Arduino WiFiEsp library 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 The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#ifndef WiFiEsp_h +#define WiFiEsp_h + +#include +#include +#include +#include + + +#include "WiFiEspClient.h" +#include "WiFiEspServer.h" +#include "utility/EspDrv.h" +#include "utility/RingBuffer.h" +#include "utility/debug.h" + + +class WiFiEspClass +{ + +public: + + static int16_t _state[MAX_SOCK_NUM]; + static uint16_t _server_port[MAX_SOCK_NUM]; + + WiFiEspClass(); + + + /** + * Initialize the ESP module. + * + * param espSerial: the serial interface (HW or SW) used to communicate with the ESP module + */ + static void init(Stream* espSerial); + + + /** + * Get firmware version + */ + static char* firmwareVersion(); + + + // NOT IMPLEMENTED + //int begin(char* ssid); + + // NOT IMPLEMENTED + //int begin(char* ssid, uint8_t key_idx, const char* key); + + + /** + * Start Wifi connection with passphrase + * the most secure supported mode will be automatically selected + * + * param ssid: Pointer to the SSID string. + * param passphrase: Passphrase. Valid characters in a passphrase + * must be between ASCII 32-126 (decimal). + */ + int begin(const char* ssid, const char* passphrase); + + + /** + * Change Ip configuration settings disabling the DHCP client + * + * param local_ip: Static ip configuration + */ + void config(IPAddress local_ip); + + + // NOT IMPLEMENTED + //void config(IPAddress local_ip, IPAddress dns_server); + + // NOT IMPLEMENTED + //void config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway); + + // NOT IMPLEMENTED + //void config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet); + + // NOT IMPLEMENTED + //void setDNS(IPAddress dns_server1); + + // NOT IMPLEMENTED + //void setDNS(IPAddress dns_server1, IPAddress dns_server2); + + /** + * Disconnect from the network + * + * return: one value of wl_status_t enum + */ + int disconnect(void); + + /** + * Get the interface MAC address. + * + * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + */ + uint8_t* macAddress(uint8_t* mac); + + /** + * Get the interface IP address. + * + * return: Ip address value + */ + IPAddress localIP(); + + + /** + * Get the interface subnet mask address. + * + * return: subnet mask address value + */ + IPAddress subnetMask(); + + /** + * Get the gateway ip address. + * + * return: gateway ip address value + */ + IPAddress gatewayIP(); + + /** + * Return the current SSID associated with the network + * + * return: ssid string + */ + char* SSID(); + + /** + * Return the current BSSID associated with the network. + * It is the MAC address of the Access Point + * + * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + */ + uint8_t* BSSID(uint8_t* bssid); + + + /** + * Return the current RSSI /Received Signal Strength in dBm) + * associated with the network + * + * return: signed value + */ + int32_t RSSI(); + + + /** + * Return Connection status. + * + * return: one of the value defined in wl_status_t + * see https://www.arduino.cc/en/Reference/WiFiStatus + */ + uint8_t status(); + + + /* + * Return the Encryption Type associated with the network + * + * return: one value of wl_enc_type enum + */ + //uint8_t encryptionType(); + + /* + * Start scan WiFi networks available + * + * return: Number of discovered networks + */ + int8_t scanNetworks(); + + /* + * Return the SSID discovered during the network scan. + * + * param networkItem: specify from which network item want to get the information + * + * return: ssid string of the specified item on the networks scanned list + */ + char* SSID(uint8_t networkItem); + + /* + * Return the encryption type of the networks discovered during the scanNetworks + * + * param networkItem: specify from which network item want to get the information + * + * return: encryption type (enum wl_enc_type) of the specified item on the networks scanned list + */ + uint8_t encryptionType(uint8_t networkItem); + + /* + * Return the RSSI of the networks discovered during the scanNetworks + * + * param networkItem: specify from which network item want to get the information + * + * return: signed value of RSSI of the specified item on the networks scanned list + */ + int32_t RSSI(uint8_t networkItem); + + + // NOT IMPLEMENTED + //int hostByName(const char* aHostname, IPAddress& aResult); + + + + //////////////////////////////////////////////////////////////////////////// + // Non standard methods + //////////////////////////////////////////////////////////////////////////// + + /** + * Start the ESP access point. + * + * param ssid: Pointer to the SSID string. + * param channel: WiFi channel (1-14) + * param pwd: Passphrase. Valid characters in a passphrase + * must be between ASCII 32-126 (decimal). + * param enc: encryption type (enum wl_enc_type) + * param apOnly: Set to false if you want to run AP and Station modes simultaneously + */ + int beginAP(const char* ssid, uint8_t channel, const char* pwd, uint8_t enc, bool apOnly=true); + + /* + * Start the ESP access point with open security. + */ + int beginAP(const char* ssid); + int beginAP(const char* ssid, uint8_t channel); + + /** + * Change IP address of the AP + * + * param ip: Static ip configuration + */ + void configAP(IPAddress ip); + + + + /** + * Restart the ESP module. + */ + void reset(); + + /** + * Ping a host. + */ + bool ping(const char *host); + + + friend class WiFiEspClient; + friend class WiFiEspServer; + friend class WiFiEspUDP; + +private: + static uint8_t getFreeSocket(); + static void allocateSocket(uint8_t sock); + static void releaseSocket(uint8_t sock); + + static uint8_t espMode; +}; + +extern WiFiEspClass WiFi; + +#endif diff --git a/lib/WiFiEsp/src/WiFiEspClient.cpp b/lib/WiFiEsp/src/WiFiEspClient.cpp new file mode 100644 index 0000000..5a242a1 --- /dev/null +++ b/lib/WiFiEsp/src/WiFiEspClient.cpp @@ -0,0 +1,290 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library 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. + +The Arduino WiFiEsp library 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 The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#include + +#include "WiFiEsp.h" +#include "WiFiEspClient.h" +#include "WiFiEspServer.h" + +#include "utility/EspDrv.h" +#include "utility/debug.h" + + +WiFiEspClient::WiFiEspClient() : _sock(255) +{ +} + +WiFiEspClient::WiFiEspClient(uint8_t sock) : _sock(sock) +{ +} + + +//////////////////////////////////////////////////////////////////////////////// +// Overrided Print methods +//////////////////////////////////////////////////////////////////////////////// + +// the standard print method will call write for each character in the buffer +// this is very slow on ESP +size_t WiFiEspClient::print(const __FlashStringHelper *ifsh) +{ + printFSH(ifsh, false); +} + +// if we do override this, the standard println will call the print +// method twice +size_t WiFiEspClient::println(const __FlashStringHelper *ifsh) +{ + printFSH(ifsh, true); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Implementation of Client virtual methods +//////////////////////////////////////////////////////////////////////////////// + +int WiFiEspClient::connectSSL(const char* host, uint16_t port) +{ + return connect(host, port, SSL_MODE); +} + +int WiFiEspClient::connectSSL(IPAddress ip, uint16_t port) +{ + char s[16]; + sprintf_P(s, PSTR("%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + return connect(s, port, SSL_MODE); +} + +int WiFiEspClient::connect(const char* host, uint16_t port) +{ + return connect(host, port, TCP_MODE); +} + +int WiFiEspClient::connect(IPAddress ip, uint16_t port) +{ + char s[16]; + sprintf_P(s, PSTR("%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + + return connect(s, port, TCP_MODE); +} + +/* Private method */ +int WiFiEspClient::connect(const char* host, uint16_t port, uint8_t protMode) +{ + LOGINFO1(F("Connecting to"), host); + + _sock = WiFiEspClass::getFreeSocket(); + + if (_sock != NO_SOCKET_AVAIL) + { + if (!EspDrv::startClient(host, port, _sock, protMode)) + return 0; + + WiFiEspClass::allocateSocket(_sock); + } + else + { + LOGERROR(F("No socket available")); + return 0; + } + return 1; +} + + + +size_t WiFiEspClient::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t WiFiEspClient::write(const uint8_t *buf, size_t size) +{ + if (_sock >= MAX_SOCK_NUM or size==0) + { + setWriteError(); + return 0; + } + + bool r = EspDrv::sendData(_sock, buf, size); + if (!r) + { + setWriteError(); + LOGERROR1(F("Failed to write to socket"), _sock); + delay(4000); + stop(); + return 0; + } + + return size; +} + + + +int WiFiEspClient::available() +{ + if (_sock != 255) + { + int bytes = EspDrv::availData(_sock); + if (bytes>0) + { + return bytes; + } + } + + return 0; +} + +int WiFiEspClient::read() +{ + uint8_t b; + if (!available()) + return -1; + + bool connClose = false; + EspDrv::getData(_sock, &b, false, &connClose); + + if (connClose) + { + WiFiEspClass::releaseSocket(_sock); + _sock = 255; + } + + return b; +} + +int WiFiEspClient::read(uint8_t* buf, size_t size) +{ + if (!available()) + return -1; + return EspDrv::getDataBuf(_sock, buf, size); +} + +int WiFiEspClient::peek() +{ + uint8_t b; + if (!available()) + return -1; + + bool connClose = false; + EspDrv::getData(_sock, &b, true, &connClose); + + if (connClose) + { + WiFiEspClass::releaseSocket(_sock); + _sock = 255; + } + + return b; +} + + +void WiFiEspClient::flush() +{ + while (available()) + read(); +} + + + +void WiFiEspClient::stop() +{ + if (_sock == 255) + return; + + LOGINFO1(F("Disconnecting "), _sock); + + EspDrv::stopClient(_sock); + + WiFiEspClass::releaseSocket(_sock); + _sock = 255; +} + + +uint8_t WiFiEspClient::connected() +{ + return (status() == ESTABLISHED); +} + + +WiFiEspClient::operator bool() +{ + return _sock != 255; +} + + +//////////////////////////////////////////////////////////////////////////////// +// Additional WiFi standard methods +//////////////////////////////////////////////////////////////////////////////// + + +uint8_t WiFiEspClient::status() +{ + if (_sock == 255) + { + return CLOSED; + } + + if (EspDrv::availData(_sock)) + { + return ESTABLISHED; + } + + if (EspDrv::getClientState(_sock)) + { + return ESTABLISHED; + } + + WiFiEspClass::releaseSocket(_sock); + _sock = 255; + + return CLOSED; +} + +IPAddress WiFiEspClient::remoteIP() +{ + IPAddress ret; + EspDrv::getRemoteIpAddress(ret); + return ret; +} + +//////////////////////////////////////////////////////////////////////////////// +// Private Methods +//////////////////////////////////////////////////////////////////////////////// + +size_t WiFiEspClient::printFSH(const __FlashStringHelper *ifsh, bool appendCrLf) +{ + size_t size = strlen_P((char*)ifsh); + + if (_sock >= MAX_SOCK_NUM or size==0) + { + setWriteError(); + return 0; + } + + bool r = EspDrv::sendData(_sock, ifsh, size, appendCrLf); + if (!r) + { + setWriteError(); + LOGERROR1(F("Failed to write to socket"), _sock); + delay(4000); + stop(); + return 0; + } + + return size; +} diff --git a/lib/WiFiEsp/src/WiFiEspClient.h b/lib/WiFiEsp/src/WiFiEspClient.h new file mode 100644 index 0000000..1e3823c --- /dev/null +++ b/lib/WiFiEsp/src/WiFiEspClient.h @@ -0,0 +1,144 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library 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. + +The Arduino WiFiEsp library 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 The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#ifndef WiFiEspClient_h +#define WiFiEspClient_h + + +#include "Arduino.h" +#include "Print.h" +#include "Client.h" +#include "IPAddress.h" + + + +class WiFiEspClient : public Client +{ +public: + WiFiEspClient(); + WiFiEspClient(uint8_t sock); + + + // override Print.print method + + size_t print(const __FlashStringHelper *ifsh); + size_t println(const __FlashStringHelper *ifsh); + + + /* + * Connect to the specified IP address and port. The return value indicates success or failure. + * Returns true if the connection succeeds, false if not. + */ + virtual int connect(IPAddress ip, uint16_t port); + + /* + * Connect to the specified host and port. The return value indicates success or failure. + * Returns true if the connection succeeds, false if not. + */ + virtual int connect(const char *host, uint16_t port); + + /* + * Connect to the specified IP address and port using SSL. The return value indicates success or failure. + * Returns true if the connection succeeds, false if not. + */ + int connectSSL(IPAddress ip, uint16_t port); + + /* + * Connect to the specified host and port using SSL. The return value indicates success or failure. + * Returns true if the connection succeeds, false if not. + */ + int connectSSL(const char* host, uint16_t port); + + /* + * Write a character to the server the client is connected to. + * Returns the number of characters written. + */ + virtual size_t write(uint8_t); + + /* + * Write data to the server the client is connected to. + * Returns the number of characters written. + */ + virtual size_t write(const uint8_t *buf, size_t size); + + + virtual int available(); + + /* + * Read the next byte received from the server the client is connected to (after the last call to read()). + * Returns the next byte (or character), or -1 if none is available. + */ + virtual int read(); + + + virtual int read(uint8_t *buf, size_t size); + + /* + * Returns the next byte (character) of incoming serial data without removing it from the internal serial buffer. + */ + virtual int peek(); + + /* + * Discard any bytes that have been written to the client but not yet read. + */ + virtual void flush(); + + /* + * Disconnect from the server. + */ + virtual void stop(); + + /* + * Whether or not the client is connected. + * Note that a client is considered connected if the connection has been closed but there is still unread data. + * Returns true if the client is connected, false if not. + */ + virtual uint8_t connected(); + + + uint8_t status(); + + virtual operator bool(); + + + // needed to correctly handle overriding + // see http://stackoverflow.com/questions/888235/overriding-a-bases-overloaded-function-in-c + using Print::write; + using Print::print; + using Print::println; + + + /* + * Returns the remote IP address. + */ + IPAddress remoteIP(); + + + friend class WiFiEspServer; + +private: + + uint8_t _sock; // connection id + + int connect(const char* host, uint16_t port, uint8_t protMode); + + size_t printFSH(const __FlashStringHelper *ifsh, bool appendCrLf); + +}; + +#endif diff --git a/lib/WiFiEsp/src/WiFiEspServer.cpp b/lib/WiFiEsp/src/WiFiEspServer.cpp new file mode 100644 index 0000000..44384ba --- /dev/null +++ b/lib/WiFiEsp/src/WiFiEspServer.cpp @@ -0,0 +1,99 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library 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. + +The Arduino WiFiEsp library 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 The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#include "WiFiEspServer.h" + +#include "utility/EspDrv.h" +#include "utility/debug.h" + + + +WiFiEspServer::WiFiEspServer(uint16_t port) +{ + _port = port; +} + +void WiFiEspServer::begin() +{ + LOGDEBUG(F("Starting server")); + + /* The ESP Module only allows socket 1 to be used for the server */ +#if 0 + _sock = WiFiEspClass::getFreeSocket(); + if (_sock == SOCK_NOT_AVAIL) + { + LOGERROR(F("No socket available for server")); + return; + } +#else + _sock = 1; // If this is already in use, the startServer attempt will fail +#endif + WiFiEspClass::allocateSocket(_sock); + + _started = EspDrv::startServer(_port, _sock); + + if (_started) + { + LOGINFO1(F("Server started on port"), _port); + } + else + { + LOGERROR(F("Server failed to start")); + } +} + +WiFiEspClient WiFiEspServer::available(byte* status) +{ + // TODO the original method seems to handle automatic server restart + + int bytes = EspDrv::availData(0); + if (bytes>0) + { + LOGINFO1(F("New client"), EspDrv::_connId); + WiFiEspClass::allocateSocket(EspDrv::_connId); + WiFiEspClient client(EspDrv::_connId); + return client; + } + + return WiFiEspClient(255); +} + +uint8_t WiFiEspServer::status() +{ + return EspDrv::getServerState(0); +} + +size_t WiFiEspServer::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t WiFiEspServer::write(const uint8_t *buffer, size_t size) +{ + size_t n = 0; + + for (int sock = 0; sock < MAX_SOCK_NUM; sock++) + { + if (WiFiEspClass::_state[sock] != 0) + { + WiFiEspClient client(sock); + n += client.write(buffer, size); + } + } + return n; +} diff --git a/lib/WiFiEsp/src/WiFiEspServer.h b/lib/WiFiEsp/src/WiFiEspServer.h new file mode 100644 index 0000000..2564c3d --- /dev/null +++ b/lib/WiFiEsp/src/WiFiEspServer.h @@ -0,0 +1,63 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library 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. + +The Arduino WiFiEsp library 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 The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#ifndef WiFiEspServer_h +#define WiFiEspServer_h + +#include + +#include "WiFiEsp.h" + + +class WiFiEspClient; + +class WiFiEspServer : public Server +{ + +public: + WiFiEspServer(uint16_t port); + + + /* + * Gets a client that is connected to the server and has data available for reading. + * The connection persists when the returned client object goes out of scope; you can close it by calling client.stop(). + * Returns a Client object; if no Client has data available for reading, this object will evaluate to false in an if-statement. + */ + WiFiEspClient available(uint8_t* status = NULL); + + /* + * Start the TCP server + */ + void begin(); + + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + + uint8_t status(); + + using Print::write; + + +private: + uint16_t _port; + uint8_t _sock; + bool _started; + +}; + +#endif diff --git a/lib/WiFiEsp/src/WiFiEspUdp.cpp b/lib/WiFiEsp/src/WiFiEspUdp.cpp new file mode 100644 index 0000000..a255486 --- /dev/null +++ b/lib/WiFiEsp/src/WiFiEspUdp.cpp @@ -0,0 +1,193 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library 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. + +The Arduino WiFiEsp library 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 The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#include "WiFiEsp.h" +#include "WiFiEspUdp.h" + +#include "utility/EspDrv.h" +#include "utility/debug.h" + +/* Constructor */ +WiFiEspUDP::WiFiEspUDP() : _sock(NO_SOCKET_AVAIL) {} + + + + +/* Start WiFiUDP socket, listening at local port PORT */ + +uint8_t WiFiEspUDP::begin(uint16_t port) +{ + uint8_t sock = WiFiEspClass::getFreeSocket(); + if (sock != NO_SOCKET_AVAIL) + { + EspDrv::startClient("0", port, sock, UDP_MODE); + + WiFiEspClass::allocateSocket(sock); // allocating the socket for the listener + WiFiEspClass::_server_port[sock] = port; + _sock = sock; + _port = port; + return 1; + } + return 0; + +} + + +/* return number of bytes available in the current packet, + will return zero if parsePacket hasn't been called yet */ +int WiFiEspUDP::available() +{ + if (_sock != NO_SOCKET_AVAIL) + { + int bytes = EspDrv::availData(_sock); + if (bytes>0) + { + return bytes; + } + } + + return 0; +} + +/* Release any resources being used by this WiFiUDP instance */ +void WiFiEspUDP::stop() +{ + if (_sock == NO_SOCKET_AVAIL) + return; + + // Discard data that might be in the incoming buffer + flush(); + + // Stop the listener and return the socket to the pool + EspDrv::stopClient(_sock); + WiFiEspClass::_state[_sock] = NA_STATE; + WiFiEspClass::_server_port[_sock] = 0; + + _sock = NO_SOCKET_AVAIL; +} + +int WiFiEspUDP::beginPacket(const char *host, uint16_t port) +{ + if (_sock == NO_SOCKET_AVAIL) + _sock = WiFiEspClass::getFreeSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + //EspDrv::startClient(host, port, _sock, UDP_MODE); + _remotePort = port; + strcpy(_remoteHost, host); + WiFiEspClass::allocateSocket(_sock); + return 1; + } + return 0; +} + + +int WiFiEspUDP::beginPacket(IPAddress ip, uint16_t port) +{ + char s[18]; + sprintf_P(s, PSTR("%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + + return beginPacket(s, port); +} + + +int WiFiEspUDP::endPacket() +{ + return 1; //ServerDrv::sendUdpData(_sock); +} + +size_t WiFiEspUDP::write(uint8_t byte) +{ + return write(&byte, 1); +} + +size_t WiFiEspUDP::write(const uint8_t *buffer, size_t size) +{ + bool r = EspDrv::sendDataUdp(_sock, _remoteHost, _remotePort, buffer, size); + if (!r) + { + return 0; + } + + return size; +} + +int WiFiEspUDP::parsePacket() +{ + return available(); +} + +int WiFiEspUDP::read() +{ + uint8_t b; + if (!available()) + return -1; + + bool connClose = false; + + // Read the data and handle the timeout condition + if (! EspDrv::getData(_sock, &b, false, &connClose)) + return -1; // Timeout occured + + return b; +} + +int WiFiEspUDP::read(uint8_t* buf, size_t size) +{ + if (!available()) + return -1; + return EspDrv::getDataBuf(_sock, buf, size); +} + +int WiFiEspUDP::peek() +{ + uint8_t b; + if (!available()) + return -1; + + return b; +} + +void WiFiEspUDP::flush() +{ + // Discard all input data + int count = available(); + while (count-- > 0) + read(); +} + + +IPAddress WiFiEspUDP::remoteIP() +{ + IPAddress ret; + EspDrv::getRemoteIpAddress(ret); + return ret; +} + +uint16_t WiFiEspUDP::remotePort() +{ + return EspDrv::getRemotePort(); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// Private Methods +//////////////////////////////////////////////////////////////////////////////// + + diff --git a/lib/WiFiEsp/src/WiFiEspUdp.h b/lib/WiFiEsp/src/WiFiEspUdp.h new file mode 100644 index 0000000..f84b154 --- /dev/null +++ b/lib/WiFiEsp/src/WiFiEspUdp.h @@ -0,0 +1,97 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library 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. + +The Arduino WiFiEsp library 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 The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#ifndef WiFiEspUdp_h +#define WiFiEspUdp_h + +#include + +#define UDP_TX_PACKET_MAX_SIZE 24 + +class WiFiEspUDP : public UDP { +private: + uint8_t _sock; // socket ID for Wiz5100 + uint16_t _port; // local port to listen on + + + uint16_t _remotePort; + char _remoteHost[30]; + + +public: + WiFiEspUDP(); // Constructor + + virtual uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual void stop(); // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port); + + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port); + + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket(); + + // Write a single byte into the packet + virtual size_t write(uint8_t); + + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size); + + using Print::write; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket(); + + // Number of bytes remaining in the current packet + virtual int available(); + + // Read a single byte from the current packet + virtual int read(); + + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len); + + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; + + // Return the next byte from the current packet without moving on to the next byte + virtual int peek(); + + virtual void flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP(); + + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort(); + + + friend class WiFiEspServer; +}; + +#endif diff --git a/lib/WiFiEsp/src/utility/EspDrv.cpp b/lib/WiFiEsp/src/utility/EspDrv.cpp new file mode 100644 index 0000000..76b1a61 --- /dev/null +++ b/lib/WiFiEsp/src/utility/EspDrv.cpp @@ -0,0 +1,1127 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library 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. + +The Arduino WiFiEsp library 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 The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#include +#include + +#include "utility/EspDrv.h" +#include "utility/debug.h" + + +#define NUMESPTAGS 5 + +const char* ESPTAGS[] = +{ + "\r\nOK\r\n", + "\r\nERROR\r\n", + "\r\nFAIL\r\n", + "\r\nSEND OK\r\n", + " CONNECT\r\n" +}; + +typedef enum +{ + TAG_OK, + TAG_ERROR, + TAG_FAIL, + TAG_SENDOK, + TAG_CONNECT +} TagsEnum; + + +Stream *EspDrv::espSerial; + +RingBuffer EspDrv::ringBuf(32); + +// Array of data to cache the information related to the networks discovered +char EspDrv::_networkSsid[][WL_SSID_MAX_LENGTH] = {{"1"},{"2"},{"3"},{"4"},{"5"}}; +int32_t EspDrv::_networkRssi[WL_NETWORKS_LIST_MAXNUM] = { 0 }; +uint8_t EspDrv::_networkEncr[WL_NETWORKS_LIST_MAXNUM] = { 0 }; + +// Cached values of retrieved data +char EspDrv::_ssid[] = {0}; +uint8_t EspDrv::_bssid[] = {0}; +uint8_t EspDrv::_mac[] = {0}; +uint8_t EspDrv::_localIp[] = {0}; +char EspDrv::fwVersion[] = {0}; + +long EspDrv::_bufPos=0; +uint8_t EspDrv::_connId=0; + +uint16_t EspDrv::_remotePort =0; +uint8_t EspDrv::_remoteIp[] = {0}; + + +void EspDrv::wifiDriverInit(Stream *espSerial) +{ + LOGDEBUG(F("> wifiDriverInit")); + + EspDrv::espSerial = espSerial; + + bool initOK = false; + + for(int i=0; i<5; i++) + { + if (sendCmd(F("AT")) == TAG_OK) + { + initOK=true; + break; + } + delay(1000); + } + + if (!initOK) + { + LOGERROR(F("Cannot initialize ESP module")); + delay(5000); + return; + } + + reset(); + + // check firmware version + getFwVersion(); + + // prints a warning message if the firmware is not 1.X or 2.X + if ((fwVersion[0] != '1' and fwVersion[0] != '2') or + fwVersion[1] != '.') + { + LOGWARN1(F("Warning: Unsupported firmware"), fwVersion); + delay(4000); + } + else + { + LOGINFO1(F("Initilization successful -"), fwVersion); + } +} + + +void EspDrv::reset() +{ + LOGDEBUG(F("> reset")); + + sendCmd(F("AT+RST")); + delay(3000); + espEmptyBuf(false); // empty dirty characters from the buffer + + // disable echo of commands + sendCmd(F("ATE0")); + + // set station mode + sendCmd(F("AT+CWMODE=1")); + delay(200); + + // set multiple connections mode + sendCmd(F("AT+CIPMUX=1")); + + // Show remote IP and port with "+IPD" + sendCmd(F("AT+CIPDINFO=1")); + + // Disable autoconnect + // Automatic connection can create problems during initialization phase at next boot + sendCmd(F("AT+CWAUTOCONN=0")); + + // enable DHCP + sendCmd(F("AT+CWDHCP=1,1")); + delay(200); +} + + + +bool EspDrv::wifiConnect(const char* ssid, const char* passphrase) +{ + LOGDEBUG(F("> wifiConnect")); + + // TODO + // Escape character syntax is needed if "SSID" or "password" contains + // any special characters (',', '"' and '/') + + // connect to access point, use CUR mode to avoid connection at boot + int ret = sendCmd(F("AT+CWJAP_CUR=\"%s\",\"%s\""), 20000, ssid, passphrase); + + if (ret==TAG_OK) + { + LOGINFO1(F("Connected to"), ssid); + return true; + } + + LOGWARN1(F("Failed connecting to"), ssid); + + // clean additional messages logged after the FAIL tag + delay(1000); + espEmptyBuf(false); + + return false; +} + + +bool EspDrv::wifiStartAP(const char* ssid, const char* pwd, uint8_t channel, uint8_t enc, uint8_t espMode) +{ + LOGDEBUG(F("> wifiStartAP")); + + // set AP mode, use CUR mode to avoid automatic start at boot + int ret = sendCmd(F("AT+CWMODE_CUR=%d"), 10000, espMode); + if (ret!=TAG_OK) + { + LOGWARN1(F("Failed to set AP mode"), ssid); + return false; + } + + // TODO + // Escape character syntax is needed if "SSID" or "password" contains + // any special characters (',', '"' and '/') + + // start access point + ret = sendCmd(F("AT+CWSAP_CUR=\"%s\",\"%s\",%d,%d"), 10000, ssid, pwd, channel, enc); + + if (ret!=TAG_OK) + { + LOGWARN1(F("Failed to start AP"), ssid); + return false; + } + + if (espMode==2) + sendCmd(F("AT+CWDHCP_CUR=0,1")); // enable DHCP for AP mode + if (espMode==3) + sendCmd(F("AT+CWDHCP_CUR=2,1")); // enable DHCP for station and AP mode + + LOGINFO1(F("Access point started"), ssid); + return true; +} + + +int8_t EspDrv::disconnect() +{ + LOGDEBUG(F("> disconnect")); + + if(sendCmd(F("AT+CWQAP"))==TAG_OK) + return WL_DISCONNECTED; + + // wait and clear any additional message + delay(2000); + espEmptyBuf(false); + + return WL_DISCONNECTED; +} + +void EspDrv::config(IPAddress ip) +{ + LOGDEBUG(F("> config")); + + // disable station DHCP + sendCmd(F("AT+CWDHCP_CUR=1,0")); + + // it seems we need to wait here... + delay(500); + + char buf[16]; + sprintf_P(buf, PSTR("%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + + int ret = sendCmd(F("AT+CIPSTA_CUR=\"%s\""), 2000, buf); + delay(500); + + if (ret==TAG_OK) + { + LOGINFO1(F("IP address set"), buf); + } +} + +void EspDrv::configAP(IPAddress ip) +{ + LOGDEBUG(F("> config")); + + sendCmd(F("AT+CWMODE_CUR=2")); + + // disable station DHCP + sendCmd(F("AT+CWDHCP_CUR=2,0")); + + // it seems we need to wait here... + delay(500); + + char buf[16]; + sprintf_P(buf, PSTR("%d.%d.%d.%d"), ip[0], ip[1], ip[2], ip[3]); + + int ret = sendCmd(F("AT+CIPAP_CUR=\"%s\""), 2000, buf); + delay(500); + + if (ret==TAG_OK) + { + LOGINFO1(F("IP address set"), buf); + } +} + +uint8_t EspDrv::getConnectionStatus() +{ + LOGDEBUG(F("> getConnectionStatus")); + +/* + AT+CIPSTATUS + + Response + + STATUS: + +CIPSTATUS:,,,,, + + Parameters + + + 2: Got IP + 3: Connected + 4: Disconnected + ID of the connection (0~4), for multi-connect + string, "TCP" or "UDP" + string, remote IP address. + remote port number + ESP8266 local port number + + 0: ESP8266 runs as client + 1: ESP8266 runs as server +*/ + + char buf[10]; + if(!sendCmdGet(F("AT+CIPSTATUS"), F("STATUS:"), F("\r\n"), buf, sizeof(buf))) + return WL_NO_SHIELD; + + // 4: client disconnected + // 5: wifi disconnected + int s = atoi(buf); + if(s==2 or s==3 or s==4) + return WL_CONNECTED; + else if(s==5) + return WL_DISCONNECTED; + + return WL_IDLE_STATUS; +} + +uint8_t EspDrv::getClientState(uint8_t sock) +{ + LOGDEBUG1(F("> getClientState"), sock); + + char findBuf[20]; + sprintf_P(findBuf, PSTR("+CIPSTATUS:%d,"), sock); + + char buf[10]; + if (sendCmdGet(F("AT+CIPSTATUS"), findBuf, ",", buf, sizeof(buf))) + { + LOGDEBUG(F("Connected")); + return true; + } + + LOGDEBUG(F("Not connected")); + return false; +} + +uint8_t* EspDrv::getMacAddress() +{ + LOGDEBUG(F("> getMacAddress")); + + memset(_mac, 0, WL_MAC_ADDR_LENGTH); + + char buf[20]; + if (sendCmdGet(F("AT+CIFSR"), F(":STAMAC,\""), F("\""), buf, sizeof(buf))) + { + char* token; + + token = strtok(buf, ":"); + _mac[5] = (byte)strtol(token, NULL, 16); + token = strtok(NULL, ":"); + _mac[4] = (byte)strtol(token, NULL, 16); + token = strtok(NULL, ":"); + _mac[3] = (byte)strtol(token, NULL, 16); + token = strtok(NULL, ":"); + _mac[2] = (byte)strtol(token, NULL, 16); + token = strtok(NULL, ":"); + _mac[1] = (byte)strtol(token, NULL, 16); + token = strtok(NULL, ":"); + _mac[0] = (byte)strtol(token, NULL, 16); + } + return _mac; +} + + +void EspDrv::getIpAddress(IPAddress& ip) +{ + LOGDEBUG(F("> getIpAddress")); + + char buf[20]; + if (sendCmdGet(F("AT+CIFSR"), F(":STAIP,\""), F("\""), buf, sizeof(buf))) + { + char* token; + + token = strtok(buf, "."); + _localIp[0] = atoi(token); + token = strtok(NULL, "."); + _localIp[1] = atoi(token); + token = strtok(NULL, "."); + _localIp[2] = atoi(token); + token = strtok(NULL, "."); + _localIp[3] = atoi(token); + + ip = _localIp; + } +} + +void EspDrv::getIpAddressAP(IPAddress& ip) +{ + LOGDEBUG(F("> getIpAddressAP")); + + char buf[20]; + if (sendCmdGet(F("AT+CIPAP?"), F("+CIPAP:ip:\""), F("\""), buf, sizeof(buf))) + { + char* token; + + token = strtok(buf, "."); + _localIp[0] = atoi(token); + token = strtok(NULL, "."); + _localIp[1] = atoi(token); + token = strtok(NULL, "."); + _localIp[2] = atoi(token); + token = strtok(NULL, "."); + _localIp[3] = atoi(token); + + ip = _localIp; + } +} + + + +char* EspDrv::getCurrentSSID() +{ + LOGDEBUG(F("> getCurrentSSID")); + + _ssid[0] = 0; + sendCmdGet(F("AT+CWJAP?"), F("+CWJAP:\""), F("\""), _ssid, sizeof(_ssid)); + + return _ssid; +} + +uint8_t* EspDrv::getCurrentBSSID() +{ + LOGDEBUG(F("> getCurrentBSSID")); + + memset(_bssid, 0, WL_MAC_ADDR_LENGTH); + + char buf[20]; + if (sendCmdGet(F("AT+CWJAP?"), F(",\""), F("\","), buf, sizeof(buf))) + { + char* token; + + token = strtok(buf, ":"); + _bssid[5] = (byte)strtol(token, NULL, 16); + token = strtok(NULL, ":"); + _bssid[4] = (byte)strtol(token, NULL, 16); + token = strtok(NULL, ":"); + _bssid[3] = (byte)strtol(token, NULL, 16); + token = strtok(NULL, ":"); + _bssid[2] = (byte)strtol(token, NULL, 16); + token = strtok(NULL, ":"); + _bssid[1] = (byte)strtol(token, NULL, 16); + token = strtok(NULL, ":"); + _bssid[0] = (byte)strtol(token, NULL, 16); + } + return _bssid; + +} + +int32_t EspDrv::getCurrentRSSI() +{ + LOGDEBUG(F("> getCurrentRSSI")); + + int ret=0; + char buf[10]; + sendCmdGet(F("AT+CWJAP?"), F(",-"), F("\r\n"), buf, sizeof(buf)); + + if (isDigit(buf[0])) { + ret = -atoi(buf); + } + + return ret; +} + + +uint8_t EspDrv::getScanNetworks() +{ + uint8_t ssidListNum = 0; + int idx; + bool ret = false; + + + espEmptyBuf(); + + LOGDEBUG(F("----------------------------------------------")); + LOGDEBUG(F(">> AT+CWLAP")); + + espSerial->println(F("AT+CWLAP")); + + char buf[100]; + + idx = readUntil(10000, "+CWLAP:("); + + while (idx == NUMESPTAGS) + { + _networkEncr[ssidListNum] = espSerial->parseInt(); + + // discard , and " characters + readUntil(1000, "\""); + + idx = readUntil(1000, "\"", false); + if(idx==NUMESPTAGS) + { + memset(_networkSsid[ssidListNum], 0, WL_SSID_MAX_LENGTH ); + ringBuf.getStrN(_networkSsid[ssidListNum], 1, WL_SSID_MAX_LENGTH-1); + } + + // discard , character + readUntil(1000, ","); + + _networkRssi[ssidListNum] = espSerial->parseInt(); + + idx = readUntil(1000, "+CWLAP:("); + + if(ssidListNum==WL_NETWORKS_LIST_MAXNUM-1) + break; + + ssidListNum++; + } + + if (idx==-1) + return -1; + + LOGDEBUG1(F("---------------------------------------------- >"), ssidListNum); + LOGDEBUG(); + return ssidListNum; +} + +bool EspDrv::getNetmask(IPAddress& mask) { + LOGDEBUG(F("> getNetmask")); + + char buf[20]; + if (sendCmdGet(F("AT+CIPSTA?"), F("+CIPSTA:netmask:\""), F("\""), buf, sizeof(buf))) + { + mask.fromString (buf); + return true; + } + + return false; +} + +bool EspDrv::getGateway(IPAddress& gw) +{ + LOGDEBUG(F("> getGateway")); + + char buf[20]; + if (sendCmdGet(F("AT+CIPSTA?"), F("+CIPSTA:gateway:\""), F("\""), buf, sizeof(buf))) + { + gw.fromString (buf); + return true; + } + + return false; +} + +char* EspDrv::getSSIDNetoworks(uint8_t networkItem) +{ + if (networkItem >= WL_NETWORKS_LIST_MAXNUM) + return NULL; + + return _networkSsid[networkItem]; +} + +uint8_t EspDrv::getEncTypeNetowrks(uint8_t networkItem) +{ + if (networkItem >= WL_NETWORKS_LIST_MAXNUM) + return 0; + + return _networkEncr[networkItem]; +} + +int32_t EspDrv::getRSSINetoworks(uint8_t networkItem) +{ + if (networkItem >= WL_NETWORKS_LIST_MAXNUM) + return 0; + + return _networkRssi[networkItem]; +} + +char* EspDrv::getFwVersion() +{ + LOGDEBUG(F("> getFwVersion")); + + fwVersion[0] = 0; + + sendCmdGet(F("AT+GMR"), F("SDK version:"), F("\r\n"), fwVersion, sizeof(fwVersion)); + + return fwVersion; +} + + + +bool EspDrv::ping(const char *host) +{ + LOGDEBUG(F("> ping")); + + int ret = sendCmd(F("AT+PING=\"%s\""), 8000, host); + + if (ret==TAG_OK) + return true; + + return false; +} + + + +// Start server TCP on port specified +bool EspDrv::startServer(uint16_t port, uint8_t sock) +{ + LOGDEBUG1(F("> startServer"), port); + + int ret = sendCmd(F("AT+CIPSERVER=%d,%d"), 1000, sock, port); + + return ret==TAG_OK; +} + + +bool EspDrv::startClient(const char* host, uint16_t port, uint8_t sock, uint8_t protMode) +{ + LOGDEBUG2(F("> startClient"), host, port); + + // TCP + // AT+CIPSTART=,"TCP",, + + // UDP + // AT+CIPSTART=,"UDP",,[,,] + + // for UDP we set a dummy remote port and UDP mode to 2 + // this allows to specify the target host/port in CIPSEND + + int ret; + if (protMode==TCP_MODE) + ret = sendCmd(F("AT+CIPSTART=%d,\"TCP\",\"%s\",%u"), 5000, sock, host, port); + else if (protMode==SSL_MODE) + { + // better to put the CIPSSLSIZE here because it is not supported before firmware 1.4 + sendCmd(F("AT+CIPSSLSIZE=4096")); + ret = sendCmd(F("AT+CIPSTART=%d,\"SSL\",\"%s\",%u"), 5000, sock, host, port); + } + else if (protMode==UDP_MODE) + ret = sendCmd(F("AT+CIPSTART=%d,\"UDP\",\"%s\",0,%u,2"), 5000, sock, host, port); + + return ret==TAG_OK; +} + + +// Start server TCP on port specified +void EspDrv::stopClient(uint8_t sock) +{ + LOGDEBUG1(F("> stopClient"), sock); + + int ret = sendCmd(F("AT+CIPCLOSE=%d"), 4000, sock); +} + + +uint8_t EspDrv::getServerState(uint8_t sock) +{ + return 0; +} + + + +//////////////////////////////////////////////////////////////////////////// +// TCP/IP functions +//////////////////////////////////////////////////////////////////////////// + + + +uint16_t EspDrv::availData(uint8_t connId) +{ + //LOGDEBUG(bufPos); + + // if there is data in the buffer + if (_bufPos>0) + { + if (_connId==connId) + return _bufPos; + else if (_connId==0) + return _bufPos; + } + + + int bytes = espSerial->available(); + + if (bytes) + { + //LOGDEBUG1(F("Bytes in the serial buffer: "), bytes); + if (espSerial->find((char *)"+IPD,")) + { + // format is : +IPD,,: + // format is : +IPD,,[,,]: + + _connId = espSerial->parseInt(); // + espSerial->read(); // , + _bufPos = espSerial->parseInt(); // + espSerial->read(); // " + _remoteIp[0] = espSerial->parseInt(); // + espSerial->read(); // . + _remoteIp[1] = espSerial->parseInt(); + espSerial->read(); // . + _remoteIp[2] = espSerial->parseInt(); + espSerial->read(); // . + _remoteIp[3] = espSerial->parseInt(); + espSerial->read(); // " + espSerial->read(); // , + _remotePort = espSerial->parseInt(); // + + espSerial->read(); // : + + LOGDEBUG(); + LOGDEBUG2(F("Data packet"), _connId, _bufPos); + + if(_connId==connId || connId==0) + return _bufPos; + } + } + return 0; +} + + +bool EspDrv::getData(uint8_t connId, uint8_t *data, bool peek, bool* connClose) +{ + if (connId!=_connId) + return false; + + + // see Serial.timedRead + + long _startMillis = millis(); + do + { + if (espSerial->available()) + { + if (peek) + { + *data = (char)espSerial->peek(); + } + else + { + *data = (char)espSerial->read(); + _bufPos--; + } + //Serial.print((char)*data); + + if (_bufPos == 0) + { + // after the data packet a ",CLOSED" string may be received + // this means that the socket is now closed + + delay(5); + + if (espSerial->available()) + { + //LOGDEBUG(".2"); + //LOGDEBUG(espSerial->peek()); + + // 48 = '0' + if (espSerial->peek()==48+connId) + { + int idx = readUntil(500, ",CLOSED\r\n", false); + if(idx!=NUMESPTAGS) + { + LOGERROR(F("Tag CLOSED not found")); + } + + LOGDEBUG(); + LOGDEBUG(F("Connection closed")); + + *connClose=true; + } + } + } + + return true; + } + } while(millis() - _startMillis < 2000); + + // timed out, reset the buffer + LOGERROR1(F("TIMEOUT:"), _bufPos); + + _bufPos = 0; + _connId = 0; + *data = 0; + + return false; +} + +/** + * Receive the data into a buffer. + * It reads up to bufSize bytes. + * @return received data size for success else -1. + */ +int EspDrv::getDataBuf(uint8_t connId, uint8_t *buf, uint16_t bufSize) +{ + if (connId!=_connId) + return false; + + if(_bufPos sendData:"), sock, len); + + char cmdBuf[20]; + sprintf_P(cmdBuf, PSTR("AT+CIPSEND=%d,%u"), sock, len); + espSerial->println(cmdBuf); + + int idx = readUntil(1000, (char *)">", false); + if(idx!=NUMESPTAGS) + { + LOGERROR(F("Data packet send error (1)")); + return false; + } + + espSerial->write(data, len); + + idx = readUntil(2000); + if(idx!=TAG_SENDOK) + { + LOGERROR(F("Data packet send error (2)")); + return false; + } + + return true; +} + +// Overrided sendData method for __FlashStringHelper strings +bool EspDrv::sendData(uint8_t sock, const __FlashStringHelper *data, uint16_t len, bool appendCrLf) +{ + LOGDEBUG2(F("> sendData:"), sock, len); + + char cmdBuf[20]; + uint16_t len2 = len + 2*appendCrLf; + sprintf_P(cmdBuf, PSTR("AT+CIPSEND=%d,%u"), sock, len2); + espSerial->println(cmdBuf); + + int idx = readUntil(1000, (char *)">", false); + if(idx!=NUMESPTAGS) + { + LOGERROR(F("Data packet send error (1)")); + return false; + } + + //espSerial->write(data, len); + PGM_P p = reinterpret_cast(data); + for (int i=0; iwrite(c); + } + if (appendCrLf) + { + espSerial->write('\r'); + espSerial->write('\n'); + } + + idx = readUntil(2000); + if(idx!=TAG_SENDOK) + { + LOGERROR(F("Data packet send error (2)")); + return false; + } + + return true; +} + +bool EspDrv::sendDataUdp(uint8_t sock, const char* host, uint16_t port, const uint8_t *data, uint16_t len) +{ + LOGDEBUG2(F("> sendDataUdp:"), sock, len); + LOGDEBUG2(F("> sendDataUdp:"), host, port); + + char cmdBuf[40]; + sprintf_P(cmdBuf, PSTR("AT+CIPSEND=%d,%u,\"%s\",%u"), sock, len, host, port); + //LOGDEBUG1(F("> sendDataUdp:"), cmdBuf); + espSerial->println(cmdBuf); + + int idx = readUntil(1000, (char *)">", false); + if(idx!=NUMESPTAGS) + { + LOGERROR(F("Data packet send error (1)")); + return false; + } + + espSerial->write(data, len); + + idx = readUntil(2000); + if(idx!=TAG_SENDOK) + { + LOGERROR(F("Data packet send error (2)")); + return false; + } + + return true; +} + + + +void EspDrv::getRemoteIpAddress(IPAddress& ip) +{ + ip = _remoteIp; +} + +uint16_t EspDrv::getRemotePort() +{ + return _remotePort; +} + + +//////////////////////////////////////////////////////////////////////////// +// Utility functions +//////////////////////////////////////////////////////////////////////////// + + + +/* +* Sends the AT command and stops if any of the TAGS is found. +* Extract the string enclosed in the passed tags and returns it in the outStr buffer. +* Returns true if the string is extracted, false if tags are not found of timed out. +*/ +bool EspDrv::sendCmdGet(const __FlashStringHelper* cmd, const char* startTag, const char* endTag, char* outStr, int outStrLen) +{ + int idx; + bool ret = false; + + outStr[0] = 0; + + espEmptyBuf(); + + LOGDEBUG(F("----------------------------------------------")); + LOGDEBUG1(F(">>"), cmd); + + // send AT command to ESP + espSerial->println(cmd); + + // read result until the startTag is found + idx = readUntil(1000, startTag); + + if(idx==NUMESPTAGS) + { + // clean the buffer to get a clean string + ringBuf.init(); + + // start tag found, search the endTag + idx = readUntil(500, endTag); + + if(idx==NUMESPTAGS) + { + // end tag found + // copy result to output buffer avoiding overflow + ringBuf.getStrN(outStr, strlen(endTag), outStrLen-1); + + // read the remaining part of the response + readUntil(2000); + + ret = true; + } + else + { + LOGWARN(F("End tag not found")); + } + } + else if(idx>=0 and idx"), outStr); + LOGDEBUG(); + + return ret; +} + +bool EspDrv::sendCmdGet(const __FlashStringHelper* cmd, const __FlashStringHelper* startTag, const __FlashStringHelper* endTag, char* outStr, int outStrLen) +{ + char _startTag[strlen_P((char*)startTag)+1]; + strcpy_P(_startTag, (char*)startTag); + + char _endTag[strlen_P((char*)endTag)+1]; + strcpy_P(_endTag, (char*)endTag); + + return sendCmdGet(cmd, _startTag, _endTag, outStr, outStrLen); +} + + +/* +* Sends the AT command and returns the id of the TAG. +* Return -1 if no tag is found. +*/ +int EspDrv::sendCmd(const __FlashStringHelper* cmd, int timeout) +{ + espEmptyBuf(); + + LOGDEBUG(F("----------------------------------------------")); + LOGDEBUG1(F(">>"), cmd); + + espSerial->println(cmd); + + int idx = readUntil(timeout); + + LOGDEBUG1(F("---------------------------------------------- >"), idx); + LOGDEBUG(); + + return idx; +} + + +/* +* Sends the AT command and returns the id of the TAG. +* The additional arguments are formatted into the command using sprintf. +* Return -1 if no tag is found. +*/ +int EspDrv::sendCmd(const __FlashStringHelper* cmd, int timeout, ...) +{ + char cmdBuf[CMD_BUFFER_SIZE]; + + va_list args; + va_start (args, timeout); + vsnprintf_P (cmdBuf, CMD_BUFFER_SIZE, (char*)cmd, args); + va_end (args); + + espEmptyBuf(); + + LOGDEBUG(F("----------------------------------------------")); + LOGDEBUG1(F(">>"), cmdBuf); + + espSerial->println(cmdBuf); + + int idx = readUntil(timeout); + + LOGDEBUG1(F("---------------------------------------------- >"), idx); + LOGDEBUG(); + + return idx; +} + + +// Read from serial until one of the tags is found +// Returns: +// the index of the tag found in the ESPTAGS array +// -1 if no tag was found (timeout) +int EspDrv::readUntil(int timeout, const char* tag, bool findTags) +{ + ringBuf.reset(); + + char c; + unsigned long start = millis(); + int ret = -1; + + while ((millis() - start < timeout) and ret<0) + { + if(espSerial->available()) + { + c = (char)espSerial->read(); + LOGDEBUG0(c); + ringBuf.push(c); + + if (tag!=NULL) + { + if (ringBuf.endsWith(tag)) + { + ret = NUMESPTAGS; + //LOGDEBUG1("xxx"); + } + } + if(findTags) + { + for(int i=0; i= timeout) + { + LOGWARN(F(">>> TIMEOUT >>>")); + } + + return ret; +} + + +void EspDrv::espEmptyBuf(bool warn) +{ + char c; + int i=0; + while(espSerial->available() > 0) + { + c = espSerial->read(); + if (i>0 and warn==true) + LOGDEBUG0(c); + i++; + } + if (i>0 and warn==true) + { + LOGDEBUG(F("")); + LOGDEBUG1(F("Dirty characters in the serial buffer! >"), i); + } +} + + +// copied from Serial::timedRead +int EspDrv::timedRead() +{ + int _timeout = 1000; + int c; + long _startMillis = millis(); + do + { + c = espSerial->read(); + if (c >= 0) return c; + } while(millis() - _startMillis < _timeout); + + return -1; // -1 indicates timeout +} + + + +EspDrv espDrv; diff --git a/lib/WiFiEsp/src/utility/EspDrv.h b/lib/WiFiEsp/src/utility/EspDrv.h new file mode 100644 index 0000000..5c782d9 --- /dev/null +++ b/lib/WiFiEsp/src/utility/EspDrv.h @@ -0,0 +1,340 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library 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. + +The Arduino WiFiEsp library 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 The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#ifndef EspDrv_h +#define EspDrv_h + +#include "Stream.h" +#include "IPAddress.h" + + +#include "RingBuffer.h" + + + +// Maximum size of a SSID +#define WL_SSID_MAX_LENGTH 32 + +// Size of a MAC-address or BSSID +#define WL_MAC_ADDR_LENGTH 6 + +// Size of a MAC-address or BSSID +#define WL_IPV4_LENGTH 4 + +// Maximum size of a SSID list +#define WL_NETWORKS_LIST_MAXNUM 10 + +// Maxmium number of socket +#define MAX_SOCK_NUM 4 + +// Socket not available constant +#define SOCK_NOT_AVAIL 255 + +// Default state value for Wifi state field +#define NA_STATE -1 + +#define WL_FW_VER_LENGTH 6 + +#define NO_SOCKET_AVAIL 255 + + +// maximum size of AT command +#define CMD_BUFFER_SIZE 200 + + +typedef enum eProtMode {TCP_MODE, UDP_MODE, SSL_MODE} tProtMode; + + +typedef enum { + WL_FAILURE = -1, + WL_SUCCESS = 1, +} wl_error_code_t; + +/* Authentication modes */ +enum wl_auth_mode { + AUTH_MODE_INVALID, + AUTH_MODE_AUTO, + AUTH_MODE_OPEN_SYSTEM, + AUTH_MODE_SHARED_KEY, + AUTH_MODE_WPA, + AUTH_MODE_WPA2, + AUTH_MODE_WPA_PSK, + AUTH_MODE_WPA2_PSK +}; + + +typedef enum { + WL_NO_SHIELD = 255, + WL_IDLE_STATUS = 0, + //WL_NO_SSID_AVAIL, + //WL_SCAN_COMPLETED, + WL_CONNECTED, + WL_CONNECT_FAILED, + //WL_CONNECTION_LOST, + WL_DISCONNECTED +} wl_status_t; + +/* Encryption modes */ +enum wl_enc_type { + ENC_TYPE_NONE = 0, + ENC_TYPE_WEP = 1, + ENC_TYPE_WPA_PSK = 2, + ENC_TYPE_WPA2_PSK = 3, + ENC_TYPE_WPA_WPA2_PSK = 4 +}; + + +enum wl_tcp_state { + CLOSED = 0, + LISTEN = 1, + SYN_SENT = 2, + SYN_RCVD = 3, + ESTABLISHED = 4, + FIN_WAIT_1 = 5, + FIN_WAIT_2 = 6, + CLOSE_WAIT = 7, + CLOSING = 8, + LAST_ACK = 9, + TIME_WAIT = 10 +}; + + + +class EspDrv +{ + +public: + + static void wifiDriverInit(Stream *espSerial); + + + /* Start Wifi connection with passphrase + * + * param ssid: Pointer to the SSID string. + * param passphrase: Passphrase. Valid characters in a passphrase must be between ASCII 32-126 (decimal). + */ + static bool wifiConnect(const char* ssid, const char* passphrase); + + + /* + * Start the Access Point + */ + static bool wifiStartAP(const char* ssid, const char* pwd, uint8_t channel, uint8_t enc, uint8_t espMode); + + + /* + * Set ip configuration disabling dhcp client + */ + static void config(IPAddress local_ip); + + /* + * Set ip configuration disabling dhcp client + */ + static void configAP(IPAddress local_ip); + + + /* + * Disconnect from the network + * + * return: WL_SUCCESS or WL_FAILURE + */ + static int8_t disconnect(); + + /* + * + * + * return: one value of wl_status_t enum + */ + static uint8_t getConnectionStatus(); + + /* + * Get the interface MAC address. + * + * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + */ + static uint8_t* getMacAddress(); + + /* + * Get the interface IP address. + * + * return: copy the ip address value in IPAddress object + */ + static void getIpAddress(IPAddress& ip); + + static void getIpAddressAP(IPAddress& ip); + + /* + * Get the interface IP netmask. + * This can be used to retrieve settings configured through DHCP. + * + * return: true if successful + */ + static bool getNetmask(IPAddress& mask); + + /* + * Get the interface IP gateway. + * This can be used to retrieve settings configured through DHCP. + * + * return: true if successful + */ + static bool getGateway(IPAddress& mask); + + /* + * Return the current SSID associated with the network + * + * return: ssid string + */ + static char* getCurrentSSID(); + + /* + * Return the current BSSID associated with the network. + * It is the MAC address of the Access Point + * + * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + */ + static uint8_t* getCurrentBSSID(); + + /* + * Return the current RSSI /Received Signal Strength in dBm) + * associated with the network + * + * return: signed value + */ + static int32_t getCurrentRSSI(); + + /* + * Get the networks available + * + * return: Number of discovered networks + */ + static uint8_t getScanNetworks(); + + /* + * Return the SSID discovered during the network scan. + * + * param networkItem: specify from which network item want to get the information + * + * return: ssid string of the specified item on the networks scanned list + */ + static char* getSSIDNetoworks(uint8_t networkItem); + + /* + * Return the RSSI of the networks discovered during the scanNetworks + * + * param networkItem: specify from which network item want to get the information + * + * return: signed value of RSSI of the specified item on the networks scanned list + */ + static int32_t getRSSINetoworks(uint8_t networkItem); + + /* + * Return the encryption type of the networks discovered during the scanNetworks + * + * param networkItem: specify from which network item want to get the information + * + * return: encryption type (enum wl_enc_type) of the specified item on the networks scanned list + */ + static uint8_t getEncTypeNetowrks(uint8_t networkItem); + + + /* + * Get the firmware version + */ + static char* getFwVersion(); + + + //////////////////////////////////////////////////////////////////////////// + // Client/Server methods + //////////////////////////////////////////////////////////////////////////// + + + static bool startServer(uint16_t port, uint8_t sock); + static bool startClient(const char* host, uint16_t port, uint8_t sock, uint8_t protMode); + static void stopClient(uint8_t sock); + static uint8_t getServerState(uint8_t sock); + static uint8_t getClientState(uint8_t sock); + static bool getData(uint8_t connId, uint8_t *data, bool peek, bool* connClose); + static int getDataBuf(uint8_t connId, uint8_t *buf, uint16_t bufSize); + static bool sendData(uint8_t sock, const uint8_t *data, uint16_t len); + static bool sendData(uint8_t sock, const __FlashStringHelper *data, uint16_t len, bool appendCrLf=false); + static bool sendDataUdp(uint8_t sock, const char* host, uint16_t port, const uint8_t *data, uint16_t len); + static uint16_t availData(uint8_t connId); + + + static bool ping(const char *host); + static void reset(); + + static void getRemoteIpAddress(IPAddress& ip); + static uint16_t getRemotePort(); + + +//////////////////////////////////////////////////////////////////////////////// + +private: + static Stream *espSerial; + + static long _bufPos; + static uint8_t _connId; + + static uint16_t _remotePort; + static uint8_t _remoteIp[WL_IPV4_LENGTH]; + + + // firmware version string + static char fwVersion[WL_FW_VER_LENGTH]; + + // settings of requested network + static char _networkSsid[WL_NETWORKS_LIST_MAXNUM][WL_SSID_MAX_LENGTH]; + static int32_t _networkRssi[WL_NETWORKS_LIST_MAXNUM]; + static uint8_t _networkEncr[WL_NETWORKS_LIST_MAXNUM]; + + + // settings of current selected network + static char _ssid[WL_SSID_MAX_LENGTH]; + static uint8_t _bssid[WL_MAC_ADDR_LENGTH]; + static uint8_t _mac[WL_MAC_ADDR_LENGTH]; + static uint8_t _localIp[WL_IPV4_LENGTH]; + + + // the ring buffer is used to search the tags in the stream + static RingBuffer ringBuf; + + + //static int sendCmd(const char* cmd, int timeout=1000); + static int sendCmd(const __FlashStringHelper* cmd, int timeout=1000); + static int sendCmd(const __FlashStringHelper* cmd, int timeout, ...); + + static bool sendCmdGet(const __FlashStringHelper* cmd, const char* startTag, const char* endTag, char* outStr, int outStrLen); + static bool sendCmdGet(const __FlashStringHelper* cmd, const __FlashStringHelper* startTag, const __FlashStringHelper* endTag, char* outStr, int outStrLen); + + static int readUntil(int timeout, const char* tag=NULL, bool findTags=true); + + static void espEmptyBuf(bool warn=true); + + static int timedRead(); + + + friend class WiFiEsp; + friend class WiFiEspServer; + friend class WiFiEspClient; + friend class WiFiEspUdp; +}; + +extern EspDrv espDrv; + +#endif diff --git a/lib/WiFiEsp/src/utility/RingBuffer.cpp b/lib/WiFiEsp/src/utility/RingBuffer.cpp new file mode 100644 index 0000000..e5fa3c4 --- /dev/null +++ b/lib/WiFiEsp/src/utility/RingBuffer.cpp @@ -0,0 +1,105 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library 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. + +The Arduino WiFiEsp library 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 The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#include "RingBuffer.h" + +#include + +RingBuffer::RingBuffer(unsigned int size) +{ + _size = size; + // add one char to terminate the string + ringBuf = new char[size+1]; + ringBufEnd = &ringBuf[size]; + init(); +} + +RingBuffer::~RingBuffer() {} + +void RingBuffer::reset() +{ + ringBufP = ringBuf; +} + +void RingBuffer::init() +{ + ringBufP = ringBuf; + memset(ringBuf, 0, _size+1); +} + +void RingBuffer::push(char c) +{ + *ringBufP = c; + ringBufP++; + if (ringBufP>=ringBufEnd) + ringBufP = ringBuf; +} + + + +bool RingBuffer::endsWith(const char* str) +{ + int findStrLen = strlen(str); + + // b is the start position into the ring buffer + char* b = ringBufP-findStrLen; + if(b < ringBuf) + b = b + _size; + + char *p1 = (char*)&str[0]; + char *p2 = p1 + findStrLen; + + for(char *p=p1; pnum) + len=num; + + // copy buffer to destination string + strncpy(destination, ringBuf, len); + + // terminate output string + //destination[len]=0; +} diff --git a/lib/WiFiEsp/src/utility/RingBuffer.h b/lib/WiFiEsp/src/utility/RingBuffer.h new file mode 100644 index 0000000..437ff66 --- /dev/null +++ b/lib/WiFiEsp/src/utility/RingBuffer.h @@ -0,0 +1,47 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library 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. + +The Arduino WiFiEsp library 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 The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#ifndef RingBuffer_h +#define RingBuffer_h + + +class RingBuffer +{ +public: + RingBuffer(unsigned int size); + ~RingBuffer(); + + void reset(); + void init(); + void push(char c); + int getPos(); + bool endsWith(const char* str); + void getStr(char * destination, unsigned int skipChars); + void getStrN(char * destination, unsigned int skipChars, unsigned int num); + + +private: + + unsigned int _size; + char* ringBuf; + char* ringBufEnd; + char* ringBufP; + +}; + +#endif \ No newline at end of file diff --git a/lib/WiFiEsp/src/utility/debug.h b/lib/WiFiEsp/src/utility/debug.h new file mode 100644 index 0000000..4187469 --- /dev/null +++ b/lib/WiFiEsp/src/utility/debug.h @@ -0,0 +1,49 @@ +/*-------------------------------------------------------------------- +This file is part of the Arduino WiFiEsp library. + +The Arduino WiFiEsp library 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. + +The Arduino WiFiEsp library 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 The Arduino WiFiEsp library. If not, see +. +--------------------------------------------------------------------*/ + +#ifndef EspDebug_H +#define EspDebug_H + +#include + +// Change _ESPLOGLEVEL_ to set tracing and logging verbosity +// 0: DISABLED: no logging +// 1: ERROR: errors +// 2: WARN: errors and warnings +// 3: INFO: errors, warnings and informational (default) +// 4: DEBUG: errors, warnings, informational and debug + +#ifndef _ESPLOGLEVEL_ +#define _ESPLOGLEVEL_ 2 +#endif + + +#define LOGERROR(x) if(_ESPLOGLEVEL_>0) { Serial.print("[WiFiEsp] "); Serial.println(x); } +#define LOGERROR1(x,y) if(_ESPLOGLEVEL_>2) { Serial.print("[WiFiEsp] "); Serial.print(x); Serial.print(" "); Serial.println(y); } +#define LOGWARN(x) if(_ESPLOGLEVEL_>1) { Serial.print("[WiFiEsp] "); Serial.println(x); } +#define LOGWARN1(x,y) if(_ESPLOGLEVEL_>2) { Serial.print("[WiFiEsp] "); Serial.print(x); Serial.print(" "); Serial.println(y); } +#define LOGINFO(x) if(_ESPLOGLEVEL_>2) { Serial.print("[WiFiEsp] "); Serial.println(x); } +#define LOGINFO1(x,y) if(_ESPLOGLEVEL_>2) { Serial.print("[WiFiEsp] "); Serial.print(x); Serial.print(" "); Serial.println(y); } + +#define LOGDEBUG(x) if(_ESPLOGLEVEL_>3) { Serial.println(x); } +#define LOGDEBUG0(x) if(_ESPLOGLEVEL_>3) { Serial.print(x); } +#define LOGDEBUG1(x,y) if(_ESPLOGLEVEL_>3) { Serial.print(x); Serial.print(" "); Serial.println(y); } +#define LOGDEBUG2(x,y,z) if(_ESPLOGLEVEL_>3) { Serial.print(x); Serial.print(" "); Serial.print(y); Serial.print(" "); Serial.println(z); } + + +#endif diff --git a/lib/WiFiEsp/test/BasicTest/BasicTest.ino b/lib/WiFiEsp/test/BasicTest/BasicTest.ino new file mode 100644 index 0000000..eb768e8 --- /dev/null +++ b/lib/WiFiEsp/test/BasicTest/BasicTest.ino @@ -0,0 +1,142 @@ +/* + WiFiEsp test: BasicTest + + Performs basic connectivity test and checks. +*/ + +#include "WiFiEsp.h" + +// Emulate Serial1 on pins 7/6 if not present +#ifndef HAVE_HWSERIAL1 +#include "SoftwareSerial.h" +SoftwareSerial Serial1(6, 7); // RX, TX +#endif + + +char ssid[] = "Twim"; // your network SSID (name) +char pwd[] = "12345678"; // your network password +char pwdErr[] = "xxxx"; // wrong password + + +void setup() +{ + Serial.begin(115200); + Serial1.begin(9600); + WiFi.init(&Serial1); +} + +void loop() +{ + assertEquals("Firmware version", WiFi.firmwareVersion(), "1.5.2"); + assertEquals("Status is (WL_DISCONNECTED)", WiFi.status(), WL_DISCONNECTED); + assertEquals("Connect", WiFi.begin(ssid, pwd), WL_CONNECTED); + assertEquals("Check status (WL_CONNECTED)", WiFi.status(), WL_CONNECTED); + assertEquals("Check SSID", WiFi.SSID(), ssid); + + IPAddress ip = WiFi.localIP(); + assertNotEquals("Check IP Address", ip[0], 0); + Serial.print("IP Address: "); + Serial.println(ip); + + byte mac[6]={0,0,0,0,0,0}; + WiFi.macAddress(mac); + + Serial.print("MAC: "); + Serial.print(mac[5], HEX); + Serial.print(":"); + Serial.print(mac[4], HEX); + Serial.print(":"); + Serial.print(mac[3], HEX); + Serial.print(":"); + Serial.print(mac[2], HEX); + Serial.print(":"); + Serial.print(mac[1], HEX); + Serial.print(":"); + Serial.println(mac[0], HEX); + Serial.println(); + + assertEquals("Disconnect", WiFi.disconnect(), WL_DISCONNECTED); + assertEquals("Check status (WL_DISCONNECTED)", WiFi.status(), WL_DISCONNECTED); + assertEquals("IP Address", WiFi.localIP(), 0); + assertEquals("Check SSID", WiFi.SSID(), ""); + assertEquals("Wrong pwd", WiFi.begin(ssid, pwdErr), WL_CONNECT_FAILED); + + IPAddress localIp(192, 168, 168, 111); + WiFi.config(localIp); + + assertEquals("Connect", WiFi.begin(ssid, pwd), WL_CONNECTED); + assertEquals("Check status (WL_CONNECTED)", WiFi.status(), WL_CONNECTED); + + ip = WiFi.localIP(); + assertNotEquals("Check IP Address", ip[0], 0); + + + Serial.println("END OF TESTS"); + delay(60000); +} + + +//////////////////////////////////////////////////////////////////////////////////// + + +void assertNotEquals(const char* test, int actual, int expected) +{ + if(actual!=expected) + pass(test); + else + fail(test, actual, expected); +} + +void assertEquals(const char* test, int actual, int expected) +{ + if(actual==expected) + pass(test); + else + fail(test, actual, expected); +} + +void assertEquals(const char* test, char* actual, char* expected) +{ + if(strcmp(actual, expected) == 0) + pass(test); + else + fail(test, actual, expected); +} + + +void pass(const char* test) +{ + Serial.print(F("********************************************** ")); + Serial.print(test); + Serial.println(" > PASSED"); + Serial.println(); +} + +void fail(const char* test, char* actual, char* expected) +{ + Serial.print(F("********************************************** ")); + Serial.print(test); + Serial.print(" > FAILED"); + Serial.print(" (actual=\""); + Serial.print(actual); + Serial.print("\", expected=\""); + Serial.print(expected); + Serial.println("\")"); + Serial.println(); + delay(10000); +} + +void fail(const char* test, int actual, int expected) +{ + Serial.print(F("********************************************** ")); + Serial.print(test); + Serial.print(" > FAILED"); + Serial.print(" (actual="); + Serial.print(actual); + Serial.print(", expected="); + Serial.print(expected); + Serial.println(")"); + Serial.println(); + delay(10000); +} + diff --git a/lib/WiFiEsp/test/ClientTest/ClientTest.ino b/lib/WiFiEsp/test/ClientTest/ClientTest.ino new file mode 100644 index 0000000..0e544ef --- /dev/null +++ b/lib/WiFiEsp/test/ClientTest/ClientTest.ino @@ -0,0 +1,184 @@ +/* + WiFiEsp test: ClientTest + + Test client functions. +*/ + +#include "WiFiEsp.h" + +// Emulate Serial1 on pins 7/6 if not present +#ifndef HAVE_HWSERIAL1 +#include "SoftwareSerial.h" +SoftwareSerial Serial1(6, 7); // RX, TX +#endif + + +char ssid[] = "Twim"; // your network SSID (name) +char pwd[] = "12345678"; // your network password + + +// Initialize the Wifi client library +WiFiEspClient client; + +void setup() +{ + Serial.begin(115200); + Serial1.begin(9600); + WiFi.init(&Serial1); +} + +void loop() +{ + bool f; + int c; + + + assertEquals("Check status WL_DISCONNECTED", WiFi.status(), WL_DISCONNECTED); + + assertEquals("Connect", WiFi.begin(ssid, pwd), WL_CONNECTED); + + assertEquals("Check status WL_CONNECTED", WiFi.status(), WL_CONNECTED); + + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + assertEquals("Ping", WiFi.ping("www.google.com"), true); + + assertEquals("Not connected", client.connected(), false); + assertEquals("Connect to server", client.connect("www.brainjar.com", 80), 1); + assertEquals("Connected", client.connected(), true); + + + //-------------------------------------------------------------- + // HTTP request without 'Connection: close' command + + client.println("GET /java/host/test.html HTTP/1.1"); + client.println("Host: www.brainjar.com"); + client.println(); + + // wait for the response + long _startMillis = millis(); + while (!client.available() and (millis()-_startMillis < 2000)) + { + } + + assertEquals("Response received", (millis()-_startMillis < 2000), true); + + f = client.find(""); + assertEquals("Response check", f, true); + if (f) + { + while( (c = client.read()) > 0) + Serial.print((char)c); + } + + assertEquals("Connected", client.connected(), true); + + + //-------------------------------------------------------------- + + delay(5000); + + assertEquals("Check status WL_CONNECTED", WiFi.status(), WL_CONNECTED); + + assertEquals("Connected", client.connected(), true); + + + //-------------------------------------------------------------- + // HTTP request without 'Connection: close' command + + client.println("GET /java/host/test.html HTTP/1.1"); + client.println("Host: www.brainjar.com"); + client.println("Connection: close"); + client.println(); + + + // wait for the response + _startMillis = millis(); + while (!client.available() and (millis()-_startMillis < 2000)) + { + } + + assertEquals("Response received", (millis()-_startMillis < 2000), true); + + f = client.find(""); + assertEquals("Response check", f, true); + if (f) + { + while( (c = client.read()) > 0) + Serial.print((char)c); + } + + //-------------------------------------------------------------- + + assertEquals("Check status WL_CONNECTED", WiFi.status(), WL_CONNECTED); + assertEquals("Not connected", client.connected(), false); + + assertEquals("Ping", WiFi.ping("www.google.com"), true); + + assertEquals("Connect", WiFi.disconnect(), WL_DISCONNECTED); + assertEquals("Check status WL_DISCONNECTED", WiFi.status(), WL_DISCONNECTED); + + Serial.println("END OF TESTS"); + delay(30000); +} + + +//////////////////////////////////////////////////////////////////////////////////// + + +void assertEquals(const char* test, int actual, int expected) +{ + if(actual==expected) + pass(test); + else + fail(test, actual, expected); +} + +void assertEquals(const char* test, char* actual, char* expected) +{ + if(strcmp(actual, expected) == 0) + pass(test); + else + fail(test, actual, expected); +} + + +void pass(const char* test) +{ + Serial.print(F("********************************************** ")); + Serial.print(test); + Serial.println(" > PASSED"); + Serial.println(); +} + +void fail(const char* test, char* actual, char* expected) +{ + Serial.print(F("********************************************** ")); + Serial.print(test); + Serial.print(" > FAILED"); + Serial.print(" (actual=\""); + Serial.print(actual); + Serial.print("\", expected=\""); + Serial.print(expected); + Serial.println("\")"); + Serial.println(); + delay(10000); +} + +void fail(const char* test, int actual, int expected) +{ + Serial.print(F("********************************************** ")); + Serial.print(test); + Serial.print(" > FAILED"); + Serial.print(" (actual="); + Serial.print(actual); + Serial.print(", expected="); + Serial.print(expected); + Serial.println(")"); + Serial.println(); + delay(10000); +} + + diff --git a/lib/WiFiEsp/test/EspDebug/EspDebug.ino b/lib/WiFiEsp/test/EspDebug/EspDebug.ino new file mode 100644 index 0000000..6824f6c --- /dev/null +++ b/lib/WiFiEsp/test/EspDebug/EspDebug.ino @@ -0,0 +1,48 @@ +// EspDebug - Test sketch for ESP8266 module + +#include "Arduino.h" + +// Emulate Serial1 on pins 7/6 if not present +#ifndef HAVE_HWSERIAL1 +#include "SoftwareSerial.h" +SoftwareSerial Serial1(6, 7); // RX, TX +#endif + +void setup() +{ + Serial.begin(115200); // serial port used for debugging + Serial1.begin(9600); // your ESP's baud rate might be different +} + +void loop() +{ + if(Serial1.available()) // check if the ESP is sending a message + { + while(Serial1.available()) + { + int c = Serial1.read(); // read the next character + Serial.write((char)c); // writes data to the serial monitor + } + } + + if(Serial.available()) + { + // wait to let all the input command in the serial buffer + delay(10); + + // read the input command in a string + String cmd = ""; + while(Serial.available()) + { + cmd += (char)Serial.read(); + } + + // print the command and send it to the ESP + Serial.println(); + Serial.print(">>>> "); + Serial.println(cmd); + + // send the read character to the ESP + Serial1.print(cmd); + } +} diff --git a/lib/WiFiEsp/test/RingBufferTest/RingBufferTest.ino b/lib/WiFiEsp/test/RingBufferTest/RingBufferTest.ino new file mode 100644 index 0000000..2fb75c0 --- /dev/null +++ b/lib/WiFiEsp/test/RingBufferTest/RingBufferTest.ino @@ -0,0 +1,58 @@ +/* + WiFiEsp test: RingBufferTest + + Test of the RingBuffer class. +*/ + +#include "WiFiEsp.h" + +RingBuffer buf(5); + + +void setup() +{ + Serial.begin(115200); + + Serial.println("Starting tests"); + + buf.init(); + + buf.push('a'); + assert(10, buf.endsWith("a"), true); + assert(11, buf.endsWith("A"), false); + assert(12, buf.endsWith("ab"), false); + + buf.push('b'); + assert(21, buf.endsWith("a"), false); + assert(22, buf.endsWith("A"), false); + assert(23, buf.endsWith("ab"), true); + + buf.push('c'); + buf.push('d'); + buf.push('e'); + assert(31, buf.endsWith("abcde"), true); + assert(32, buf.endsWith("de"), true); + + buf.push('f'); + assert(43, buf.endsWith("bcdef"), true); + assert(44, buf.endsWith("ef"), true); + + Serial.println("Done"); +} + + +void loop() +{ + // nothing to do +} + + +void assert(int i, bool x, bool y) +{ + if (x!=y) + { + Serial.print ("FAIL "); + Serial.println(i); + } +} + diff --git a/lib/WiFiNINA/CHANGELOG b/lib/WiFiNINA/CHANGELOG new file mode 100644 index 0000000..ad6e784 --- /dev/null +++ b/lib/WiFiNINA/CHANGELOG @@ -0,0 +1,62 @@ +WiFiNINA ?.?.? - ????.??.?? + +WiFiNINA 1.8.0 - 2020.11.18 + +* Limit the maximum length of the download URL for the OTA binary since the receive buffer on the nina firmware can't hold more than 128 bytes (#131) +* Introduce WiFiBearSSLClient (offloaded to Nina) (#139) +* Change WIFI_FIRMWARE_LATEST_VERSION to 1.4.2 + +WiFiNINA 1.7.1 - 2020.08.26 + +* Change WIFI_FIRMWARE_LATEST_VERSION to 1.4.1 + +WiFiNINA 1.7.0 - 2020.08.06 + +* Add downloadOTA command to download OTA file and verify length/CRC (#124) (to be used together with nina-fw > arduino/nina-fw@d4a2118) + +WiFiNINA 1.6.0 - 2020.07.13 + +* Adding API to make use of file storage/retieval capability available since nina-fw 1.5.0 (#74) +* Speed up of duration of function ServerDrv::getDataBuf (#84) + +WiFiNINA 1.5.0 - 2019.12.30 + +* Add WiFi.reasonCode() API to retrieve the deauthentication reason code +* Use WIFI_FIRMWARE_LATEST_VERSION in example sketch FW version checks +* Updated firmware updaters for Nano 33 IoT +* Added Nano 33 IoT to explicit targets list +* Added WPA2 Enterprise support: PEAP/MSCHAPv2 (depends on NINA f/w 1.3.0) + +WiFiNINA 1.4.0 - 2019.03.27 + +* Improved connection time, by increasing poll time of checking connection status to 100ms on begin +* Added WiFiClass::setTimeout(...) API to set timeout of begin +* Fixed issue of WiFiServer:available() only reporting the first byte in the WiFiChatServer example + +WiFiNINA 1.3.0 - 2018.11.13 + +* Added Tools/CheckFirmwareVersion example to check NINA firmware version +* Changed examples where required, the server's URL arduino.cc:80 to example.org:80, because http://arduino.cc will be no longer available +* Changed WiFi.end() to not put the reset pin mode in input mode +* Use 1000000 baud for the firmware updater, and added support for the Uno WiFi Rev2 + +WiFiNINA 1.2.0 - 2018.10.05 + +* Changed WiFi.begin(...) not to fail, if not connected in 5 seconds +* Removed retrying to get the host by name if it fails +* Renamed WiFiNINAFirmwareUpdater example to SerialNINAPassthrough +* Added new Firmware Updater Tool sketch (which talks to ESP32 boot ROM) +* Changed firmware version comparison check to < instead of != + +WiFiNINA 1.1.1 - 2018.09.11 + +* Improved byte by byte read performance of sockets by adding a socket buffer + +WiFiNINA 1.1.0 - 2018.08.13 + +* Added support for MKR Vidor 4000 +* Added handling of unknown encryption type in the ScanNetworks example + +WiFiNINA 1.0.0 - 2018.07.11 + +* Initial release diff --git a/lib/WiFiNINA/README.adoc b/lib/WiFiNINA/README.adoc new file mode 100644 index 0000000..5cb7576 --- /dev/null +++ b/lib/WiFiNINA/README.adoc @@ -0,0 +1,35 @@ +// Define the repository information in these attributes +:repository-owner: arduino-libraries +:repository-name: WiFiNINA + += {repository-name} library for Arduino = + +image:https://github.com/{repository-owner}/{repository-name}/actions/workflows/check-arduino.yml/badge.svg["Check Arduino status", link="https://github.com/{repository-owner}/{repository-name}/actions/workflows/check-arduino.yml"] +image:https://github.com/{repository-owner}/{repository-name}/actions/workflows/compile-examples.yml/badge.svg["Compile Examples status", link="https://github.com/{repository-owner}/{repository-name}/actions/workflows/compile-examples.yml"] +image:https://github.com/{repository-owner}/{repository-name}/actions/workflows/spell-check.yml/badge.svg["Spell Check status", link="https://github.com/{repository-owner}/{repository-name}/actions/workflows/spell-check.yml"] + +Enables network connection (local and Internet) with the Arduino MKR WiFi 1010, Arduino MKR VIDOR 4000 and Arduino UNO WiFi Rev.2. + +With this library you can instantiate Servers, Clients and send/receive UDP packets through WiFi. The board can connect either to open or encrypted networks (WEP, WPA). The IP address can be assigned statically or through a DHCP. The library can also manage DNS. + +For more information about this library please visit us at +https://www.arduino.cc/en/Reference/{repository-name} + +== License == + +Copyright (c) 2018 Arduino SA. All rights reserved. +Copyright (c) 2011-2014 Arduino LLC. All right reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/lib/WiFiNINA/examples/AP_SimpleWebServer/AP_SimpleWebServer.ino b/lib/WiFiNINA/examples/AP_SimpleWebServer/AP_SimpleWebServer.ino new file mode 100644 index 0000000..17d72d1 --- /dev/null +++ b/lib/WiFiNINA/examples/AP_SimpleWebServer/AP_SimpleWebServer.ino @@ -0,0 +1,163 @@ +/* + WiFi Web Server LED Blink + + A simple web server that lets you blink an LED via the web. + This sketch will create a new access point (with no password). + It will then launch a new server and print out the IP address + to the Serial Monitor. From there, you can open that address in a web browser + to turn on and off the LED on pin 13. + + If the IP address of your board is yourAddress: + http://yourAddress/H turns the LED on + http://yourAddress/L turns it off + + created 25 Nov 2012 + by Tom Igoe + adapted to WiFi AP by Adafruit + */ + +#include +#include +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key index number (needed only for WEP) + +int led = LED_BUILTIN; +int status = WL_IDLE_STATUS; +WiFiServer server(80); + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + Serial.println("Access Point Web Server"); + + pinMode(led, OUTPUT); // set the LED pin mode + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // by default the local IP address will be 192.168.4.1 + // you can override it with the following: + // WiFi.config(IPAddress(10, 0, 0, 1)); + + // print the network name (SSID); + Serial.print("Creating access point named: "); + Serial.println(ssid); + + // Create open network. Change this line if you want to create an WEP network: + status = WiFi.beginAP(ssid, pass); + if (status != WL_AP_LISTENING) { + Serial.println("Creating access point failed"); + // don't continue + while (true); + } + + // wait 10 seconds for connection: + delay(10000); + + // start the web server on port 80 + server.begin(); + + // you're connected now, so print out the status + printWiFiStatus(); +} + + +void loop() { + // compare the previous status to the current status + if (status != WiFi.status()) { + // it has changed update the variable + status = WiFi.status(); + + if (status == WL_AP_CONNECTED) { + // a device has connected to the AP + Serial.println("Device connected to AP"); + } else { + // a device has disconnected from the AP, and we are back in listening mode + Serial.println("Device disconnected from AP"); + } + } + + WiFiClient client = server.available(); // listen for incoming clients + + if (client) { // if you get a client, + Serial.println("new client"); // print a message out the serial port + String currentLine = ""; // make a String to hold incoming data from the client + while (client.connected()) { // loop while the client's connected + delayMicroseconds(10); // This is required for the Arduino Nano RP2040 Connect - otherwise it will loop so fast that SPI will never be served. + if (client.available()) { // if there's bytes to read from the client, + char c = client.read(); // read a byte, then + Serial.write(c); // print it out the serial monitor + if (c == '\n') { // if the byte is a newline character + + // if the current line is blank, you got two newline characters in a row. + // that's the end of the client HTTP request, so send a response: + if (currentLine.length() == 0) { + // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) + // and a content-type so the client knows what's coming, then a blank line: + client.println("HTTP/1.1 200 OK"); + client.println("Content-type:text/html"); + client.println(); + + // the content of the HTTP response follows the header: + client.print("Click here turn the LED on
"); + client.print("Click here turn the LED off
"); + + // The HTTP response ends with another blank line: + client.println(); + // break out of the while loop: + break; + } + else { // if you got a newline, then clear currentLine: + currentLine = ""; + } + } + else if (c != '\r') { // if you got anything else but a carriage return character, + currentLine += c; // add it to the end of the currentLine + } + + // Check to see if the client request was "GET /H" or "GET /L": + if (currentLine.endsWith("GET /H")) { + digitalWrite(led, HIGH); // GET /H turns the LED on + } + if (currentLine.endsWith("GET /L")) { + digitalWrite(led, LOW); // GET /L turns the LED off + } + } + } + // close the connection: + client.stop(); + Serial.println("client disconnected"); + } +} + +void printWiFiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your WiFi shield's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print where to go in a browser: + Serial.print("To see this page in action, open a browser to http://"); + Serial.println(ip); + +} diff --git a/lib/WiFiNINA/examples/AP_SimpleWebServer/arduino_secrets.h b/lib/WiFiNINA/examples/AP_SimpleWebServer/arduino_secrets.h new file mode 100644 index 0000000..493b719 --- /dev/null +++ b/lib/WiFiNINA/examples/AP_SimpleWebServer/arduino_secrets.h @@ -0,0 +1,3 @@ +// Both SSID and password must be 8 characters or longer +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/lib/WiFiNINA/examples/ConnectNoEncryption/ConnectNoEncryption.ino b/lib/WiFiNINA/examples/ConnectNoEncryption/ConnectNoEncryption.ino new file mode 100644 index 0000000..22ba35a --- /dev/null +++ b/lib/WiFiNINA/examples/ConnectNoEncryption/ConnectNoEncryption.ino @@ -0,0 +1,116 @@ +/* + This example connects to an unencrypted WiFi network. + Then it prints the MAC address of the board, + the IP address obtained, and other network details. + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +int status = WL_IDLE_STATUS; // the WiFi radio's status + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to open SSID: "); + Serial.println(ssid); + status = WiFi.begin(ssid); + + // wait 10 seconds for connection: + delay(10000); + } + + // you're connected now, so print out the data: + Serial.print("You're connected to the network"); + printCurrentNet(); + printWifiData(); +} + +void loop() { + // check the network connection once every 10 seconds: + delay(10000); + printCurrentNet(); +} + +void printWifiData() { + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + Serial.println(ip); + + // print your MAC address: + byte mac[6]; + WiFi.macAddress(mac); + Serial.print("MAC address: "); + printMacAddress(mac); + + // print your subnet mask: + IPAddress subnet = WiFi.subnetMask(); + Serial.print("NetMask: "); + Serial.println(subnet); + + // print your gateway address: + IPAddress gateway = WiFi.gatewayIP(); + Serial.print("Gateway: "); + Serial.println(gateway); +} + +void printCurrentNet() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print the MAC address of the router you're attached to: + byte bssid[6]; + WiFi.BSSID(bssid); + Serial.print("BSSID: "); + printMacAddress(bssid); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.println(rssi); + + // print the encryption type: + byte encryption = WiFi.encryptionType(); + Serial.print("Encryption Type:"); + Serial.println(encryption, HEX); +} + +void printMacAddress(byte mac[]) { + for (int i = 5; i >= 0; i--) { + if (mac[i] < 16) { + Serial.print("0"); + } + Serial.print(mac[i], HEX); + if (i > 0) { + Serial.print(":"); + } + } + Serial.println(); +} diff --git a/lib/WiFiNINA/examples/ConnectNoEncryption/arduino_secrets.h b/lib/WiFiNINA/examples/ConnectNoEncryption/arduino_secrets.h new file mode 100644 index 0000000..07c1148 --- /dev/null +++ b/lib/WiFiNINA/examples/ConnectNoEncryption/arduino_secrets.h @@ -0,0 +1 @@ +#define SECRET_SSID "" diff --git a/lib/WiFiNINA/examples/ConnectWithWEP/ConnectWithWEP.ino b/lib/WiFiNINA/examples/ConnectWithWEP/ConnectWithWEP.ino new file mode 100644 index 0000000..5f65ce4 --- /dev/null +++ b/lib/WiFiNINA/examples/ConnectWithWEP/ConnectWithWEP.ino @@ -0,0 +1,120 @@ +/* + This example connects to a WEP-encrypted WiFi network. + Then it prints the MAC address of the WiFi module, + the IP address obtained, and other network details. + + If you use 40-bit WEP, you need a key that is 10 characters long, + and the characters must be hexadecimal (0-9 or A-F). + e.g. for 40-bit, ABBADEAF01 will work, but ABBADEAF won't work + (too short) and ABBAISDEAF won't work (I and S are not + hexadecimal characters). + + For 128-bit, you need a string that is 26 characters long. + D0D0DEADF00DABBADEAFBEADED will work because it's 26 characters, + all in the 0-9, A-F range. + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key index number +int status = WL_IDLE_STATUS; // the WiFi radio's status + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to WEP network, SSID: "); + Serial.println(ssid); + status = WiFi.begin(ssid, keyIndex, pass); + + // wait 10 seconds for connection: + delay(10000); + } + + // once you are connected : + Serial.print("You're connected to the network"); + printCurrentNet(); + printWifiData(); +} + +void loop() { + // check the network connection once every 10 seconds: + delay(10000); + printCurrentNet(); +} + +void printWifiData() { + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + Serial.println(ip); + + // print your MAC address: + byte mac[6]; + WiFi.macAddress(mac); + Serial.print("MAC address: "); + printMacAddress(mac); +} + +void printCurrentNet() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print the MAC address of the router you're attached to: + byte bssid[6]; + WiFi.BSSID(bssid); + Serial.print("BSSID: "); + printMacAddress(bssid); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.println(rssi); + + // print the encryption type: + byte encryption = WiFi.encryptionType(); + Serial.print("Encryption Type:"); + Serial.println(encryption, HEX); + Serial.println(); +} + +void printMacAddress(byte mac[]) { + for (int i = 5; i >= 0; i--) { + if (mac[i] < 16) { + Serial.print("0"); + } + Serial.print(mac[i], HEX); + if (i > 0) { + Serial.print(":"); + } + } + Serial.println(); +} diff --git a/lib/WiFiNINA/examples/ConnectWithWEP/arduino_secrets.h b/lib/WiFiNINA/examples/ConnectWithWEP/arduino_secrets.h new file mode 100644 index 0000000..0c9fdd5 --- /dev/null +++ b/lib/WiFiNINA/examples/ConnectWithWEP/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/lib/WiFiNINA/examples/ConnectWithWPA/ConnectWithWPA.ino b/lib/WiFiNINA/examples/ConnectWithWPA/ConnectWithWPA.ino new file mode 100644 index 0000000..2e2b95e --- /dev/null +++ b/lib/WiFiNINA/examples/ConnectWithWPA/ConnectWithWPA.ino @@ -0,0 +1,111 @@ +/* + This example connects to an unencrypted WiFi network. + Then it prints the MAC address of the WiFi module, + the IP address obtained, and other network details. + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int status = WL_IDLE_STATUS; // the WiFi radio's status + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + + // you're connected now, so print out the data: + Serial.print("You're connected to the network"); + printCurrentNet(); + printWifiData(); + +} + +void loop() { + // check the network connection once every 10 seconds: + delay(10000); + printCurrentNet(); +} + +void printWifiData() { + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + Serial.println(ip); + + // print your MAC address: + byte mac[6]; + WiFi.macAddress(mac); + Serial.print("MAC address: "); + printMacAddress(mac); +} + +void printCurrentNet() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print the MAC address of the router you're attached to: + byte bssid[6]; + WiFi.BSSID(bssid); + Serial.print("BSSID: "); + printMacAddress(bssid); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.println(rssi); + + // print the encryption type: + byte encryption = WiFi.encryptionType(); + Serial.print("Encryption Type:"); + Serial.println(encryption, HEX); + Serial.println(); +} + +void printMacAddress(byte mac[]) { + for (int i = 5; i >= 0; i--) { + if (mac[i] < 16) { + Serial.print("0"); + } + Serial.print(mac[i], HEX); + if (i > 0) { + Serial.print(":"); + } + } + Serial.println(); +} diff --git a/lib/WiFiNINA/examples/ConnectWithWPA/arduino_secrets.h b/lib/WiFiNINA/examples/ConnectWithWPA/arduino_secrets.h new file mode 100644 index 0000000..0c9fdd5 --- /dev/null +++ b/lib/WiFiNINA/examples/ConnectWithWPA/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/lib/WiFiNINA/examples/ConnectWithWPA2Enterprise/ConnectWithWPA2Enterprise.ino b/lib/WiFiNINA/examples/ConnectWithWPA2Enterprise/ConnectWithWPA2Enterprise.ino new file mode 100644 index 0000000..fcf090b --- /dev/null +++ b/lib/WiFiNINA/examples/ConnectWithWPA2Enterprise/ConnectWithWPA2Enterprise.ino @@ -0,0 +1,110 @@ +/* + This example connects to a WPA2 Enterprise WiFi network. + Then it prints the MAC address of the WiFi module, + the IP address obtained, and other network details. + + Based on ConnectWithWPA.ino by dlf (Metodo2 srl) and Tom Igoe +*/ +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your WPA2 enterprise network SSID (name) +char user[] = SECRET_USER; // your WPA2 enterprise username +char pass[] = SECRET_PASS; // your WPA2 enterprise password +int status = WL_IDLE_STATUS; // the WiFi radio's status + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + // Connect to WPA2 enterprise network: + // - You can optionally provide additional identity and CA cert (string) parameters if your network requires them: + // WiFi.beginEnterprise(ssid, user, pass, identity, caCert) + status = WiFi.beginEnterprise(ssid, user, pass); + + // wait 10 seconds for connection: + delay(10000); + } + + // you're connected now, so print out the data: + Serial.print("You're connected to the network"); + printCurrentNet(); + printWifiData(); + +} + +void loop() { + // check the network connection once every 10 seconds: + delay(10000); + printCurrentNet(); +} + +void printWifiData() { + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print your MAC address: + byte mac[6]; + WiFi.macAddress(mac); + Serial.print("MAC address: "); + printMacAddress(mac); +} + +void printCurrentNet() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print the MAC address of the router you're attached to: + byte bssid[6]; + WiFi.BSSID(bssid); + Serial.print("BSSID: "); + printMacAddress(bssid); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.println(rssi); + + // print the encryption type: + byte encryption = WiFi.encryptionType(); + Serial.print("Encryption Type:"); + Serial.println(encryption, HEX); + Serial.println(); +} + +void printMacAddress(byte mac[]) { + for (int i = 5; i >= 0; i--) { + if (mac[i] < 16) { + Serial.print("0"); + } + Serial.print(mac[i], HEX); + if (i > 0) { + Serial.print(":"); + } + } + Serial.println(); +} diff --git a/lib/WiFiNINA/examples/ConnectWithWPA2Enterprise/arduino_secrets.h b/lib/WiFiNINA/examples/ConnectWithWPA2Enterprise/arduino_secrets.h new file mode 100644 index 0000000..d1310bb --- /dev/null +++ b/lib/WiFiNINA/examples/ConnectWithWPA2Enterprise/arduino_secrets.h @@ -0,0 +1,3 @@ +#define SECRET_SSID "" +#define SECRET_USER "" +#define SECRET_PASS "" diff --git a/lib/WiFiNINA/examples/ScanNetworks/ScanNetworks.ino b/lib/WiFiNINA/examples/ScanNetworks/ScanNetworks.ino new file mode 100644 index 0000000..e90bc7e --- /dev/null +++ b/lib/WiFiNINA/examples/ScanNetworks/ScanNetworks.ino @@ -0,0 +1,116 @@ +/* + This example prints the board's MAC address, and + scans for available WiFi networks using the NINA module. + Every ten seconds, it scans again. It doesn't actually + connect to any network, so no encryption scheme is specified. + + Circuit: + * Board with NINA module (Arduino MKR WiFi 1010, MKR VIDOR 4000 and UNO WiFi Rev.2) + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 21 Junn 2012 + by Tom Igoe and Jaymes Dec + */ + + +#include +#include + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // print your MAC address: + byte mac[6]; + WiFi.macAddress(mac); + Serial.print("MAC: "); + printMacAddress(mac); +} + +void loop() { + // scan for existing networks: + Serial.println("Scanning available networks..."); + listNetworks(); + delay(10000); +} + +void listNetworks() { + // scan for nearby networks: + Serial.println("** Scan Networks **"); + int numSsid = WiFi.scanNetworks(); + if (numSsid == -1) { + Serial.println("Couldn't get a WiFi connection"); + while (true); + } + + // print the list of networks seen: + Serial.print("number of available networks:"); + Serial.println(numSsid); + + // print the network number and name for each network found: + for (int thisNet = 0; thisNet < numSsid; thisNet++) { + Serial.print(thisNet); + Serial.print(") "); + Serial.print(WiFi.SSID(thisNet)); + Serial.print("\tSignal: "); + Serial.print(WiFi.RSSI(thisNet)); + Serial.print(" dBm"); + Serial.print("\tEncryption: "); + printEncryptionType(WiFi.encryptionType(thisNet)); + } +} + +void printEncryptionType(int thisType) { + // read the encryption type and print out the name: + switch (thisType) { + case ENC_TYPE_WEP: + Serial.println("WEP"); + break; + case ENC_TYPE_TKIP: + Serial.println("WPA"); + break; + case ENC_TYPE_CCMP: + Serial.println("WPA2"); + break; + case ENC_TYPE_NONE: + Serial.println("None"); + break; + case ENC_TYPE_AUTO: + Serial.println("Auto"); + break; + case ENC_TYPE_UNKNOWN: + default: + Serial.println("Unknown"); + break; + } +} + + +void printMacAddress(byte mac[]) { + for (int i = 5; i >= 0; i--) { + if (mac[i] < 16) { + Serial.print("0"); + } + Serial.print(mac[i], HEX); + if (i > 0) { + Serial.print(":"); + } + } + Serial.println(); +} diff --git a/lib/WiFiNINA/examples/ScanNetworksAdvanced/ScanNetworksAdvanced.ino b/lib/WiFiNINA/examples/ScanNetworksAdvanced/ScanNetworksAdvanced.ino new file mode 100644 index 0000000..9a32862 --- /dev/null +++ b/lib/WiFiNINA/examples/ScanNetworksAdvanced/ScanNetworksAdvanced.ino @@ -0,0 +1,137 @@ +/* + This example prints the board's MAC address, and + scans for available WiFi networks using the NINA module. + Every ten seconds, it scans again. It doesn't actually + connect to any network, so no encryption scheme is specified. + BSSID and WiFi channel are printed + + Circuit: + * Board with NINA module (Arduino MKR WiFi 1010, MKR VIDOR 4000 and UNO WiFi Rev.2) + + This example is based on ScanNetworks + + created 1 Mar 2017 + by Arturo Guadalupi +*/ + + +#include +#include + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // print your MAC address: + byte mac[6]; + WiFi.macAddress(mac); + Serial.print("MAC: "); + printMacAddress(mac); + + // scan for existing networks: + Serial.println(); + Serial.println("Scanning available networks..."); + listNetworks(); +} + +void loop() { + delay(10000); + // scan for existing networks: + Serial.println("Scanning available networks..."); + listNetworks(); +} + +void listNetworks() { + // scan for nearby networks: + Serial.println("** Scan Networks **"); + int numSsid = WiFi.scanNetworks(); + if (numSsid == -1) + { + Serial.println("Couldn't get a WiFi connection"); + while (true); + } + + // print the list of networks seen: + Serial.print("number of available networks: "); + Serial.println(numSsid); + + // print the network number and name for each network found: + for (int thisNet = 0; thisNet < numSsid; thisNet++) { + Serial.print(thisNet + 1); + Serial.print(") "); + Serial.print("Signal: "); + Serial.print(WiFi.RSSI(thisNet)); + Serial.print(" dBm"); + Serial.print("\tChannel: "); + Serial.print(WiFi.channel(thisNet)); + byte bssid[6]; + Serial.print("\t\tBSSID: "); + printMacAddress(WiFi.BSSID(thisNet, bssid)); + Serial.print("\tEncryption: "); + printEncryptionType(WiFi.encryptionType(thisNet)); + Serial.print("\t\tSSID: "); + Serial.println(WiFi.SSID(thisNet)); + Serial.flush(); + } + Serial.println(); +} + +void printEncryptionType(int thisType) { + // read the encryption type and print out the name: + switch (thisType) { + case ENC_TYPE_WEP: + Serial.print("WEP"); + break; + case ENC_TYPE_TKIP: + Serial.print("WPA"); + break; + case ENC_TYPE_CCMP: + Serial.print("WPA2"); + break; + case ENC_TYPE_NONE: + Serial.print("None"); + break; + case ENC_TYPE_AUTO: + Serial.print("Auto"); + break; + case ENC_TYPE_UNKNOWN: + default: + Serial.print("Unknown"); + break; + } +} + +void print2Digits(byte thisByte) { + if (thisByte < 0xF) { + Serial.print("0"); + } + Serial.print(thisByte, HEX); +} + +void printMacAddress(byte mac[]) { + for (int i = 5; i >= 0; i--) { + if (mac[i] < 16) { + Serial.print("0"); + } + Serial.print(mac[i], HEX); + if (i > 0) { + Serial.print(":"); + } + } + Serial.println(); +} diff --git a/lib/WiFiNINA/examples/SimpleWebServerWiFi/SimpleWebServerWiFi.ino b/lib/WiFiNINA/examples/SimpleWebServerWiFi/SimpleWebServerWiFi.ino new file mode 100644 index 0000000..35d7077 --- /dev/null +++ b/lib/WiFiNINA/examples/SimpleWebServerWiFi/SimpleWebServerWiFi.ino @@ -0,0 +1,135 @@ +/* + WiFi Web Server LED Blink + + A simple web server that lets you blink an LED via the web. + This sketch will print the IP address of your WiFi module (once connected) + to the Serial Monitor. From there, you can open that address in a web browser + to turn on and off the LED on pin 9. + + If the IP address of your board is yourAddress: + http://yourAddress/H turns the LED on + http://yourAddress/L turns it off + + This example is written for a network using WPA encryption. For + WEP or WPA, change the WiFi.begin() call accordingly. + + Circuit: + * Board with NINA module (Arduino MKR WiFi 1010, MKR VIDOR 4000 and UNO WiFi Rev.2) + * LED attached to pin 9 + + created 25 Nov 2012 + by Tom Igoe + */ +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key index number (needed only for WEP) + +int status = WL_IDLE_STATUS; +WiFiServer server(80); + +void setup() { + Serial.begin(9600); // initialize serial communication + pinMode(9, OUTPUT); // set the LED pin mode + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to Network named: "); + Serial.println(ssid); // print the network name (SSID); + + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + // wait 10 seconds for connection: + delay(10000); + } + server.begin(); // start the web server on port 80 + printWifiStatus(); // you're connected now, so print out the status +} + + +void loop() { + WiFiClient client = server.available(); // listen for incoming clients + + if (client) { // if you get a client, + Serial.println("new client"); // print a message out the serial port + String currentLine = ""; // make a String to hold incoming data from the client + while (client.connected()) { // loop while the client's connected + if (client.available()) { // if there's bytes to read from the client, + char c = client.read(); // read a byte, then + Serial.write(c); // print it out the serial monitor + if (c == '\n') { // if the byte is a newline character + + // if the current line is blank, you got two newline characters in a row. + // that's the end of the client HTTP request, so send a response: + if (currentLine.length() == 0) { + // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) + // and a content-type so the client knows what's coming, then a blank line: + client.println("HTTP/1.1 200 OK"); + client.println("Content-type:text/html"); + client.println(); + + // the content of the HTTP response follows the header: + client.print("Click here turn the LED on pin 9 on
"); + client.print("Click here turn the LED on pin 9 off
"); + + // The HTTP response ends with another blank line: + client.println(); + // break out of the while loop: + break; + } else { // if you got a newline, then clear currentLine: + currentLine = ""; + } + } else if (c != '\r') { // if you got anything else but a carriage return character, + currentLine += c; // add it to the end of the currentLine + } + + // Check to see if the client request was "GET /H" or "GET /L": + if (currentLine.endsWith("GET /H")) { + digitalWrite(9, HIGH); // GET /H turns the LED on + } + if (currentLine.endsWith("GET /L")) { + digitalWrite(9, LOW); // GET /L turns the LED off + } + } + } + // close the connection: + client.stop(); + Serial.println("client disconnected"); + } +} + +void printWifiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); + // print where to go in a browser: + Serial.print("To see this page in action, open a browser to http://"); + Serial.println(ip); +} diff --git a/lib/WiFiNINA/examples/SimpleWebServerWiFi/arduino_secrets.h b/lib/WiFiNINA/examples/SimpleWebServerWiFi/arduino_secrets.h new file mode 100644 index 0000000..0c9fdd5 --- /dev/null +++ b/lib/WiFiNINA/examples/SimpleWebServerWiFi/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/lib/WiFiNINA/examples/Tools/CheckFirmwareVersion/CheckFirmwareVersion.ino b/lib/WiFiNINA/examples/Tools/CheckFirmwareVersion/CheckFirmwareVersion.ino new file mode 100644 index 0000000..1a30163 --- /dev/null +++ b/lib/WiFiNINA/examples/Tools/CheckFirmwareVersion/CheckFirmwareVersion.ino @@ -0,0 +1,58 @@ +/* + * This example checks if the firmware loaded on the NINA module + * is updated. + * + * Circuit: + * - Board with NINA module (Arduino MKR WiFi 1010, MKR VIDOR 4000 and UNO WiFi Rev.2) + * + * Created 17 October 2018 by Riccardo Rosario Rizzo + * This code is in the public domain. + */ +#include +#include + +void setup() { + // Initialize serial + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // Print a welcome message + Serial.println("WiFiNINA firmware check."); + Serial.println(); + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + // Print firmware version on the module + String fv = WiFi.firmwareVersion(); + String latestFv; + Serial.print("Firmware version installed: "); + Serial.println(fv); + + latestFv = WIFI_FIRMWARE_LATEST_VERSION; + + // Print required firmware version + Serial.print("Latest firmware version available : "); + Serial.println(latestFv); + + // Check if the latest version is installed + Serial.println(); + if (fv >= latestFv) { + Serial.println("Check result: PASSED"); + } else { + Serial.println("Check result: NOT PASSED"); + Serial.println(" - The firmware version on the module does not match the"); + Serial.println(" version required by the library, you may experience"); + Serial.println(" issues or failures."); + } +} + +void loop() { + // do nothing +} diff --git a/lib/WiFiNINA/examples/Tools/FirmwareUpdater/ESP32BootROM.cpp b/lib/WiFiNINA/examples/Tools/FirmwareUpdater/ESP32BootROM.cpp new file mode 100644 index 0000000..320f245 --- /dev/null +++ b/lib/WiFiNINA/examples/Tools/FirmwareUpdater/ESP32BootROM.cpp @@ -0,0 +1,335 @@ +/* + ESP32BootROM - part of the Firmware Updater for the + Arduino MKR WiFi 1010, Arduino MKR Vidor 4000, and Arduino UNO WiFi Rev.2. + + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifdef ARDUINO_SAMD_MKRVIDOR4000 +#include + +#define NINA_GPIO0 FPGA_NINA_GPIO0 +#define NINA_RESETN FPGA_SPIWIFI_RESET +#endif + + +#include "ESP32BootROM.h" + +ESP32BootROMClass::ESP32BootROMClass(HardwareSerial& serial, int gpio0Pin, int resetnPin) : + _serial(&serial), + _gpio0Pin(gpio0Pin), + _resetnPin(resetnPin) +{ + +} + +int ESP32BootROMClass::begin(unsigned long baudrate) +{ +#ifdef ARDUINO_SAMD_MKRVIDOR4000 + FPGA.begin(); + + _serial->begin(119400); + + FPGA.pinMode(_gpio0Pin, OUTPUT); + FPGA.pinMode(_resetnPin, OUTPUT); + + FPGA.digitalWrite(_gpio0Pin, LOW); + + FPGA.digitalWrite(_resetnPin, LOW); + delay(10); + FPGA.digitalWrite(_resetnPin, HIGH); + delay(100); + +#elif defined(ARDUINO_AVR_UNO_WIFI_REV2) + _serial->begin(119400); + + pinMode(_gpio0Pin, OUTPUT); + pinMode(_resetnPin, OUTPUT); + + digitalWrite(_gpio0Pin, LOW); + + digitalWrite(_resetnPin, LOW); + delay(100); + digitalWrite(_resetnPin, HIGH); + delay(100); + digitalWrite(_resetnPin, LOW); +#else + _serial->begin(115200); + + pinMode(_gpio0Pin, OUTPUT); + pinMode(_resetnPin, OUTPUT); + + digitalWrite(_gpio0Pin, LOW); + + digitalWrite(_resetnPin, HIGH); + delay(10); + digitalWrite(_resetnPin, LOW); + delay(100); +#if defined(ARDUINO_SAMD_NANO_33_IOT) ||defined(ARDUINO_NANO_RP2040_CONNECT) + digitalWrite(_resetnPin, HIGH); + delay(100); +#endif +#endif + + int synced = 0; + + for (int retries = 0; !synced && (retries < 5); retries++) { + synced = sync(); + } + + if (!synced) { + return 0; + } + +#if defined(ARDUINO_SAMD_MKRVIDOR4000) || defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_NANO_RP2040_CONNECT) + (void)baudrate; +#else + if (baudrate != 115200) { + if (!changeBaudrate(baudrate)) { + return 0; + } + + delay(100); + + _serial->end(); + _serial->begin(baudrate); + } +#endif + + if (!spiAttach()) { + return 0; + } + + return 1; +} + +void ESP32BootROMClass::end() { + _serial->end(); +} + +int ESP32BootROMClass::sync() +{ + const uint8_t data[] = { + 0x07, 0x07, 0x12, 0x20, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 + }; + + command(0x08, data, sizeof(data)); + + int results[8]; + + for (int i = 0; i < 8; i++) { + results[i] = response(0x08, 100); + } + + return (results[0] == 0); +} + +int ESP32BootROMClass::changeBaudrate(unsigned long baudrate) +{ + const uint32_t data[2] = { + baudrate, + 0 + }; + + command(0x0f, data, sizeof(data)); + + return (response(0x0f, 3000) == 0); +} + +int ESP32BootROMClass::spiAttach() +{ + const uint8_t data[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + command(0x0d, data, sizeof(data)); + + return (response(0x0d, 3000) == 0); +} + +int ESP32BootROMClass::beginFlash(uint32_t offset, uint32_t size, uint32_t chunkSize) { + const uint32_t data[4] = { + size, + size / chunkSize, + chunkSize, + offset + }; + + command(0x02, data, sizeof(data)); + + _flashSequenceNumber = 0; + _chunkSize = chunkSize; + + return (response(0x02, 120000) == 0); +} + +int ESP32BootROMClass::dataFlash(const void* data, uint32_t length) +{ + uint32_t cmdData[4 + (_chunkSize / 4)]; + + cmdData[0] = length; + cmdData[1] = _flashSequenceNumber++; + cmdData[2] = 0; + cmdData[3] = 0; + + memcpy(&cmdData[4], data, length); + + if (length < _chunkSize) { + memset(&cmdData[4 + (length / 4)], 0xff, _chunkSize - length); + } + + command(0x03, cmdData, sizeof(cmdData)); + + return (response(0x03, 3000) == 0); +} + +int ESP32BootROMClass::endFlash(uint32_t reboot) { + const uint32_t data[1] = { + reboot + }; + + command(0x04, data, sizeof(data)); + + return (response(0x04, 3000) == 0); +} + +int ESP32BootROMClass::md5Flash(uint32_t offset, uint32_t size, uint8_t* result) +{ + const uint32_t data[4] = { + offset, + size, + 0, + 0 + }; + + command(0x13, data, sizeof(data)); + + uint8_t asciiResult[32]; + + if (response(0x13, 3000, asciiResult) != 0) { + return 0; + } + + char temp[3] = { 0, 0, 0 }; + + for (int i = 0; i < 16; i++) { + temp[0] = asciiResult[i * 2]; + temp[1] = asciiResult[i * 2 + 1]; + + result[i] = strtoul(temp, NULL, 16); + } + + return 1; +} + +void ESP32BootROMClass::command(int opcode, const void* data, uint16_t length) +{ + uint32_t checksum = 0; + + if (opcode == 0x03) { + checksum = 0xef; // seed + + for (uint16_t i = 16; i < length; i++) { + checksum ^= ((const uint8_t*)data)[i]; + } + } + + _serial->write(0xc0); + _serial->write((uint8_t)0x00); // direction + _serial->write(opcode); + _serial->write((uint8_t*)&length, sizeof(length)); + writeEscapedBytes((uint8_t*)&checksum, sizeof(checksum)); + writeEscapedBytes((uint8_t*)data, length); + _serial->write(0xc0); +#ifdef ARDUINO_SAMD_MKRVIDOR4000 + // _serial->flush(); // doesn't work! +#else + _serial->flush(); +#endif +} + +int ESP32BootROMClass::response(int opcode, unsigned long timeout, void* body) +{ + uint8_t data[10 + 256]; + uint16_t index = 0; + + uint8_t responseLength = 4; + + for (unsigned long start = millis(); (index < (uint16_t)(10 + responseLength)) && (millis() - start) < timeout;) { + if (_serial->available()) { + data[index] = _serial->read(); + + if (index == 3) { + responseLength = data[index]; + } + + index++; + } + } + +#ifdef DEBUG + if (index) { + for (int i = 0; i < index; i++) { + byte b = data[i]; + + if (b < 0x10) { + Serial.print('0'); + } + + Serial.print(b, HEX); + Serial.print(' '); + } + Serial.println(); + } +#endif + + if (index != (uint16_t)(10 + responseLength)) { + return -1; + } + + if (data[0] != 0xc0 || data[1] != 0x01 || data[2] != opcode || data[responseLength + 5] != 0x00 || data[responseLength + 6] != 0x00 || data[responseLength + 9] != 0xc0) { + return -1; + } + + if (body) { + memcpy(body, &data[9], responseLength - 4); + } + + return data[responseLength + 5]; +} + +void ESP32BootROMClass::writeEscapedBytes(const uint8_t* data, uint16_t length) +{ + uint16_t written = 0; + + while (written < length) { + uint8_t b = data[written++]; + + if (b == 0xdb) { + _serial->write(0xdb); + _serial->write(0xdd); + } else if (b == 0xc0) { + _serial->write(0xdb); + _serial->write(0xdc); + } else { + _serial->write(b); + } + } +} + +ESP32BootROMClass ESP32BootROM(SerialNina, NINA_GPIO0, NINA_RESETN); diff --git a/lib/WiFiNINA/examples/Tools/FirmwareUpdater/ESP32BootROM.h b/lib/WiFiNINA/examples/Tools/FirmwareUpdater/ESP32BootROM.h new file mode 100644 index 0000000..578b4ec --- /dev/null +++ b/lib/WiFiNINA/examples/Tools/FirmwareUpdater/ESP32BootROM.h @@ -0,0 +1,56 @@ +/* + ESP32BootROM - part of the Firmware Updater for the + Arduino MKR WiFi 1010, Arduino MKR Vidor 4000, and Arduino UNO WiFi Rev.2. + + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +class ESP32BootROMClass { + public: + ESP32BootROMClass(HardwareSerial& hwSerial, int gpio0Pin, int resetnPin); + + int begin(unsigned long baudrate); + void end(); + + int beginFlash(uint32_t offset, uint32_t size, uint32_t chunkSize); + int dataFlash(const void* data, uint32_t length); + int endFlash(uint32_t reboot); + + int md5Flash(uint32_t offset, uint32_t size, uint8_t* result); + + private: + int sync(); + int changeBaudrate(unsigned long baudrate); + int spiAttach(); + + void command(int opcode, const void* data, uint16_t length); + int response(int opcode, unsigned long timeout, void* body = NULL); + + void writeEscapedBytes(const uint8_t* data, uint16_t length); + + private: + HardwareSerial* _serial; + int _gpio0Pin; + int _resetnPin; + + uint32_t _flashSequenceNumber; + uint32_t _chunkSize; +}; + +extern ESP32BootROMClass ESP32BootROM; diff --git a/lib/WiFiNINA/examples/Tools/FirmwareUpdater/Endianess.ino b/lib/WiFiNINA/examples/Tools/FirmwareUpdater/Endianess.ino new file mode 100644 index 0000000..d55cacb --- /dev/null +++ b/lib/WiFiNINA/examples/Tools/FirmwareUpdater/Endianess.ino @@ -0,0 +1,60 @@ +/* + Endianess.ino - Network byte order conversion functions. + Copyright (c) 2015 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +bool isBigEndian() { + uint32_t test = 0x11223344; + uint8_t *pTest = reinterpret_cast(&test); + return pTest[0] == 0x11; +} + +uint32_t fromNetwork32(uint32_t from) { + static const bool be = isBigEndian(); + if (be) { + return from; + } else { + uint8_t *pFrom = reinterpret_cast(&from); + uint32_t to; + to = pFrom[0]; to <<= 8; + to |= pFrom[1]; to <<= 8; + to |= pFrom[2]; to <<= 8; + to |= pFrom[3]; + return to; + } +} + +uint16_t fromNetwork16(uint16_t from) { + static bool be = isBigEndian(); + if (be) { + return from; + } else { + uint8_t *pFrom = reinterpret_cast(&from); + uint16_t to; + to = pFrom[0]; to <<= 8; + to |= pFrom[1]; + return to; + } +} + +uint32_t toNetwork32(uint32_t to) { + return fromNetwork32(to); +} + +uint16_t toNetwork16(uint16_t to) { + return fromNetwork16(to); +} diff --git a/lib/WiFiNINA/examples/Tools/FirmwareUpdater/FirmwareUpdater.ino b/lib/WiFiNINA/examples/Tools/FirmwareUpdater/FirmwareUpdater.ino new file mode 100644 index 0000000..acf80fd --- /dev/null +++ b/lib/WiFiNINA/examples/Tools/FirmwareUpdater/FirmwareUpdater.ino @@ -0,0 +1,142 @@ +/* + FirmwareUpdater - Firmware Updater for the + Arduino MKR WiFi 1010, Arduino MKR Vidor 4000, and Arduino UNO WiFi Rev.2. + + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "ESP32BootROM.h" + +typedef struct __attribute__((__packed__)) { + uint8_t command; + uint32_t address; + uint32_t arg1; + uint16_t payloadLength; + + // payloadLength bytes of data follows... +} UartPacket; + +static const int MAX_PAYLOAD_SIZE = 1024; + +#define CMD_READ_FLASH 0x01 +#define CMD_WRITE_FLASH 0x02 +#define CMD_ERASE_FLASH 0x03 +#define CMD_MD5_FLASH 0x04 +#define CMD_MAX_PAYLOAD_SIZE 0x50 +#define CMD_HELLO 0x99 + +void setup() { + Serial.begin(1000000); + + if (!ESP32BootROM.begin(921600)) { + Serial.println("Unable to communicate with ESP32 boot ROM!"); + while (1); + } +} + +void receivePacket(UartPacket *pkt, uint8_t *payload) { + // Read command + uint8_t *p = reinterpret_cast(pkt); + uint16_t l = sizeof(UartPacket); + while (l > 0) { + int c = Serial.read(); + if (c == -1) + continue; + *p++ = c; + l--; + } + + // Convert parameters from network byte order to cpu byte order + pkt->address = fromNetwork32(pkt->address); + pkt->arg1 = fromNetwork32(pkt->arg1); + pkt->payloadLength = fromNetwork16(pkt->payloadLength); + + // Read payload + l = pkt->payloadLength; + while (l > 0) { + int c = Serial.read(); + if (c == -1) + continue; + *payload++ = c; + l--; + } +} + +// Allocated statically so the compiler can tell us +// about the amount of used RAM +static UartPacket pkt; +static uint8_t payload[MAX_PAYLOAD_SIZE]; + +void loop() { + receivePacket(&pkt, payload); + + if (pkt.command == CMD_HELLO) { + if (pkt.address == 0x11223344 && pkt.arg1 == 0x55667788) + Serial.print("v10000"); + } + + if (pkt.command == CMD_MAX_PAYLOAD_SIZE) { + uint16_t res = toNetwork16(MAX_PAYLOAD_SIZE); + Serial.write(reinterpret_cast(&res), sizeof(res)); + } + + if (pkt.command == CMD_READ_FLASH) { + // not supported! + Serial.println("ER"); + } + + if (pkt.command == CMD_WRITE_FLASH) { + uint32_t len = pkt.payloadLength; + if (!ESP32BootROM.dataFlash(payload, len)) { + Serial.print("ER"); + } else { + Serial.print("OK"); + } + } + + if (pkt.command == CMD_ERASE_FLASH) { + uint32_t address = pkt.address; + uint32_t len = pkt.arg1; + if (!ESP32BootROM.beginFlash(address, len, MAX_PAYLOAD_SIZE)) { + Serial.print("ER"); + } else { + Serial.print("OK"); + } + } + + if (pkt.command == CMD_MD5_FLASH) { + uint32_t address = pkt.address; + uint32_t len = pkt.arg1; + + if (!ESP32BootROM.endFlash(1)) { + Serial.print("ER"); + } else { + ESP32BootROM.end(); + + uint8_t md5[16]; + + if (!ESP32BootROM.begin(921600)) { + Serial.print("ER"); + } else if (!ESP32BootROM.md5Flash(address, len, md5)) { + Serial.print("ER"); + } else { + Serial.print("OK"); + Serial.write(md5, sizeof(md5)); + } + } + } +} diff --git a/lib/WiFiNINA/examples/Tools/SerialNINAPassthrough/SerialNINAPassthrough.ino b/lib/WiFiNINA/examples/Tools/SerialNINAPassthrough/SerialNINAPassthrough.ino new file mode 100644 index 0000000..acfd078 --- /dev/null +++ b/lib/WiFiNINA/examples/Tools/SerialNINAPassthrough/SerialNINAPassthrough.ino @@ -0,0 +1,105 @@ +/* + SerialNINAPassthrough - Use esptool to flash the u-blox NINA (ESP32) module + Arduino MKR WiFi 1010, Arduino MKR Vidor 4000, and Arduino UNO WiFi Rev.2. + + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifdef ARDUINO_SAMD_MKRVIDOR4000 +#include + +unsigned long baud = 119400; +#else +unsigned long baud = 115200; +#endif + +int rts = -1; +int dtr = -1; + +void setup() { + Serial.begin(baud); + +#ifdef ARDUINO_SAMD_MKRVIDOR4000 + FPGA.begin(); +#endif + + SerialNina.begin(baud); + +#ifdef ARDUINO_SAMD_MKRVIDOR4000 + FPGA.pinMode(FPGA_NINA_GPIO0, OUTPUT); + FPGA.pinMode(FPGA_SPIWIFI_RESET, OUTPUT); +#else + pinMode(NINA_GPIO0, OUTPUT); + pinMode(NINA_RESETN, OUTPUT); +#endif + +#ifdef ARDUINO_AVR_UNO_WIFI_REV2 + // manually put the NINA in upload mode + digitalWrite(NINA_GPIO0, LOW); + + digitalWrite(NINA_RESETN, LOW); + delay(100); + digitalWrite(NINA_RESETN, HIGH); + delay(100); + digitalWrite(NINA_RESETN, LOW); +#endif +} + +void loop() { +#ifndef ARDUINO_AVR_UNO_WIFI_REV2 + if (rts != Serial.rts()) { +#ifdef ARDUINO_SAMD_MKRVIDOR4000 + FPGA.digitalWrite(FPGA_SPIWIFI_RESET, (Serial.rts() == 1) ? LOW : HIGH); +#elif defined(ARDUINO_SAMD_NANO_33_IOT) + digitalWrite(NINA_RESETN, Serial.rts() ? LOW : HIGH); +#else + digitalWrite(NINA_RESETN, Serial.rts()); +#endif + rts = Serial.rts(); + } + + if (dtr != Serial.dtr()) { +#ifdef ARDUINO_SAMD_MKRVIDOR4000 + FPGA.digitalWrite(FPGA_NINA_GPIO0, (Serial.dtr() == 1) ? HIGH : LOW); +#else + digitalWrite(NINA_GPIO0, (Serial.dtr() == 0) ? HIGH : LOW); +#endif + dtr = Serial.dtr(); + } +#endif + + if (Serial.available()) { + SerialNina.write(Serial.read()); + } + + if (SerialNina.available()) { + Serial.write(SerialNina.read()); + } + +#ifndef ARDUINO_AVR_UNO_WIFI_REV2 + // check if the USB virtual serial wants a new baud rate + if (Serial.baud() != baud) { + rts = -1; + dtr = -1; + + baud = Serial.baud(); +#ifndef ARDUINO_SAMD_MKRVIDOR4000 + SerialNina.begin(baud); +#endif + } +#endif +} diff --git a/lib/WiFiNINA/examples/WiFiChatServer/WiFiChatServer.ino b/lib/WiFiNINA/examples/WiFiChatServer/WiFiChatServer.ino new file mode 100644 index 0000000..c608016 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiChatServer/WiFiChatServer.ino @@ -0,0 +1,117 @@ +/* + Chat Server + + A simple server that distributes any incoming messages to all + connected clients. To use, telnet to your device's IP address and type. + You can see the client's input in the serial monitor as well. + + This example is written for a network using WPA encryption. For + WEP or WPA, change the WiFi.begin() call accordingly. + + + Circuit: + * Board with NINA module (Arduino MKR WiFi 1010, MKR VIDOR 4000 and UNO WiFi Rev.2) + + created 18 Dec 2009 + by David A. Mellis + modified 31 May 2012 + by Tom Igoe + + */ + +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) + +int keyIndex = 0; // your network key index number (needed only for WEP) + +int status = WL_IDLE_STATUS; + +WiFiServer server(23); + +boolean alreadyConnected = false; // whether or not the client was connected previously + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + + // start the server: + server.begin(); + // you're connected now, so print out the status: + printWifiStatus(); +} + + +void loop() { + // wait for a new client: + WiFiClient client = server.available(); + + + // when the client sends the first byte, say hello: + if (client) { + if (!alreadyConnected) { + // clear out the input buffer: + client.flush(); + Serial.println("We have a new client"); + client.println("Hello, client!"); + alreadyConnected = true; + } + + if (client.available() > 0) { + // read the bytes incoming from the client: + char thisChar = client.read(); + // echo the bytes back to the client: + server.write(thisChar); + // echo the bytes to the server as well: + Serial.write(thisChar); + } + } +} + + +void printWifiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFiNINA/examples/WiFiChatServer/arduino_secrets.h b/lib/WiFiNINA/examples/WiFiChatServer/arduino_secrets.h new file mode 100644 index 0000000..0c9fdd5 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiChatServer/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/lib/WiFiNINA/examples/WiFiPing/WiFiPing.ino b/lib/WiFiNINA/examples/WiFiPing/WiFiPing.ino new file mode 100644 index 0000000..48ad458 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiPing/WiFiPing.ino @@ -0,0 +1,135 @@ +/* + This example connects to an encrypted WiFi network (WPA/WPA2). + Then it prints the MAC address of the board, + the IP address obtained, and other network details. + Then it continuously pings given host specified by IP Address or name. + + Circuit: + * Board with NINA module (Arduino MKR WiFi 1010, MKR VIDOR 4000 and UNO WiFi Rev.2) + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 09 June 2016 + by Petar Georgiev +*/ +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int status = WL_IDLE_STATUS; // the WiFi radio's status + +// Specify IP address or hostname +String hostName = "www.google.com"; +int pingResult; + +void setup() { + // Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // attempt to connect to WiFi network: + while ( status != WL_CONNECTED) { + Serial.print("Attempting to connect to WPA SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network: + status = WiFi.begin(ssid, pass); + + // wait 5 seconds for connection: + delay(5000); + } + + // you're connected now, so print out the data: + Serial.println("You're connected to the network"); + printCurrentNet(); + printWiFiData(); +} + +void loop() { + Serial.print("Pinging "); + Serial.print(hostName); + Serial.print(": "); + + pingResult = WiFi.ping(hostName); + + if (pingResult >= 0) { + Serial.print("SUCCESS! RTT = "); + Serial.print(pingResult); + Serial.println(" ms"); + } else { + Serial.print("FAILED! Error code: "); + Serial.println(pingResult); + } + + delay(5000); +} + +void printWiFiData() { + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP address : "); + Serial.println(ip); + + Serial.print("Subnet mask: "); + Serial.println((IPAddress)WiFi.subnetMask()); + + Serial.print("Gateway IP : "); + Serial.println((IPAddress)WiFi.gatewayIP()); + + // print your MAC address: + byte mac[6]; + WiFi.macAddress(mac); + Serial.print("MAC address: "); + printMacAddress(mac); +} + +void printCurrentNet() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print the MAC address of the router you're attached to: + byte bssid[6]; + WiFi.BSSID(bssid); + Serial.print("BSSID: "); + printMacAddress(bssid); + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI): "); + Serial.println(rssi); + + // print the encryption type: + byte encryption = WiFi.encryptionType(); + Serial.print("Encryption Type: "); + Serial.println(encryption, HEX); + Serial.println(); +} + +void printMacAddress(byte mac[]) { + for (int i = 5; i >= 0; i--) { + if (mac[i] < 16) { + Serial.print("0"); + } + Serial.print(mac[i], HEX); + if (i > 0) { + Serial.print(":"); + } + } + Serial.println(); +} diff --git a/lib/WiFiNINA/examples/WiFiPing/arduino_secrets.h b/lib/WiFiNINA/examples/WiFiPing/arduino_secrets.h new file mode 100644 index 0000000..0c9fdd5 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiPing/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/lib/WiFiNINA/examples/WiFiSSLClient/WiFiSSLClient.ino b/lib/WiFiNINA/examples/WiFiSSLClient/WiFiSSLClient.ino new file mode 100644 index 0000000..003fbf0 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiSSLClient/WiFiSSLClient.ino @@ -0,0 +1,112 @@ +/* +This example creates a client object that connects and transfers +data using always SSL. + +It is compatible with the methods normally related to plain +connections, like client.connect(host, port). + +Written by Arturo Guadalupi +last revision November 2015 + +*/ + +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key index number (needed only for WEP) + +int status = WL_IDLE_STATUS; +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +//IPAddress server(74,125,232,128); // numeric IP for Google (no DNS) +char server[] = "www.google.com"; // name address for Google (using DNS) + +// Initialize the Ethernet client library +// with the IP address and port of the server +// that you want to connect to (port 80 is default for HTTP): +WiFiSSLClient client; + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + Serial.println("Connected to WiFi"); + printWiFiStatus(); + + Serial.println("\nStarting connection to server..."); + // if you get a connection, report back via serial: + if (client.connect(server, 443)) { + Serial.println("connected to server"); + // Make a HTTP request: + client.println("GET /search?q=arduino HTTP/1.1"); + client.println("Host: www.google.com"); + client.println("Connection: close"); + client.println(); + } +} + +void loop() { + // if there are incoming bytes available + // from the server, read them and print them: + while (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + Serial.println(); + Serial.println("disconnecting from server."); + client.stop(); + + // do nothing forevermore: + while (true); + } +} + + +void printWiFiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFiNINA/examples/WiFiSSLClient/arduino_secrets.h b/lib/WiFiNINA/examples/WiFiSSLClient/arduino_secrets.h new file mode 100644 index 0000000..0c9fdd5 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiSSLClient/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/lib/WiFiNINA/examples/WiFiStorage/WiFiStorage.ino b/lib/WiFiNINA/examples/WiFiStorage/WiFiStorage.ino new file mode 100644 index 0000000..5fd627b --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiStorage/WiFiStorage.ino @@ -0,0 +1,42 @@ +/* + This example shows how to interact with NINA internal memory partition + APIs are modeled on SerialFlash library (not on SD) to speedup operations and avoid buffers. +*/ + +#include + +void setup() { + + Serial.begin(115200); + while (!Serial); + + // check for the presence of the shield: + if (WiFi.status() == WL_NO_SHIELD) { + Serial.println("WiFi shield not present"); + // don't continue: + while (true); + } + + WiFiStorageFile file = WiFiStorage.open("/fs/testfile"); + + if (file) { + file.erase(); + } + + String test = "Cantami o Diva del pelide Achille"; + file.write(test.c_str(), test.length()); + + if (file) { + file.seek(0); + while (file.available()) { + uint8_t buf[128]; + int ret = file.read(buf, 128); + Serial.write(buf, ret); + } + } +} + +void loop() { + // put your main code here, to run repeatedly: + +} diff --git a/lib/WiFiNINA/examples/WiFiUdpNtpClient/WiFiUdpNtpClient.ino b/lib/WiFiNINA/examples/WiFiUdpNtpClient/WiFiUdpNtpClient.ino new file mode 100644 index 0000000..354cfa7 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiUdpNtpClient/WiFiUdpNtpClient.ino @@ -0,0 +1,173 @@ +/* + Udp NTP Client + + Get the time from a Network Time Protocol (NTP) time server + Demonstrates use of UDP sendPacket and ReceivePacket + For more on NTP time servers and the messages needed to communicate with them, + see http://en.wikipedia.org/wiki/Network_Time_Protocol + + created 4 Sep 2010 + by Michael Margolis + modified 9 Apr 2012 + by Tom Igoe + + This code is in the public domain. + + */ + +#include +#include +#include + +int status = WL_IDLE_STATUS; +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key index number (needed only for WEP) + +unsigned int localPort = 2390; // local port to listen for UDP packets + +IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server + +const int NTP_PACKET_SIZE = 48; // NTP timestamp is in the first 48 bytes of the message + +byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets + +// A UDP instance to let us send and receive packets over UDP +WiFiUDP Udp; + +void setup() { + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + + Serial.println("Connected to WiFi"); + printWifiStatus(); + + Serial.println("\nStarting connection to server..."); + Udp.begin(localPort); +} + +void loop() { + sendNTPpacket(timeServer); // send an NTP packet to a time server + // wait to see if a reply is available + delay(1000); + if (Udp.parsePacket()) { + Serial.println("packet received"); + // We've received a packet, read the data from it + Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer + + //the timestamp starts at byte 40 of the received packet and is four bytes, + // or two words, long. First, extract the two words: + + unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); + unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); + // combine the four bytes (two words) into a long integer + // this is NTP time (seconds since Jan 1 1900): + unsigned long secsSince1900 = highWord << 16 | lowWord; + Serial.print("Seconds since Jan 1 1900 = "); + Serial.println(secsSince1900); + + // now convert NTP time into everyday time: + Serial.print("Unix time = "); + // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: + const unsigned long seventyYears = 2208988800UL; + // subtract seventy years: + unsigned long epoch = secsSince1900 - seventyYears; + // print Unix time: + Serial.println(epoch); + + + // print the hour, minute and second: + Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT) + Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day) + Serial.print(':'); + if (((epoch % 3600) / 60) < 10) { + // In the first 10 minutes of each hour, we'll want a leading '0' + Serial.print('0'); + } + Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute) + Serial.print(':'); + if ((epoch % 60) < 10) { + // In the first 10 seconds of each minute, we'll want a leading '0' + Serial.print('0'); + } + Serial.println(epoch % 60); // print the second + } + // wait ten seconds before asking for the time again + delay(10000); +} + +// send an NTP request to the time server at the given address +unsigned long sendNTPpacket(IPAddress& address) { + //Serial.println("1"); + // set all bytes in the buffer to 0 + memset(packetBuffer, 0, NTP_PACKET_SIZE); + // Initialize values needed to form NTP request + // (see URL above for details on the packets) + //Serial.println("2"); + packetBuffer[0] = 0b11100011; // LI, Version, Mode + packetBuffer[1] = 0; // Stratum, or type of clock + packetBuffer[2] = 6; // Polling Interval + packetBuffer[3] = 0xEC; // Peer Clock Precision + // 8 bytes of zero for Root Delay & Root Dispersion + packetBuffer[12] = 49; + packetBuffer[13] = 0x4E; + packetBuffer[14] = 49; + packetBuffer[15] = 52; + + //Serial.println("3"); + + // all NTP fields have been given values, now + // you can send a packet requesting a timestamp: + Udp.beginPacket(address, 123); //NTP requests are to port 123 + //Serial.println("4"); + Udp.write(packetBuffer, NTP_PACKET_SIZE); + //Serial.println("5"); + Udp.endPacket(); + //Serial.println("6"); +} + + +void printWifiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFiNINA/examples/WiFiUdpNtpClient/arduino_secrets.h b/lib/WiFiNINA/examples/WiFiUdpNtpClient/arduino_secrets.h new file mode 100644 index 0000000..0c9fdd5 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiUdpNtpClient/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/lib/WiFiNINA/examples/WiFiUdpSendReceiveString/WiFiUdpSendReceiveString.ino b/lib/WiFiNINA/examples/WiFiUdpSendReceiveString/WiFiUdpSendReceiveString.ino new file mode 100644 index 0000000..d022e27 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiUdpSendReceiveString/WiFiUdpSendReceiveString.ino @@ -0,0 +1,112 @@ +/* + WiFi UDP Send and Receive String + + This sketch waits for a UDP packet on localPort using the WiFi module. + When a packet is received an Acknowledge packet is sent to the client on port remotePort + + created 30 December 2012 + by dlf (Metodo2 srl) + + */ + + +#include +#include +#include + +int status = WL_IDLE_STATUS; +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key index number (needed only for WEP) + +unsigned int localPort = 2390; // local port to listen on + +char packetBuffer[256]; //buffer to hold incoming packet +char ReplyBuffer[] = "acknowledged"; // a string to send back + +WiFiUDP Udp; + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + Serial.println("Connected to WiFi"); + printWifiStatus(); + + Serial.println("\nStarting connection to server..."); + // if you get a connection, report back via serial: + Udp.begin(localPort); +} + +void loop() { + + // if there's data available, read a packet + int packetSize = Udp.parsePacket(); + if (packetSize) { + Serial.print("Received packet of size "); + Serial.println(packetSize); + Serial.print("From "); + IPAddress remoteIp = Udp.remoteIP(); + Serial.print(remoteIp); + Serial.print(", port "); + Serial.println(Udp.remotePort()); + + // read the packet into packetBufffer + int len = Udp.read(packetBuffer, 255); + if (len > 0) { + packetBuffer[len] = 0; + } + Serial.println("Contents:"); + Serial.println(packetBuffer); + + // send a reply, to the IP address and port that sent us the packet we received + Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); + Udp.write(ReplyBuffer); + Udp.endPacket(); + } +} + + +void printWifiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFiNINA/examples/WiFiUdpSendReceiveString/arduino_secrets.h b/lib/WiFiNINA/examples/WiFiUdpSendReceiveString/arduino_secrets.h new file mode 100644 index 0000000..0c9fdd5 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiUdpSendReceiveString/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/lib/WiFiNINA/examples/WiFiWebClient/WiFiWebClient.ino b/lib/WiFiNINA/examples/WiFiWebClient/WiFiWebClient.ino new file mode 100644 index 0000000..86a1a46 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiWebClient/WiFiWebClient.ino @@ -0,0 +1,122 @@ +/* + Web client + + This sketch connects to a website (http://www.google.com) + using the WiFi module. + + This example is written for a network using WPA encryption. For + WEP or WPA, change the WiFi.begin() call accordingly. + + This example is written for a network using WPA encryption. For + WEP or WPA, change the WiFi.begin() call accordingly. + + Circuit: + * Board with NINA module (Arduino MKR WiFi 1010, MKR VIDOR 4000 and UNO WiFi Rev.2) + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ + + +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key index number (needed only for WEP) + +int status = WL_IDLE_STATUS; +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +//IPAddress server(74,125,232,128); // numeric IP for Google (no DNS) +char server[] = "www.google.com"; // name address for Google (using DNS) + +// Initialize the Ethernet client library +// with the IP address and port of the server +// that you want to connect to (port 80 is default for HTTP): +WiFiClient client; + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + Serial.println("Connected to WiFi"); + printWifiStatus(); + + Serial.println("\nStarting connection to server..."); + // if you get a connection, report back via serial: + if (client.connect(server, 80)) { + Serial.println("connected to server"); + // Make a HTTP request: + client.println("GET /search?q=arduino HTTP/1.1"); + client.println("Host: www.google.com"); + client.println("Connection: close"); + client.println(); + } +} + +void loop() { + // if there are incoming bytes available + // from the server, read them and print them: + while (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if the server's disconnected, stop the client: + if (!client.connected()) { + Serial.println(); + Serial.println("disconnecting from server."); + client.stop(); + + // do nothing forevermore: + while (true); + } +} + + +void printWifiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFiNINA/examples/WiFiWebClient/arduino_secrets.h b/lib/WiFiNINA/examples/WiFiWebClient/arduino_secrets.h new file mode 100644 index 0000000..0c9fdd5 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiWebClient/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/lib/WiFiNINA/examples/WiFiWebClientRepeating/WiFiWebClientRepeating.ino b/lib/WiFiNINA/examples/WiFiWebClientRepeating/WiFiWebClientRepeating.ino new file mode 100644 index 0000000..efd9663 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiWebClientRepeating/WiFiWebClientRepeating.ino @@ -0,0 +1,128 @@ +/* + Repeating WiFi Web Client + + This sketch connects to a a web server and makes a request + using a WiFi equipped Arduino board. + + created 23 April 2012 + modified 31 May 2012 + by Tom Igoe + modified 13 Jan 2014 + by Federico Vanzati + + http://www.arduino.cc/en/Tutorial/WifiWebClientRepeating + This code is in the public domain. + */ + +#include +#include + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key index number (needed only for WEP) + +int status = WL_IDLE_STATUS; + +// Initialize the WiFi client library +WiFiClient client; + +// server address: +char server[] = "example.org"; +//IPAddress server(64,131,82,241); + +unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds +const unsigned long postingInterval = 10L * 1000L; // delay between updates, in milliseconds + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + // you're connected now, so print out the status: + printWifiStatus(); +} + +void loop() { + // if there's incoming data from the net connection. + // send it out the serial port. This is for debugging + // purposes only: + while (client.available()) { + char c = client.read(); + Serial.write(c); + } + + // if ten seconds have passed since your last connection, + // then connect again and send data: + if (millis() - lastConnectionTime > postingInterval) { + httpRequest(); + } + +} + +// this method makes a HTTP connection to the server: +void httpRequest() { + // close any connection before send a new request. + // This will free the socket on the NINA module + client.stop(); + + // if there's a successful connection: + if (client.connect(server, 80)) { + Serial.println("connecting..."); + // send the HTTP GET request: + client.println("GET / HTTP/1.1"); + client.println("Host: example.org"); + client.println("User-Agent: ArduinoWiFi/1.1"); + client.println("Connection: close"); + client.println(); + + // note the time that the connection was made: + lastConnectionTime = millis(); + } else { + // if you couldn't make a connection: + Serial.println("connection failed"); + } +} + + +void printWifiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFiNINA/examples/WiFiWebClientRepeating/arduino_secrets.h b/lib/WiFiNINA/examples/WiFiWebClientRepeating/arduino_secrets.h new file mode 100644 index 0000000..0c9fdd5 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiWebClientRepeating/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/lib/WiFiNINA/examples/WiFiWebServer/WiFiWebServer.ino b/lib/WiFiNINA/examples/WiFiWebServer/WiFiWebServer.ino new file mode 100644 index 0000000..9e1200b --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiWebServer/WiFiWebServer.ino @@ -0,0 +1,137 @@ +/* + WiFi Web Server + + A simple web server that shows the value of the analog input pins. + + This example is written for a network using WPA encryption. For + WEP or WPA, change the WiFi.begin() call accordingly. + + Circuit: + * Analog inputs attached to pins A0 through A5 (optional) + + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + + */ + +#include +#include + + +#include "arduino_secrets.h" +///////please enter your sensitive data in the Secret tab/arduino_secrets.h +char ssid[] = SECRET_SSID; // your network SSID (name) +char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0; // your network key index number (needed only for WEP) + +int status = WL_IDLE_STATUS; + +WiFiServer server(80); + +void setup() { + //Initialize serial and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for native USB port only + } + + // check for the WiFi module: + if (WiFi.status() == WL_NO_MODULE) { + Serial.println("Communication with WiFi module failed!"); + // don't continue + while (true); + } + + String fv = WiFi.firmwareVersion(); + if (fv < WIFI_FIRMWARE_LATEST_VERSION) { + Serial.println("Please upgrade the firmware"); + } + + // attempt to connect to WiFi network: + while (status != WL_CONNECTED) { + Serial.print("Attempting to connect to SSID: "); + Serial.println(ssid); + // Connect to WPA/WPA2 network. Change this line if using open or WEP network: + status = WiFi.begin(ssid, pass); + + // wait 10 seconds for connection: + delay(10000); + } + server.begin(); + // you're connected now, so print out the status: + printWifiStatus(); +} + + +void loop() { + // listen for incoming clients + WiFiClient client = server.available(); + if (client) { + Serial.println("new client"); + // an HTTP request ends with a blank line + boolean currentLineIsBlank = true; + while (client.connected()) { + if (client.available()) { + char c = client.read(); + Serial.write(c); + // if you've gotten to the end of the line (received a newline + // character) and the line is blank, the HTTP request has ended, + // so you can send a reply + if (c == '\n' && currentLineIsBlank) { + // send a standard HTTP response header + client.println("HTTP/1.1 200 OK"); + client.println("Content-Type: text/html"); + client.println("Connection: close"); // the connection will be closed after completion of the response + client.println("Refresh: 5"); // refresh the page automatically every 5 sec + client.println(); + client.println(""); + client.println(""); + // output the value of each analog input pin + for (int analogChannel = 0; analogChannel < 6; analogChannel++) { + int sensorReading = analogRead(analogChannel); + client.print("analog input "); + client.print(analogChannel); + client.print(" is "); + client.print(sensorReading); + client.println("
"); + } + client.println(""); + break; + } + if (c == '\n') { + // you're starting a new line + currentLineIsBlank = true; + } else if (c != '\r') { + // you've gotten a character on the current line + currentLineIsBlank = false; + } + } + } + // give the web browser time to receive the data + delay(1); + + // close the connection: + client.stop(); + Serial.println("client disconnected"); + } +} + + +void printWifiStatus() { + // print the SSID of the network you're attached to: + Serial.print("SSID: "); + Serial.println(WiFi.SSID()); + + // print your board's IP address: + IPAddress ip = WiFi.localIP(); + Serial.print("IP Address: "); + Serial.println(ip); + + // print the received signal strength: + long rssi = WiFi.RSSI(); + Serial.print("signal strength (RSSI):"); + Serial.print(rssi); + Serial.println(" dBm"); +} diff --git a/lib/WiFiNINA/examples/WiFiWebServer/arduino_secrets.h b/lib/WiFiNINA/examples/WiFiWebServer/arduino_secrets.h new file mode 100644 index 0000000..0c9fdd5 --- /dev/null +++ b/lib/WiFiNINA/examples/WiFiWebServer/arduino_secrets.h @@ -0,0 +1,2 @@ +#define SECRET_SSID "" +#define SECRET_PASS "" diff --git a/lib/WiFiNINA/keywords.txt b/lib/WiFiNINA/keywords.txt new file mode 100644 index 0000000..2e1f9c6 --- /dev/null +++ b/lib/WiFiNINA/keywords.txt @@ -0,0 +1,65 @@ +####################################### +# Syntax Coloring Map For WiFiNINA +####################################### + +####################################### +# Library (KEYWORD1) +####################################### + +WiFi KEYWORD1 +WiFiNINA KEYWORD1 +WiFiUdp KEYWORD1 +WiFiClient KEYWORD1 +WiFiSSLClient KEYWORD1 +WiFiServer KEYWORD1 +WiFiUDP KEYWORD1 + + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +firmwareVersion KEYWORD2 +status KEYWORD2 +reasonCode KEYWORD2 +connect KEYWORD2 +write KEYWORD2 +available KEYWORD2 +config KEYWORD2 +setDNS KEYWORD2 +read KEYWORD2 +flush KEYWORD2 +stop KEYWORD2 +connected KEYWORD2 +begin KEYWORD2 +disconnect KEYWORD2 +macAddress KEYWORD2 +localIP KEYWORD2 +subnetMask KEYWORD2 +gatewayIP KEYWORD2 +SSID KEYWORD2 +BSSID KEYWORD2 +RSSI KEYWORD2 +encryptionType KEYWORD2 +beginPacket KEYWORD2 +endPacket KEYWORD2 +parsePacket KEYWORD2 +remoteIP KEYWORD2 +remotePort KEYWORD2 + +beginAP KEYWORD2 +beginEnterprise KEYWORD2 +setHostname KEYWORD2 +end KEYWORD2 +getTime KEYWORD2 +lowPowerMode KEYWORD2 +noLowPowerMode KEYWORD2 +ping KEYWORD2 +beginMulticast KEYWORD2 +setTimeout KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/lib/WiFiNINA/library.properties b/lib/WiFiNINA/library.properties new file mode 100644 index 0000000..3a8ebc2 --- /dev/null +++ b/lib/WiFiNINA/library.properties @@ -0,0 +1,10 @@ +name=WiFiNINA +version=1.8.8 +author=Arduino +maintainer=Arduino +sentence=Enables network connection (local and Internet) with the Arduino MKR WiFi 1010, Arduino MKR VIDOR 4000, Arduino UNO WiFi Rev.2 and Nano 33 IoT. +paragraph=With this library you can instantiate Servers, Clients and send/receive UDP packets through WiFi. The board can connect either to open or encrypted networks (WEP, WPA). The IP address can be assigned statically or through a DHCP. The library can also manage DNS. +category=Communication +url=http://www.arduino.cc/en/Reference/WiFiNINA +architectures=* +includes=WiFiNINA.h diff --git a/lib/WiFiNINA/src/WiFi.cpp b/lib/WiFiNINA/src/WiFi.cpp new file mode 100644 index 0000000..ed5bae0 --- /dev/null +++ b/lib/WiFiNINA/src/WiFi.cpp @@ -0,0 +1,385 @@ +/* + WiFi.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "utility/wifi_drv.h" +#include "WiFi.h" + +extern "C" { + #include "utility/wl_definitions.h" + #include "utility/wl_types.h" + #include "utility/debug.h" +} + +WiFiClass::WiFiClass() : _timeout(50000) +{ +} + +void WiFiClass::init() +{ + WiFiDrv::wifiDriverInit(); +} + +const char* WiFiClass::firmwareVersion() +{ + return WiFiDrv::getFwVersion(); +} + +int WiFiClass::begin(const char* ssid) +{ + uint8_t status = WL_IDLE_STATUS; + + if (WiFiDrv::wifiSetNetwork(ssid, strlen(ssid)) != WL_FAILURE) + { + for (unsigned long start = millis(); (millis() - start) < _timeout;) + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + if ((status != WL_IDLE_STATUS) && (status != WL_NO_SSID_AVAIL) && (status != WL_SCAN_COMPLETED)) { + break; + } + } + }else + { + status = WL_CONNECT_FAILED; + } + return status; +} + +int WiFiClass::begin(const char* ssid, uint8_t key_idx, const char *key) +{ + uint8_t status = WL_IDLE_STATUS; + + // set encryption key + if (WiFiDrv::wifiSetKey(ssid, strlen(ssid), key_idx, key, strlen(key)) != WL_FAILURE) + { + for (unsigned long start = millis(); (millis() - start) < _timeout;) + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + if ((status != WL_IDLE_STATUS) && (status != WL_NO_SSID_AVAIL) && (status != WL_SCAN_COMPLETED)) { + break; + } + } + }else{ + status = WL_CONNECT_FAILED; + } + return status; +} + +int WiFiClass::begin(const char* ssid, const char *passphrase) +{ + uint8_t status = WL_IDLE_STATUS; + + // set passphrase + if (WiFiDrv::wifiSetPassphrase(ssid, strlen(ssid), passphrase, strlen(passphrase))!= WL_FAILURE) + { + for (unsigned long start = millis(); (millis() - start) < _timeout;) + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + if ((status != WL_IDLE_STATUS) && (status != WL_NO_SSID_AVAIL) && (status != WL_SCAN_COMPLETED)) { + break; + } + } + }else{ + status = WL_CONNECT_FAILED; + } + return status; +} + +uint8_t WiFiClass::beginAP(const char *ssid) +{ + return beginAP(ssid, 1); +} + +uint8_t WiFiClass::beginAP(const char *ssid, uint8_t channel) +{ + uint8_t status = WL_IDLE_STATUS; + + if (WiFiDrv::wifiSetApNetwork(ssid, strlen(ssid), channel) != WL_FAILURE) + { + for (unsigned long start = millis(); (millis() - start) < _timeout;) + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + if ((status != WL_IDLE_STATUS) && (status != WL_NO_SSID_AVAIL) && (status != WL_SCAN_COMPLETED)) { + break; + } + } + }else + { + status = WL_AP_FAILED; + } + return status; +} + +uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase) +{ + return beginAP(ssid, passphrase, 1); +} + +uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase, uint8_t channel) +{ + uint8_t status = WL_IDLE_STATUS; + + // set passphrase + if (WiFiDrv::wifiSetApPassphrase(ssid, strlen(ssid), passphrase, strlen(passphrase), channel)!= WL_FAILURE) + { + for (unsigned long start = millis(); (millis() - start) < _timeout;) + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + if ((status != WL_IDLE_STATUS) && (status != WL_NO_SSID_AVAIL) && (status != WL_SCAN_COMPLETED)) { + break; + } + } + }else{ + status = WL_AP_FAILED; + } + return status; +} + +uint8_t WiFiClass::beginEnterprise(const char* ssid, const char* username, const char* password) +{ + return beginEnterprise(ssid, username, password, ""); +} + +uint8_t WiFiClass::beginEnterprise(const char* ssid, const char* username, const char* password, const char* identity) +{ + return beginEnterprise(ssid, username, password, identity, ""); +} + +uint8_t WiFiClass::beginEnterprise(const char* ssid, const char* username, const char* password, const char* identity, const char* ca) +{ + uint8_t status = WL_IDLE_STATUS; + + // set passphrase + if (WiFiDrv::wifiSetEnterprise(0 /*PEAP/MSCHAPv2*/, ssid, strlen(ssid), username, strlen(username), password, strlen(password), identity, strlen(identity), ca, strlen(ca) + 1)!= WL_FAILURE) + { + for (unsigned long start = millis(); (millis() - start) < _timeout;) + { + delay(WL_DELAY_START_CONNECTION); + status = WiFiDrv::getConnectionStatus(); + if ((status != WL_IDLE_STATUS) && (status != WL_NO_SSID_AVAIL) && (status != WL_SCAN_COMPLETED)) { + break; + } + } + } else { + status = WL_CONNECT_FAILED; + } + return status; +} + +void WiFiClass::config(IPAddress local_ip) +{ + WiFiDrv::config(1, (uint32_t)local_ip, 0, 0); +} + +void WiFiClass::config(IPAddress local_ip, IPAddress dns_server) +{ + WiFiDrv::config(1, (uint32_t)local_ip, 0, 0); + WiFiDrv::setDNS(1, (uint32_t)dns_server, 0); +} + +void WiFiClass::config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway) +{ + WiFiDrv::config(2, (uint32_t)local_ip, (uint32_t)gateway, 0); + WiFiDrv::setDNS(1, (uint32_t)dns_server, 0); +} + +void WiFiClass::config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) +{ + WiFiDrv::config(3, (uint32_t)local_ip, (uint32_t)gateway, (uint32_t)subnet); + WiFiDrv::setDNS(1, (uint32_t)dns_server, 0); +} + +void WiFiClass::setDNS(IPAddress dns_server1) +{ + WiFiDrv::setDNS(1, (uint32_t)dns_server1, 0); +} + +void WiFiClass::setDNS(IPAddress dns_server1, IPAddress dns_server2) +{ + WiFiDrv::setDNS(2, (uint32_t)dns_server1, (uint32_t)dns_server2); +} + +void WiFiClass::setHostname(const char* name) +{ + WiFiDrv::setHostname(name); +} + +int WiFiClass::disconnect() +{ + return WiFiDrv::disconnect(); +} + +void WiFiClass::end(void) +{ + WiFiDrv::wifiDriverDeinit(); +} + +uint8_t* WiFiClass::macAddress(uint8_t* mac) +{ + uint8_t* _mac = WiFiDrv::getMacAddress(); + memcpy(mac, _mac, WL_MAC_ADDR_LENGTH); + return mac; +} + +IPAddress WiFiClass::localIP() +{ + IPAddress ret; + WiFiDrv::getIpAddress(ret); + return ret; +} + +IPAddress WiFiClass::subnetMask() +{ + IPAddress ret; + WiFiDrv::getSubnetMask(ret); + return ret; +} + +IPAddress WiFiClass::gatewayIP() +{ + IPAddress ret; + WiFiDrv::getGatewayIP(ret); + return ret; +} + +const char* WiFiClass::SSID() +{ + return WiFiDrv::getCurrentSSID(); +} + +uint8_t* WiFiClass::BSSID(uint8_t* bssid) +{ + uint8_t* _bssid = WiFiDrv::getCurrentBSSID(); + memcpy(bssid, _bssid, WL_MAC_ADDR_LENGTH); + return bssid; +} + +int32_t WiFiClass::RSSI() +{ + return WiFiDrv::getCurrentRSSI(); +} + +uint8_t WiFiClass::encryptionType() +{ + return WiFiDrv::getCurrentEncryptionType(); +} + + +int8_t WiFiClass::scanNetworks() +{ + uint8_t attempts = 10; + uint8_t numOfNetworks = 0; + + if (WiFiDrv::startScanNetworks() == WL_FAILURE) + return WL_FAILURE; + do + { + delay(2000); + numOfNetworks = WiFiDrv::getScanNetworks(); + } + while (( numOfNetworks == 0)&&(--attempts>0)); + return numOfNetworks; +} + +const char* WiFiClass::SSID(uint8_t networkItem) +{ + return WiFiDrv::getSSIDNetoworks(networkItem); +} + +int32_t WiFiClass::RSSI(uint8_t networkItem) +{ + return WiFiDrv::getRSSINetoworks(networkItem); +} + +uint8_t WiFiClass::encryptionType(uint8_t networkItem) +{ + return WiFiDrv::getEncTypeNetowrks(networkItem); +} + +uint8_t* WiFiClass::BSSID(uint8_t networkItem, uint8_t* bssid) +{ + return WiFiDrv::getBSSIDNetowrks(networkItem, bssid); +} + +uint8_t WiFiClass::channel(uint8_t networkItem) +{ + return WiFiDrv::getChannelNetowrks(networkItem); +} + +uint8_t WiFiClass::status() +{ + return WiFiDrv::getConnectionStatus(); +} + +uint8_t WiFiClass::reasonCode() +{ + return WiFiDrv::getReasonCode(); +} + +int WiFiClass::hostByName(const char* aHostname, IPAddress& aResult) +{ + return WiFiDrv::getHostByName(aHostname, aResult); +} + +unsigned long WiFiClass::getTime() +{ + return WiFiDrv::getTime(); +} + +void WiFiClass::lowPowerMode() +{ + WiFiDrv::setPowerMode(1); +} + +void WiFiClass::noLowPowerMode() +{ + WiFiDrv::setPowerMode(0); +} + +int WiFiClass::ping(const char* hostname, uint8_t ttl) +{ + IPAddress ip; + + if (!hostByName(hostname, ip)) { + return WL_PING_UNKNOWN_HOST; + } + + return ping(ip, ttl); +} + +int WiFiClass::ping(const String &hostname, uint8_t ttl) +{ + return ping(hostname.c_str(), ttl); +} + +int WiFiClass::ping(IPAddress host, uint8_t ttl) +{ + return WiFiDrv::ping(host, ttl); +} + +void WiFiClass::setTimeout(unsigned long timeout) +{ + _timeout = timeout; +} +WiFiClass WiFi; diff --git a/lib/WiFiNINA/src/WiFi.h b/lib/WiFiNINA/src/WiFi.h new file mode 100644 index 0000000..38c879c --- /dev/null +++ b/lib/WiFiNINA/src/WiFi.h @@ -0,0 +1,281 @@ +/* + WiFi.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WiFi_h +#define WiFi_h + +#define WIFI_FIRMWARE_LATEST_VERSION "1.4.4" + +#include + +extern "C" { + #include "utility/wl_definitions.h" + #include "utility/wl_types.h" +} + +#include "IPAddress.h" +#include "WiFiClient.h" +#include "WiFiSSLClient.h" +#include "WiFiServer.h" +#include "WiFiStorage.h" + +class WiFiClass +{ +private: + + static void init(); + unsigned long _timeout; +public: + WiFiClass(); + + /* + * Get firmware version + */ + static const char* firmwareVersion(); + + + /* Start WiFi connection for OPEN networks + * + * param ssid: Pointer to the SSID string. + */ + int begin(const char* ssid); + + /* Start WiFi connection with WEP encryption. + * Configure a key into the device. The key type (WEP-40, WEP-104) + * is determined by the size of the key (5 bytes for WEP-40, 13 bytes for WEP-104). + * + * param ssid: Pointer to the SSID string. + * param key_idx: The key index to set. Valid values are 0-3. + * param key: Key input buffer. + */ + int begin(const char* ssid, uint8_t key_idx, const char* key); + + /* Start WiFi connection with passphrase + * the most secure supported mode will be automatically selected + * + * param ssid: Pointer to the SSID string. + * param passphrase: Passphrase. Valid characters in a passphrase + * must be between ASCII 32-126 (decimal). + */ + int begin(const char* ssid, const char *passphrase); + + uint8_t beginAP(const char *ssid); + uint8_t beginAP(const char *ssid, uint8_t channel); + uint8_t beginAP(const char *ssid, const char* passphrase); + uint8_t beginAP(const char *ssid, const char* passphrase, uint8_t channel); + + uint8_t beginEnterprise(const char* ssid, const char* username, const char* password); + uint8_t beginEnterprise(const char* ssid, const char* username, const char* password, const char* identity); + uint8_t beginEnterprise(const char* ssid, const char* username, const char* password, const char* identity, const char* ca); + + /* Change Ip configuration settings disabling the dhcp client + * + * param local_ip: Static ip configuration + */ + void config(IPAddress local_ip); + + /* Change Ip configuration settings disabling the dhcp client + * + * param local_ip: Static ip configuration + * param dns_server: IP configuration for DNS server 1 + */ + void config(IPAddress local_ip, IPAddress dns_server); + + /* Change Ip configuration settings disabling the dhcp client + * + * param local_ip: Static ip configuration + * param dns_server: IP configuration for DNS server 1 + * param gateway : Static gateway configuration + */ + void config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway); + + /* Change Ip configuration settings disabling the dhcp client + * + * param local_ip: Static ip configuration + * param dns_server: IP configuration for DNS server 1 + * param gateway: Static gateway configuration + * param subnet: Static Subnet mask + */ + void config(IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet); + + /* Change DNS Ip configuration + * + * param dns_server1: ip configuration for DNS server 1 + */ + void setDNS(IPAddress dns_server1); + + /* Change DNS Ip configuration + * + * param dns_server1: ip configuration for DNS server 1 + * param dns_server2: ip configuration for DNS server 2 + * + */ + void setDNS(IPAddress dns_server1, IPAddress dns_server2); + + + /* Set the hostname used for DHCP requests + * + * param name: hostname to set + * + */ + void setHostname(const char* name); + + /* + * Disconnect from the network + * + * return: one value of wl_status_t enum + */ + int disconnect(void); + + void end(void); + + /* + * Get the interface MAC address. + * + * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + */ + uint8_t* macAddress(uint8_t* mac); + + /* + * Get the interface IP address. + * + * return: Ip address value + */ + IPAddress localIP(); + + /* + * Get the interface subnet mask address. + * + * return: subnet mask address value + */ + IPAddress subnetMask(); + + /* + * Get the gateway ip address. + * + * return: gateway ip address value + */ + IPAddress gatewayIP(); + + /* + * Return the current SSID associated with the network + * + * return: ssid string + */ + const char* SSID(); + + /* + * Return the current BSSID associated with the network. + * It is the MAC address of the Access Point + * + * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + */ + uint8_t* BSSID(uint8_t* bssid); + + /* + * Return the current RSSI /Received Signal Strength in dBm) + * associated with the network + * + * return: signed value + */ + int32_t RSSI(); + + /* + * Return the Encryption Type associated with the network + * + * return: one value of wl_enc_type enum + */ + uint8_t encryptionType(); + + /* + * Start scan WiFi networks available + * + * return: Number of discovered networks + */ + int8_t scanNetworks(); + + /* + * Return the SSID discovered during the network scan. + * + * param networkItem: specify from which network item want to get the information + * + * return: ssid string of the specified item on the networks scanned list + */ + const char* SSID(uint8_t networkItem); + + /* + * Return the encryption type of the networks discovered during the scanNetworks + * + * param networkItem: specify from which network item want to get the information + * + * return: encryption type (enum wl_enc_type) of the specified item on the networks scanned list + */ + uint8_t encryptionType(uint8_t networkItem); + + uint8_t* BSSID(uint8_t networkItem, uint8_t* bssid); + uint8_t channel(uint8_t networkItem); + + /* + * Return the RSSI of the networks discovered during the scanNetworks + * + * param networkItem: specify from which network item want to get the information + * + * return: signed value of RSSI of the specified item on the networks scanned list + */ + int32_t RSSI(uint8_t networkItem); + + /* + * Return Connection status. + * + * return: one of the value defined in wl_status_t + */ + uint8_t status(); + + /* + * Return The deauthentication reason code. + * + * return: the deauthentication reason code + */ + uint8_t reasonCode(); + + /* + * Resolve the given hostname to an IP address. + * param aHostname: Name to be resolved + * param aResult: IPAddress structure to store the returned IP address + * result: 1 if aIPAddrString was successfully converted to an IP address, + * else error code + */ + int hostByName(const char* aHostname, IPAddress& aResult); + + unsigned long getTime(); + + void lowPowerMode(); + void noLowPowerMode(); + + int ping(const char* hostname, uint8_t ttl = 128); + int ping(const String &hostname, uint8_t ttl = 128); + int ping(IPAddress host, uint8_t ttl = 128); + + void setTimeout(unsigned long timeout); +}; + +extern WiFiClass WiFi; + +#endif diff --git a/lib/WiFiNINA/src/WiFiClient.cpp b/lib/WiFiNINA/src/WiFiClient.cpp new file mode 100644 index 0000000..5843372 --- /dev/null +++ b/lib/WiFiNINA/src/WiFiClient.cpp @@ -0,0 +1,363 @@ +/* + WiFiClient.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +extern "C" { + #include "utility/wl_definitions.h" + #include "utility/wl_types.h" + #include "string.h" + #include "utility/debug.h" +} + + +#include "utility/server_drv.h" +#include "utility/wifi_drv.h" +#include "utility/WiFiSocketBuffer.h" + +#include "WiFi.h" +#include "WiFiClient.h" + +uint16_t WiFiClient::_srcport = 1024; + +WiFiClient::WiFiClient() : _sock(NO_SOCKET_AVAIL), _retrySend(true) { +} + +WiFiClient::WiFiClient(uint8_t sock) : _sock(sock), _retrySend(true) { +} + +int WiFiClient::connect(const char* host, uint16_t port) { + IPAddress remote_addr; + if (WiFi.hostByName(host, remote_addr)) + { + return connect(remote_addr, port); + } + return 0; +} + +int WiFiClient::connect(IPAddress ip, uint16_t port) { + if (_sock != NO_SOCKET_AVAIL) + { + stop(); + } + + _sock = ServerDrv::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startClient(uint32_t(ip), port, _sock); + + unsigned long start = millis(); + + // wait 4 second for the connection to close + while (!connected() && millis() - start < 10000) + delay(1); + + if (!connected()) + { + return 0; + } + } else { + Serial.println("No Socket available"); + return 0; + } + return 1; +} + +int WiFiClient::connectSSL(IPAddress ip, uint16_t port) +{ + if (_sock != NO_SOCKET_AVAIL) + { + stop(); + } + + _sock = ServerDrv::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startClient(uint32_t(ip), port, _sock, TLS_MODE); + + unsigned long start = millis(); + + // wait 4 second for the connection to close + while (!connected() && millis() - start < 10000) + delay(1); + + if (!connected()) + { + return 0; + } + } else { + Serial.println("No Socket available"); + return 0; + } + return 1; +} + +int WiFiClient::connectSSL(const char *host, uint16_t port) +{ + if (_sock != NO_SOCKET_AVAIL) + { + stop(); + } + + _sock = ServerDrv::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startClient(host, strlen(host), uint32_t(0), port, _sock, TLS_MODE); + + unsigned long start = millis(); + + // wait 4 second for the connection to close + while (!connected() && millis() - start < 10000) + delay(1); + + if (!connected()) + { + return 0; + } + } else { + Serial.println("No Socket available"); + return 0; + } + return 1; +} + +int WiFiClient::connectBearSSL(IPAddress ip, uint16_t port) +{ + if (_sock != NO_SOCKET_AVAIL) + { + stop(); + } + + _sock = ServerDrv::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startClient(uint32_t(ip), port, _sock, TLS_BEARSSL_MODE); + + unsigned long start = millis(); + + // wait 4 second for the connection to close + while (!connected() && millis() - start < 10000) + delay(1); + + if (!connected()) + { + return 0; + } + } else { + Serial.println("No Socket available"); + return 0; + } + return 1; +} + +int WiFiClient::connectBearSSL(const char *host, uint16_t port) +{ + if (_sock != NO_SOCKET_AVAIL) + { + stop(); + } + + _sock = ServerDrv::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startClient(host, strlen(host), uint32_t(0), port, _sock, TLS_BEARSSL_MODE); + + unsigned long start = millis(); + + // wait 4 second for the connection to close + while (!connected() && millis() - start < 10000) + delay(1); + + if (!connected()) + { + return 0; + } + } else { + Serial.println("No Socket available"); + return 0; + } + return 1; +} + +size_t WiFiClient::write(uint8_t b) { + return write(&b, 1); +} + +size_t WiFiClient::write(const uint8_t *buf, size_t size) { + if (_sock == NO_SOCKET_AVAIL) + { + setWriteError(); + return 0; + } + if (size==0) + { + setWriteError(); + return 0; + } + + size_t written = ServerDrv::sendData(_sock, buf, size); + if (!written && _retrySend) { + written = retry(buf, size, true); + } + if(!written){ + // close socket + ServerDrv::stopClient(_sock); + setWriteError(); + return 0; + } + + if (!ServerDrv::checkDataSent(_sock)) + { + setWriteError(); + return 0; + } + + return written; +} + +size_t WiFiClient::retry(const uint8_t *buf, size_t size, bool write) { + size_t rec_bytes = 0; + + if (write) { + + //RETRY WRITE + for (int i=0; i<5; i++) { + rec_bytes = ServerDrv::sendData(_sock, buf, size); + if (rec_bytes) { + break; + } + } + return rec_bytes; + + } else { + return rec_bytes; + //RETRY READ + // To be implemented, if needed + } + +} + +int WiFiClient::available() { + if (_sock != 255) + { + return WiFiSocketBuffer.available(_sock); + } + + return 0; +} + +int WiFiClient::read() { + if (!available()) + { + return -1; + } + + uint8_t b; + + WiFiSocketBuffer.read(_sock, &b, sizeof(b)); + + return b; +} + + +int WiFiClient::read(uint8_t* buf, size_t size) { + return WiFiSocketBuffer.read(_sock, buf, size); +} + +int WiFiClient::peek() { + return WiFiSocketBuffer.peek(_sock); +} + +void WiFiClient::setRetry(bool retry) { + _retrySend = retry; +} + +void WiFiClient::flush() { + // TODO: a real check to ensure transmission has been completed +} + +void WiFiClient::stop() { + + if (_sock == 255) + return; + + ServerDrv::stopClient(_sock); + + int count = 0; + // wait maximum 5 secs for the connection to close + while (status() != CLOSED && ++count < 50) + delay(100); + + WiFiSocketBuffer.close(_sock); + _sock = 255; +} + +uint8_t WiFiClient::connected() { + + if (_sock == 255) { + return 0; + } else if (available()) { + return 1; + } else { + uint8_t s = status(); + + uint8_t result = !(s == LISTEN || s == CLOSED || s == FIN_WAIT_1 || + s == FIN_WAIT_2 || s == TIME_WAIT || + s == SYN_SENT || s== SYN_RCVD || + (s == CLOSE_WAIT)); + + if (result == 0) { + WiFiSocketBuffer.close(_sock); + _sock = 255; + } + + return result; + } +} + +uint8_t WiFiClient::status() { + if (_sock == 255) { + return CLOSED; + } else { + return ServerDrv::getClientState(_sock); + } +} + +WiFiClient::operator bool() { + return _sock != 255; +} + +IPAddress WiFiClient::remoteIP() +{ + uint8_t _remoteIp[4] = {0}; + uint8_t _remotePort[2] = {0}; + + WiFiDrv::getRemoteData(_sock, _remoteIp, _remotePort); + IPAddress ip(_remoteIp); + return ip; +} + +uint16_t WiFiClient::remotePort() +{ + uint8_t _remoteIp[4] = {0}; + uint8_t _remotePort[2] = {0}; + + WiFiDrv::getRemoteData(_sock, _remoteIp, _remotePort); + uint16_t port = (_remotePort[0]<<8)+_remotePort[1]; + return port; +} diff --git a/lib/WiFiNINA/src/WiFiClient.h b/lib/WiFiNINA/src/WiFiClient.h new file mode 100644 index 0000000..a6f43e2 --- /dev/null +++ b/lib/WiFiNINA/src/WiFiClient.h @@ -0,0 +1,69 @@ +/* + WiFiClient.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef wificlient_h +#define wificlient_h +#include "Arduino.h" +#include "Print.h" +#include "Client.h" +#include "IPAddress.h" + +class WiFiClient : public Client { + +public: + WiFiClient(); + WiFiClient(uint8_t sock); + + uint8_t status(); + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char *host, uint16_t port); + virtual int connectSSL(IPAddress ip, uint16_t port); + virtual int connectSSL(const char *host, uint16_t port); + virtual int connectBearSSL(IPAddress ip, uint16_t port); + virtual int connectBearSSL(const char *host, uint16_t port); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + virtual size_t retry(const uint8_t *buf, size_t size, bool write); + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void setRetry(bool retry); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool(); + + virtual IPAddress remoteIP(); + virtual uint16_t remotePort(); + + friend class WiFiServer; + friend class WiFiDrv; + + using Print::write; + +private: + static uint16_t _srcport; + uint8_t _sock; //not used + uint16_t _socket; + bool _retrySend; +}; + +#endif diff --git a/lib/WiFiNINA/src/WiFiNINA.h b/lib/WiFiNINA/src/WiFiNINA.h new file mode 100644 index 0000000..c6c7754 --- /dev/null +++ b/lib/WiFiNINA/src/WiFiNINA.h @@ -0,0 +1,25 @@ +/* + This file is part of the WiFiNINA library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WiFiNINA_h +#define WiFiNINA_h + +#include "WiFi.h" + +#endif diff --git a/lib/WiFiNINA/src/WiFiSSLClient.cpp b/lib/WiFiNINA/src/WiFiSSLClient.cpp new file mode 100644 index 0000000..f051144 --- /dev/null +++ b/lib/WiFiNINA/src/WiFiSSLClient.cpp @@ -0,0 +1,60 @@ +/* + This file is part of the WiFiNINA library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "WiFiSSLClient.h" + +WiFiSSLClient::WiFiSSLClient() : + WiFiClient() +{ +} + +WiFiSSLClient::WiFiSSLClient(uint8_t sock) : + WiFiClient(sock) +{ +} + +int WiFiSSLClient::connect(IPAddress ip, uint16_t port) +{ + return WiFiClient::connectSSL(ip, port); +} + +int WiFiSSLClient::connect(const char* host, uint16_t port) +{ + return WiFiClient::connectSSL(host, port); +} + +WiFiBearSSLClient::WiFiBearSSLClient() : + WiFiClient() +{ +} + +WiFiBearSSLClient::WiFiBearSSLClient(uint8_t sock) : + WiFiClient(sock) +{ +} + +int WiFiBearSSLClient::connect(IPAddress ip, uint16_t port) +{ + return WiFiClient::connectBearSSL(ip, port); +} + +int WiFiBearSSLClient::connect(const char* host, uint16_t port) +{ + return WiFiClient::connectBearSSL(host, port); +} diff --git a/lib/WiFiNINA/src/WiFiSSLClient.h b/lib/WiFiNINA/src/WiFiSSLClient.h new file mode 100644 index 0000000..41c3a6a --- /dev/null +++ b/lib/WiFiNINA/src/WiFiSSLClient.h @@ -0,0 +1,45 @@ +/* + This file is part of the WiFiNINA library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WIFISSLCLIENT_H +#define WIFISSLCLIENT_H + +#include "WiFiClient.h" + +class WiFiSSLClient : public WiFiClient { + +public: + WiFiSSLClient(); + WiFiSSLClient(uint8_t sock); + + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char* host, uint16_t port); +}; + +class WiFiBearSSLClient : public WiFiClient { + +public: + WiFiBearSSLClient(); + WiFiBearSSLClient(uint8_t sock); + + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char* host, uint16_t port); +}; + +#endif /* WIFISSLCLIENT_H */ diff --git a/lib/WiFiNINA/src/WiFiServer.cpp b/lib/WiFiNINA/src/WiFiServer.cpp new file mode 100644 index 0000000..729958b --- /dev/null +++ b/lib/WiFiNINA/src/WiFiServer.cpp @@ -0,0 +1,119 @@ +/* + WiFiServer.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "utility/server_drv.h" + +extern "C" { + #include "utility/debug.h" +} + +#include "WiFi.h" +#include "WiFiClient.h" +#include "WiFiServer.h" + +WiFiServer::WiFiServer(uint16_t port) : + _sock(NO_SOCKET_AVAIL), + _lastSock(NO_SOCKET_AVAIL) +{ + _port = port; +} + +void WiFiServer::begin() +{ + _sock = ServerDrv::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startServer(_port, _sock); + } +} + +WiFiClient WiFiServer::available(byte* status) +{ + int sock = NO_SOCKET_AVAIL; + + if (_sock != NO_SOCKET_AVAIL) { + // check previous received client socket + if (_lastSock != NO_SOCKET_AVAIL) { + WiFiClient client(_lastSock); + + if (client.connected() && client.available()) { + sock = _lastSock; + } + } + + if (sock == NO_SOCKET_AVAIL) { + // check for new client socket + sock = ServerDrv::availServer(_sock); + } + } + + if (sock != NO_SOCKET_AVAIL) { + WiFiClient client(sock); + + if (status != NULL) { + *status = client.status(); + } + + _lastSock = sock; + + return client; + } + + return WiFiClient(255); +} + +uint8_t WiFiServer::status() { + if (_sock == NO_SOCKET_AVAIL) { + return CLOSED; + } else { + return ServerDrv::getServerState(_sock); + } +} + + +size_t WiFiServer::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t WiFiServer::write(const uint8_t *buffer, size_t size) +{ + if (size==0) + { + setWriteError(); + return 0; + } + + size_t written = ServerDrv::sendData(_sock, buffer, size); + if (!written) + { + setWriteError(); + return 0; + } + + if (!ServerDrv::checkDataSent(_sock)) + { + setWriteError(); + return 0; + } + + return written; +} diff --git a/lib/WiFiNINA/src/WiFiServer.h b/lib/WiFiNINA/src/WiFiServer.h new file mode 100644 index 0000000..d60f558 --- /dev/null +++ b/lib/WiFiNINA/src/WiFiServer.h @@ -0,0 +1,49 @@ +/* + WiFiServer.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef wifiserver_h +#define wifiserver_h + +extern "C" { + #include "utility/wl_definitions.h" +} + +#include "Server.h" + +class WiFiClient; + +class WiFiServer : public Server { +private: + uint8_t _sock; + uint8_t _lastSock; + uint16_t _port; + void* pcb; +public: + WiFiServer(uint16_t); + WiFiClient available(uint8_t* status = NULL); + void begin(); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + uint8_t status(); + + using Print::write; +}; + +#endif diff --git a/lib/WiFiNINA/src/WiFiStorage.cpp b/lib/WiFiNINA/src/WiFiStorage.cpp new file mode 100644 index 0000000..21b50c9 --- /dev/null +++ b/lib/WiFiNINA/src/WiFiStorage.cpp @@ -0,0 +1,30 @@ +/* + WiFiStorage.cpp - Library for Arduino boards based on NINA WiFi module. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "WiFiStorage.h" + +WiFiStorageFile WiFiStorageClass::open(const char *filename) { + WiFiStorageFile file(filename); + file.size(); + return file; +} + +WiFiStorageFile WiFiStorageClass::open(String filename) { + return open(filename.c_str()); +} \ No newline at end of file diff --git a/lib/WiFiNINA/src/WiFiStorage.h b/lib/WiFiNINA/src/WiFiStorage.h new file mode 100644 index 0000000..30a6276 --- /dev/null +++ b/lib/WiFiNINA/src/WiFiStorage.h @@ -0,0 +1,151 @@ +/* + WiFiStorage.h - Library for Arduino boards based on NINA WiFi module. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef wifistorage_h +#define wifistorage_h + +#include "utility/wifi_drv.h" + +class WiFiStorageFile; + +class WiFiStorageClass +{ +public: + static bool begin(); + + static WiFiStorageFile open(const char *filename); + static WiFiStorageFile open(String filename); + + static bool exists(const char *filename) { + uint32_t len; + return (WiFiDrv::existsFile(filename, strlen(filename), &len) > 0); + } + static bool exists(const char *filename, uint32_t* len) { + return (WiFiDrv::existsFile(filename, strlen(filename), len) > 0); + } + static bool remove(const char *filename) { + WiFiDrv::deleteFile(filename, strlen(filename)); + return true; + } + static bool rename(const char * old_file_name, const char * new_file_name) { + return (WiFiDrv::renameFile(old_file_name, strlen(old_file_name), new_file_name, strlen(new_file_name)) == 0); + } + static bool read(const char *filename, uint32_t offset, uint8_t* buffer, uint32_t buffer_len) { + WiFiDrv::readFile(filename, strlen(filename), offset, buffer, buffer_len); + return true; + } + static bool write(const char *filename, uint32_t offset, uint8_t* buffer, uint32_t buffer_len) { + WiFiDrv::writeFile(filename, strlen(filename), offset, buffer, buffer_len); + return true; + } + static bool download(const char* url, const char *filename) { + WiFiDrv::downloadFile(url, strlen(url), filename, strlen(filename)); + return true; + } + static bool downloadOTA(const char * url, uint8_t * res_ota_download = NULL) { + /* The buffer within the nina firmware allows a maximum + * url size of 128 bytes. It's better to prevent the + * transmission of over-sized URL as soon as possible. + */ + if (strlen(url) > 128) + return false; + + uint8_t const res = WiFiDrv::downloadOTA(url, strlen(url)); + if (res_ota_download) + *res_ota_download = res; + bool const success = (res == 0); + return success; + } + + + static bool remove(String filename) { + return remove(filename.c_str()); + } + static bool rename(String old_file_name, String new_file_name) { + return rename(old_file_name.c_str(), new_file_name.c_str()); + } + static bool read(String filename, uint32_t offset, uint8_t* buffer, uint32_t buffer_len) { + return read(filename.c_str(), offset, buffer, buffer_len); + } + static bool write(String filename, uint32_t offset, uint8_t* buffer, uint32_t buffer_len) { + return write(filename.c_str(), offset, buffer, buffer_len); + } + static bool download(String url, String filename) { + return download(url.c_str(), filename.c_str()); + } + static bool download(String url, uint8_t * res_ota_download = NULL) { + return downloadOTA(url.c_str(), res_ota_download); + } +}; + +extern WiFiStorageClass WiFiStorage; + + +class WiFiStorageFile +{ +public: + constexpr WiFiStorageFile(const char* _filename) : filename(_filename) { } + + operator bool() { + return WiFiStorage.exists(filename, &length); + } + uint32_t read(void *buf, uint32_t rdlen) { + if (offset + rdlen > length) { + if (offset >= length) return 0; + rdlen = length - offset; + } + WiFiStorage.read(filename, offset, (uint8_t*)buf, rdlen); + offset += rdlen; + return rdlen; + } + uint32_t write(const void *buf, uint32_t wrlen) { + WiFiStorage.write(filename, offset, (uint8_t*)buf, wrlen); + offset += wrlen; + return wrlen; + } + void seek(uint32_t n) { + offset = n; + } + uint32_t position() { + return offset; + } + uint32_t size() { + WiFiStorage.exists(filename, &length); + return length; + } + uint32_t available() { + WiFiStorage.exists(filename, &length); + return length - offset; + } + void erase() { + offset = 0; + WiFiStorage.remove(filename); + } + void flush(); + void close() { + offset = 0; + } +protected: + friend class WiFiStorageClass; + uint32_t offset = 0; + uint32_t length = 0; + const char* filename; +}; + +#endif \ No newline at end of file diff --git a/lib/WiFiNINA/src/WiFiUdp.cpp b/lib/WiFiNINA/src/WiFiUdp.cpp new file mode 100644 index 0000000..12f27fa --- /dev/null +++ b/lib/WiFiNINA/src/WiFiUdp.cpp @@ -0,0 +1,217 @@ +/* + WiFiUdp.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +extern "C" { + #include "utility/debug.h" + #include "utility/wifi_spi.h" +} + +#include "utility/server_drv.h" +#include "utility/wifi_drv.h" +#include "utility/WiFiSocketBuffer.h" + +#include "WiFi.h" +#include "WiFiUdp.h" +#include "WiFiClient.h" +#include "WiFiServer.h" + + +/* Constructor */ +WiFiUDP::WiFiUDP() : _sock(NO_SOCKET_AVAIL), _parsed(0) {} + +/* Start WiFiUDP socket, listening at local port PORT */ +uint8_t WiFiUDP::begin(uint16_t port) { + if (_sock != NO_SOCKET_AVAIL) + { + stop(); + } + + uint8_t sock = ServerDrv::getSocket(); + if (sock != NO_SOCKET_AVAIL) + { + ServerDrv::startServer(port, sock, UDP_MODE); + _sock = sock; + _port = port; + _parsed = 0; + return 1; + } + return 0; +} + +uint8_t WiFiUDP::beginMulticast(IPAddress ip, uint16_t port) { + if (_sock != NO_SOCKET_AVAIL) + { + stop(); + } + + uint8_t sock = ServerDrv::getSocket(); + if (sock != NO_SOCKET_AVAIL) + { + ServerDrv::startServer(ip, port, sock, UDP_MULTICAST_MODE); + _sock = sock; + _port = port; + _parsed = 0; + return 1; + } + return 0; +} + +/* return number of bytes available in the current packet, + will return zero if parsePacket hasn't been called yet */ +int WiFiUDP::available() { + return _parsed; +} + +/* Release any resources being used by this WiFiUDP instance */ +void WiFiUDP::stop() +{ + if (_sock == NO_SOCKET_AVAIL) + return; + + ServerDrv::stopClient(_sock); + + WiFiSocketBuffer.close(_sock); + _sock = NO_SOCKET_AVAIL; +} + +int WiFiUDP::beginPacket(const char *host, uint16_t port) +{ + // Look up the host first + int ret = 0; + IPAddress remote_addr; + if (WiFi.hostByName(host, remote_addr)) + { + return beginPacket(remote_addr, port); + } + return ret; +} + +int WiFiUDP::beginPacket(IPAddress ip, uint16_t port) +{ + if (_sock == NO_SOCKET_AVAIL) + _sock = ServerDrv::getSocket(); + if (_sock != NO_SOCKET_AVAIL) + { + ServerDrv::startClient(uint32_t(ip), port, _sock, UDP_MODE); + return 1; + } + return 0; +} + +int WiFiUDP::endPacket() +{ + return ServerDrv::sendUdpData(_sock); +} + +size_t WiFiUDP::write(uint8_t byte) +{ + return write(&byte, 1); +} + +size_t WiFiUDP::write(const uint8_t *buffer, size_t size) +{ + ServerDrv::insertDataBuf(_sock, buffer, size); + return size; +} + +int WiFiUDP::parsePacket() +{ + while (_parsed--) + { + // discard previously parsed packet data + uint8_t b; + + WiFiSocketBuffer.read(_sock, &b, sizeof(b)); + } + + _parsed = ServerDrv::availData(_sock); + + return _parsed; +} + +int WiFiUDP::read() +{ + if (_parsed < 1) + { + return -1; + } + + uint8_t b; + + WiFiSocketBuffer.read(_sock, &b, sizeof(b)); + _parsed--; + + return b; +} + +int WiFiUDP::read(unsigned char* buffer, size_t len) +{ + if (_parsed < 1) + { + return 0; + } + + int result = WiFiSocketBuffer.read(_sock, buffer, len); + + if (result > 0) + { + _parsed -= result; + } + + return result; +} + +int WiFiUDP::peek() +{ + if (_parsed < 1) + { + return -1; + } + + return WiFiSocketBuffer.peek(_sock); +} + +void WiFiUDP::flush() +{ + // TODO: a real check to ensure transmission has been completed +} + +IPAddress WiFiUDP::remoteIP() +{ + uint8_t _remoteIp[4] = {0}; + uint8_t _remotePort[2] = {0}; + + WiFiDrv::getRemoteData(_sock, _remoteIp, _remotePort); + IPAddress ip(_remoteIp); + return ip; +} + +uint16_t WiFiUDP::remotePort() +{ + uint8_t _remoteIp[4] = {0}; + uint8_t _remotePort[2] = {0}; + + WiFiDrv::getRemoteData(_sock, _remoteIp, _remotePort); + uint16_t port = (_remotePort[0]<<8)+_remotePort[1]; + return port; +} + diff --git a/lib/WiFiNINA/src/WiFiUdp.h b/lib/WiFiNINA/src/WiFiUdp.h new file mode 100644 index 0000000..96c019e --- /dev/null +++ b/lib/WiFiNINA/src/WiFiUdp.h @@ -0,0 +1,83 @@ +/* + WiFiUdp.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino LLC. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef wifiudp_h +#define wifiudp_h + +#include + +#define UDP_TX_PACKET_MAX_SIZE 24 + +class WiFiUDP : public UDP { +private: + uint8_t _sock; // socket ID for Wiz5100 + uint16_t _port; // local port to listen on + int _parsed; + +public: + WiFiUDP(); // Constructor + virtual uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual uint8_t beginMulticast(IPAddress, uint16_t); // initialize, start listening on specified multicast IP address and port. Returns 1 if successful, 0 if there are no sockets available to use + virtual void stop(); // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port); + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port); + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket(); + // Write a single byte into the packet + virtual size_t write(uint8_t); + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size); + + using Print::write; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket(); + // Number of bytes remaining in the current packet + virtual int available(); + // Read a single byte from the current packet + virtual int read(); + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len); + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek(); + virtual void flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP(); + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort(); + + friend class WiFiDrv; +}; + +#endif diff --git a/lib/WiFiNINA/src/utility/WiFiSocketBuffer.cpp b/lib/WiFiNINA/src/utility/WiFiSocketBuffer.cpp new file mode 100644 index 0000000..2a73069 --- /dev/null +++ b/lib/WiFiNINA/src/utility/WiFiSocketBuffer.cpp @@ -0,0 +1,104 @@ +/* + This file is part of the WiFiNINA library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +#include "utility/server_drv.h" + +#include "WiFiSocketBuffer.h" + +#define WIFI_SOCKET_NUM_BUFFERS (sizeof(_buffers) / sizeof(_buffers[0])) + +#ifdef __AVR__ +#define WIFI_SOCKET_BUFFER_SIZE 64 +#else +#define WIFI_SOCKET_BUFFER_SIZE 1500 +#endif + +WiFiSocketBufferClass::WiFiSocketBufferClass() +{ + memset(&_buffers, 0x00, sizeof(_buffers)); +} + +WiFiSocketBufferClass::~WiFiSocketBufferClass() +{ + for (unsigned int i = 0; i < WIFI_SOCKET_NUM_BUFFERS; i++) { + close(i); + } +} + +void WiFiSocketBufferClass::close(int socket) +{ + if (_buffers[socket].data) { + free(_buffers[socket].data); + _buffers[socket].data = _buffers[socket].head = NULL; + _buffers[socket].length = 0; + } +} + +int WiFiSocketBufferClass::available(int socket) +{ + if (_buffers[socket].length == 0) { + if (_buffers[socket].data == NULL) { + _buffers[socket].data = _buffers[socket].head = (uint8_t*)malloc(WIFI_SOCKET_BUFFER_SIZE); + _buffers[socket].length = 0; + } + + // sizeof(size_t) is architecture dependent + // but we need a 16 bit data type here + uint16_t size = WIFI_SOCKET_BUFFER_SIZE; + if (ServerDrv::getDataBuf(socket, _buffers[socket].data, &size)) { + _buffers[socket].head = _buffers[socket].data; + _buffers[socket].length = size; + } + } + + return _buffers[socket].length; +} + +int WiFiSocketBufferClass::peek(int socket) +{ + if (!available(socket)) { + return -1; + } + + return *_buffers[socket].head; +} + +int WiFiSocketBufferClass::read(int socket, uint8_t* data, size_t length) +{ + int avail = available(socket); + + if (!avail) { + return 0; + } + + if (avail < (int)length) { + length = avail; + } + + memcpy(data, _buffers[socket].head, length); + _buffers[socket].head += length; + _buffers[socket].length -= length; + + return length; +} + +WiFiSocketBufferClass WiFiSocketBuffer; diff --git a/lib/WiFiNINA/src/utility/WiFiSocketBuffer.h b/lib/WiFiNINA/src/utility/WiFiSocketBuffer.h new file mode 100644 index 0000000..88572b7 --- /dev/null +++ b/lib/WiFiNINA/src/utility/WiFiSocketBuffer.h @@ -0,0 +1,52 @@ +/* + This file is part of the WiFiNINA library. + Copyright (c) 2018 Arduino SA. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WiFiSocketBuffer_h +#define WiFiSocketBuffer_h + +#include +#include + +extern "C" { + #include "utility/wl_definitions.h" +} + +class WiFiSocketBufferClass { + +public: + WiFiSocketBufferClass(); + ~WiFiSocketBufferClass(); + + void close(int socket); + + int available(int socket); + int peek(int socket); + int read(int socket, uint8_t* data, size_t length); + +private: + struct { + uint8_t* data; + uint8_t* head; + int length; + } _buffers[WIFI_MAX_SOCK_NUM]; +}; + +extern WiFiSocketBufferClass WiFiSocketBuffer; + +#endif diff --git a/lib/WiFiNINA/src/utility/debug.h b/lib/WiFiNINA/src/utility/debug.h new file mode 100644 index 0000000..5569e45 --- /dev/null +++ b/lib/WiFiNINA/src/utility/debug.h @@ -0,0 +1,95 @@ +/* + debug.h - Library for Arduino Wifi shield. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +//*********************************************/ +// +// File: debug.h +// +// Author: dlf (Metodo2 srl) +// +//********************************************/ + + +#ifndef Debug_H +#define Debug_H + +#include +#include + +#define PRINT_FILE_LINE() do { \ + Serial.print("[");Serial.print(__FILE__); \ + Serial.print("::");Serial.print(__LINE__);Serial.print("]");\ +}while (0); + +#ifdef _DEBUG_ + +#define INFO(format, args...) do { \ + char buf[250]; \ + sprintf(buf, format, args); \ + Serial.println(buf); \ +} while(0); + +#define INFO1(x) do { PRINT_FILE_LINE() Serial.print("-I-");\ + Serial.println(x); \ +}while (0); + + +#define INFO2(x,y) do { PRINT_FILE_LINE() Serial.print("-I-");\ + Serial.print(x,16);Serial.print(",");Serial.println(y,16); \ +}while (0); + + +#else +#define INFO1(x) do {} while(0); +#define INFO2(x,y) do {} while(0); +#define INFO(format, args...) do {} while(0); +#endif + +#if 0 +#define WARN(args) do { PRINT_FILE_LINE() \ + Serial.print("-W-"); Serial.println(args); \ +}while (0); +#else +#define WARN(args) do {} while (0); +#endif + +#if _DEBUG_SPI_ +#define DBG_PIN2 5 +#define DBG_PIN 4 + +#define START() digitalWrite(DBG_PIN2, HIGH); +#define END() digitalWrite(DBG_PIN2, LOW); +#define SET_TRIGGER() digitalWrite(DBG_PIN, HIGH); +#define RST_TRIGGER() digitalWrite(DBG_PIN, LOW); + +#define INIT_TRIGGER() pinMode(DBG_PIN, OUTPUT); \ + pinMode(DBG_PIN2, OUTPUT); \ + RST_TRIGGER() +#define TOGGLE_TRIGGER() SET_TRIGGER() \ + delayMicroseconds(2); \ + RST_TRIGGER() +#else +#define START() +#define END() +#define SET_TRIGGER() +#define RST_TRIGGER() +#define INIT_TRIGGER() +#define TOGGLE_TRIGGER() +#endif + +#endif diff --git a/lib/WiFiNINA/src/utility/server_drv.cpp b/lib/WiFiNINA/src/utility/server_drv.cpp new file mode 100644 index 0000000..4fc35b4 --- /dev/null +++ b/lib/WiFiNINA/src/utility/server_drv.cpp @@ -0,0 +1,520 @@ +/* + server_drv.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//#define _DEBUG_ + +#include "utility/server_drv.h" + +#include "Arduino.h" +#include "utility/spi_drv.h" + +extern "C" { +#include "utility/wl_types.h" +#include "utility/debug.h" +} + + +// Start server TCP on port specified +void ServerDrv::startServer(uint16_t port, uint8_t sock, uint8_t protMode) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(START_SERVER_TCP_CMD, PARAM_NUMS_3); + SpiDrv::sendParam(port); + SpiDrv::sendParam(&sock, 1); + SpiDrv::sendParam(&protMode, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(START_SERVER_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); +} + +void ServerDrv::startServer(uint32_t ipAddress, uint16_t port, uint8_t sock, uint8_t protMode) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(START_SERVER_TCP_CMD, PARAM_NUMS_4); + SpiDrv::sendParam((uint8_t*)&ipAddress, sizeof(ipAddress)); + SpiDrv::sendParam(port); + SpiDrv::sendParam(&sock, 1); + SpiDrv::sendParam(&protMode, 1, LAST_PARAM); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(START_SERVER_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); +} + +// Start server TCP on port specified +void ServerDrv::startClient(uint32_t ipAddress, uint16_t port, uint8_t sock, uint8_t protMode) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(START_CLIENT_TCP_CMD, PARAM_NUMS_4); + SpiDrv::sendParam((uint8_t*)&ipAddress, sizeof(ipAddress)); + SpiDrv::sendParam(port); + SpiDrv::sendParam(&sock, 1); + SpiDrv::sendParam(&protMode, 1, LAST_PARAM); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(START_CLIENT_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); +} + +void ServerDrv::startClient(const char* host, uint8_t host_len, uint32_t ipAddress, uint16_t port, uint8_t sock, uint8_t protMode) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(START_CLIENT_TCP_CMD, PARAM_NUMS_5); + SpiDrv::sendParam((uint8_t*)host, host_len); + SpiDrv::sendParam((uint8_t*)&ipAddress, sizeof(ipAddress)); + SpiDrv::sendParam(port); + SpiDrv::sendParam(&sock, 1); + SpiDrv::sendParam(&protMode, 1, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 17 + host_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(/* feed_watchdog = */ (protMode == TLS_BEARSSL_MODE)); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(START_CLIENT_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); +} + +// Start server TCP on port specified +void ServerDrv::stopClient(uint8_t sock) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(STOP_CLIENT_TCP_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(STOP_CLIENT_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); +} + + +uint8_t ServerDrv::getServerState(uint8_t sock) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_STATE_TCP_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(GET_STATE_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +uint8_t ServerDrv::getClientState(uint8_t sock) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_CLIENT_STATE_TCP_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(GET_CLIENT_STATE_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +uint16_t ServerDrv::availData(uint8_t sock) +{ + if (!SpiDrv::available()) { + return 0; + } + + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(AVAIL_DATA_TCP_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + uint16_t len = 0; + + SpiDrv::waitResponseCmd(AVAIL_DATA_TCP_CMD, PARAM_NUMS_1, (uint8_t*)&len, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return len; +} + +uint8_t ServerDrv::availServer(uint8_t sock) +{ + if (!SpiDrv::available()) { + return 255; + } + + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(AVAIL_DATA_TCP_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + uint16_t socket = 0; + + SpiDrv::waitResponseCmd(AVAIL_DATA_TCP_CMD, PARAM_NUMS_1, (uint8_t*)&socket, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return socket; +} + +bool ServerDrv::getData(uint8_t sock, uint8_t *data, uint8_t peek) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_DATA_TCP_CMD, PARAM_NUMS_2); + SpiDrv::sendParam(&sock, sizeof(sock)); + SpiDrv::sendParam(peek, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseData8(GET_DATA_TCP_CMD, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + if (_dataLen!=0) + { + *data = _data; + return true; + } + return false; +} + +bool ServerDrv::getDataBuf(uint8_t sock, uint8_t *_data, uint16_t *_dataLen) +{ + if (!SpiDrv::available()) + { + *_dataLen = 0; + return false; + } + + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_DATABUF_TCP_CMD, PARAM_NUMS_2); + SpiDrv::sendBuffer(&sock, sizeof(sock)); + SpiDrv::sendBuffer((uint8_t *)_dataLen, sizeof(*_dataLen), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + if (!SpiDrv::waitResponseData16(GET_DATABUF_TCP_CMD, _data, _dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + if (*_dataLen!=0) + { + return true; + } + return false; +} + +bool ServerDrv::insertDataBuf(uint8_t sock, const uint8_t *data, uint16_t _len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(INSERT_DATABUF_CMD, PARAM_NUMS_2); + SpiDrv::sendBuffer(&sock, sizeof(sock)); + SpiDrv::sendBuffer((uint8_t *)data, _len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 9 + _len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseData8(INSERT_DATABUF_CMD, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + if (_dataLen!=0) + { + return (_data == 1); + } + return false; +} + +bool ServerDrv::sendUdpData(uint8_t sock) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SEND_DATA_UDP_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseData8(SEND_DATA_UDP_CMD, &_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + if (_dataLen!=0) + { + return (_data == 1); + } + return false; +} + + +uint16_t ServerDrv::sendData(uint8_t sock, const uint8_t *data, uint16_t len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SEND_DATA_TCP_CMD, PARAM_NUMS_2); + SpiDrv::sendBuffer(&sock, sizeof(sock)); + SpiDrv::sendBuffer((uint8_t *)data, len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 9 + len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint16_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseData8(SEND_DATA_TCP_CMD, (uint8_t*)&_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + + return _data; +} + + +uint8_t ServerDrv::checkDataSent(uint8_t sock) +{ + const uint16_t TIMEOUT_DATA_SENT = 25; + uint16_t timeout = 0; + uint8_t _data = 0; + uint8_t _dataLen = 0; + + do { + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(DATA_SENT_TCP_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + if (!SpiDrv::waitResponseCmd(DATA_SENT_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse isDataSent"); + } + SpiDrv::spiSlaveDeselect(); + + if (_data) timeout = 0; + else{ + ++timeout; + delay(100); + } + + }while((_data==0)&&(timeout +#include "utility/wifi_spi.h" + +typedef enum eProtMode {TCP_MODE, UDP_MODE, TLS_MODE, UDP_MULTICAST_MODE, TLS_BEARSSL_MODE}tProtMode; + +class ServerDrv +{ +public: + + // Start server TCP on port specified + static void startServer(uint16_t port, uint8_t sock, uint8_t protMode=TCP_MODE); + + static void startServer(uint32_t ipAddress, uint16_t port, uint8_t sock, uint8_t protMode=TCP_MODE); + + static void startClient(uint32_t ipAddress, uint16_t port, uint8_t sock, uint8_t protMode=TCP_MODE); + + static void startClient(const char* host, uint8_t host_len, uint32_t ipAddress, uint16_t port, uint8_t sock, uint8_t protMode=TCP_MODE); + + static void stopClient(uint8_t sock); + + static uint8_t getServerState(uint8_t sock); + + static uint8_t getClientState(uint8_t sock); + + static bool getData(uint8_t sock, uint8_t *data, uint8_t peek = 0); + + static bool getDataBuf(uint8_t sock, uint8_t *data, uint16_t *len); + + static bool insertDataBuf(uint8_t sock, const uint8_t *_data, uint16_t _dataLen); + + static uint16_t sendData(uint8_t sock, const uint8_t *data, uint16_t len); + + static bool sendUdpData(uint8_t sock); + + static uint16_t availData(uint8_t sock); + + static uint8_t availServer(uint8_t sock); + + static uint8_t checkDataSent(uint8_t sock); + + static uint8_t getSocket(); +}; + +extern ServerDrv serverDrv; + +#endif diff --git a/lib/WiFiNINA/src/utility/spi_drv.cpp b/lib/WiFiNINA/src/utility/spi_drv.cpp new file mode 100644 index 0000000..c57e1c6 --- /dev/null +++ b/lib/WiFiNINA/src/utility/spi_drv.cpp @@ -0,0 +1,605 @@ +/* + spi_drv.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "Arduino.h" +#include +#include "utility/spi_drv.h" +#include "pins_arduino.h" + +#ifdef ARDUINO_SAMD_MKRVIDOR4000 + +// check if a bitstream is already included +#if __has_include() +// yes, so use the existing VidorFPGA include +#include +#else +// otherwise, fallback to VidorPeripherals and it's bitstream +#include +#endif + +#define NINA_GPIO0 FPGA_NINA_GPIO0 +#define SPIWIFI_SS FPGA_SPIWIFI_SS +#define SPIWIFI_ACK FPGA_SPIWIFI_ACK +#define SPIWIFI_RESET FPGA_SPIWIFI_RESET + +#define pinMode(pin, mode) FPGA.pinMode(pin, mode) +#define digitalRead(pin) FPGA.digitalRead(pin) +#define digitalWrite(pin, value) FPGA.digitalWrite(pin, value) +#endif + +//#define _DEBUG_ +extern "C" { +#include "utility/debug.h" +} + +static uint8_t SLAVESELECT = 10; // ss +static uint8_t SLAVEREADY = 7; // handshake pin +static uint8_t SLAVERESET = 5; // reset pin + +static bool inverted_reset = false; + +#define DELAY_TRANSFER() + +#ifndef SPIWIFI +#define SPIWIFI SPI +#endif + +#ifndef NINA_GPIOIRQ +#define NINA_GPIOIRQ NINA_GPIO0 +#endif + +bool SpiDrv::initialized = false; + +__attribute__((weak)) void wifi_nina_feed_watchdog() +{ + /* This function can be overwritten by a "strong" implementation + * in a higher level application, such as the ArduinoIoTCloud + * firmware stack. + */ +} + +void SpiDrv::begin() +{ +#ifdef ARDUINO_SAMD_MKRVIDOR4000 + FPGA.begin(); +#endif + +#ifdef SPIWIFI_SS + SLAVESELECT = SPIWIFI_SS; +#endif + +#ifdef SPIWIFI_ACK + SLAVEREADY = SPIWIFI_ACK; +#endif + +#ifdef SPIWIFI_RESET + SLAVERESET = (uint8_t)SPIWIFI_RESET; +#endif + +#ifdef ARDUINO_SAMD_MKRVIDOR4000 + inverted_reset = false; +#else + if (SLAVERESET > PINS_COUNT) { + inverted_reset = true; + SLAVERESET = ~SLAVERESET; + } +#endif + + pinMode(SLAVESELECT, OUTPUT); + pinMode(SLAVEREADY, INPUT); + pinMode(SLAVERESET, OUTPUT); + pinMode(NINA_GPIO0, OUTPUT); + + digitalWrite(NINA_GPIO0, HIGH); + digitalWrite(SLAVESELECT, HIGH); + digitalWrite(SLAVERESET, inverted_reset ? HIGH : LOW); + delay(10); + digitalWrite(SLAVERESET, inverted_reset ? LOW : HIGH); + delay(750); + + digitalWrite(NINA_GPIO0, LOW); + pinMode(NINA_GPIOIRQ, INPUT); + + SPIWIFI.begin(); + +#ifdef _DEBUG_ + INIT_TRIGGER() +#endif + + initialized = true; +} + +void SpiDrv::end() { + digitalWrite(SLAVERESET, inverted_reset ? HIGH : LOW); + + pinMode(SLAVESELECT, INPUT); + + SPIWIFI.end(); + + initialized = false; +} + +void SpiDrv::spiSlaveSelect() +{ + SPIWIFI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0)); + digitalWrite(SLAVESELECT,LOW); + + // wait for up to 5 ms for the NINA to indicate it is not ready for transfer + // the timeout is only needed for the case when the shield or module is not present + for (unsigned long start = millis(); (digitalRead(SLAVEREADY) != HIGH) && (millis() - start) < 5;); +} + + +void SpiDrv::spiSlaveDeselect() +{ + digitalWrite(SLAVESELECT,HIGH); + SPIWIFI.endTransaction(); +} + + +char SpiDrv::spiTransfer(volatile char data) +{ + char result = SPIWIFI.transfer(data); + DELAY_TRANSFER(); + + return result; // return the received byte +} + +int SpiDrv::waitSpiChar(unsigned char waitChar) +{ + int timeout = TIMEOUT_CHAR; + unsigned char _readChar = 0; + do{ + _readChar = readChar(); //get data byte + if (_readChar == ERR_CMD) + { + WARN("Err cmd received\n"); + return -1; + } + }while((timeout-- > 0) && (_readChar != waitChar)); + return (_readChar == waitChar); +} + +int SpiDrv::readAndCheckChar(char checkChar, char* readChar) +{ + getParam((uint8_t*)readChar); + + return (*readChar == checkChar); +} + +char SpiDrv::readChar() +{ + uint8_t readChar = 0; + getParam(&readChar); + return readChar; +} + +#define WAIT_START_CMD(x) waitSpiChar(START_CMD) + +#define IF_CHECK_START_CMD(x) \ + if (!WAIT_START_CMD(_data)) \ + { \ + TOGGLE_TRIGGER() \ + WARN("Error waiting START_CMD"); \ + return 0; \ + }else \ + +#define CHECK_DATA(check, x) \ + if (!readAndCheckChar(check, &x)) \ + { \ + TOGGLE_TRIGGER() \ + WARN("Reply error"); \ + INFO2(check, (uint8_t)x); \ + return 0; \ + }else \ + +#define waitSlaveReady() (digitalRead(SLAVEREADY) == LOW) +#define waitSlaveSign() (digitalRead(SLAVEREADY) == HIGH) +#define waitSlaveSignalH() while(digitalRead(SLAVEREADY) != HIGH){} +#define waitSlaveSignalL() while(digitalRead(SLAVEREADY) != LOW){} + +void SpiDrv::waitForSlaveSign() +{ + while (!waitSlaveSign()); +} + +void SpiDrv::waitForSlaveReady(bool const feed_watchdog) +{ + unsigned long const start = millis(); + while (!waitSlaveReady()) + { + if (feed_watchdog) { + if ((millis() - start) < 10000) { + wifi_nina_feed_watchdog(); + } + } + } +} + +void SpiDrv::getParam(uint8_t* param) +{ + // Get Params data + *param = spiTransfer(DUMMY_DATA); + DELAY_TRANSFER(); +} + +int SpiDrv::waitResponseCmd(uint8_t cmd, uint8_t numParam, uint8_t* param, uint8_t* param_len) +{ + char _data = 0; + int ii = 0; + + IF_CHECK_START_CMD(_data) + { + CHECK_DATA(cmd | REPLY_FLAG, _data){}; + + CHECK_DATA(numParam, _data) + { + readParamLen8(param_len); + for (ii=0; ii<(*param_len); ++ii) + { + // Get Params data + //param[ii] = spiTransfer(DUMMY_DATA); + getParam(¶m[ii]); + } + } + + readAndCheckChar(END_CMD, &_data); + } + + return 1; +} +/* +int SpiDrv::waitResponse(uint8_t cmd, uint8_t numParam, uint8_t* param, uint16_t* param_len) +{ + char _data = 0; + int i =0, ii = 0; + + IF_CHECK_START_CMD(_data) + { + CHECK_DATA(cmd | REPLY_FLAG, _data){}; + + CHECK_DATA(numParam, _data); + { + readParamLen16(param_len); + for (ii=0; ii<(*param_len); ++ii) + { + // Get Params data + param[ii] = spiTransfer(DUMMY_DATA); + } + } + + readAndCheckChar(END_CMD, &_data); + } + + return 1; +} +*/ + +int SpiDrv::waitResponseData16(uint8_t cmd, uint8_t* param, uint16_t* param_len) +{ + char _data = 0; + uint16_t ii = 0; + + IF_CHECK_START_CMD(_data) + { + CHECK_DATA(cmd | REPLY_FLAG, _data){}; + + uint8_t numParam = readChar(); + if (numParam != 0) + { + readParamLen16(param_len); + for (ii=0; ii<(*param_len); ++ii) + { + // Get Params data + param[ii] = spiTransfer(DUMMY_DATA); + } + } + + readAndCheckChar(END_CMD, &_data); + } + + return 1; +} + +int SpiDrv::waitResponseData8(uint8_t cmd, uint8_t* param, uint8_t* param_len) +{ + char _data = 0; + int ii = 0; + + IF_CHECK_START_CMD(_data) + { + CHECK_DATA(cmd | REPLY_FLAG, _data){}; + + uint8_t numParam = readChar(); + if (numParam != 0) + { + readParamLen8(param_len); + for (ii=0; ii<(*param_len); ++ii) + { + // Get Params data + param[ii] = spiTransfer(DUMMY_DATA); + } + } + + readAndCheckChar(END_CMD, &_data); + } + + return 1; +} + +int SpiDrv::waitResponseParams(uint8_t cmd, uint8_t numParam, tParam* params) +{ + char _data = 0; + int i =0, ii = 0; + + + IF_CHECK_START_CMD(_data) + { + CHECK_DATA(cmd | REPLY_FLAG, _data){}; + + uint8_t _numParam = readChar(); + if (_numParam != 0) + { + for (i=0; i<_numParam; ++i) + { + params[i].paramLen = readParamLen8(); + for (ii=0; ii maxNumParams) + { + numParam = maxNumParams; + } + *numParamRead = numParam; + if (numParam != 0) + { + for (i=0; i maxNumParams) + { + numParam = maxNumParams; + } + *numParamRead = numParam; + if (numParam != 0) + { + for (i=0; i>8)); + spiTransfer((uint8_t)(param_len & 0xff)); +} + +uint8_t SpiDrv::readParamLen8(uint8_t* param_len) +{ + uint8_t _param_len = spiTransfer(DUMMY_DATA); + if (param_len != NULL) + { + *param_len = _param_len; + } + return _param_len; +} + +uint16_t SpiDrv::readParamLen16(uint16_t* param_len) +{ + uint16_t _param_len = spiTransfer(DUMMY_DATA)<<8 | (spiTransfer(DUMMY_DATA)& 0xff); + if (param_len != NULL) + { + *param_len = _param_len; + } + return _param_len; +} + + +void SpiDrv::sendBuffer(uint8_t* param, uint16_t param_len, uint8_t lastParam) +{ + uint16_t i = 0; + + // Send Spi paramLen + sendParamLen16(param_len); + + // Send Spi param data + for (i=0; i>8)); + spiTransfer((uint8_t)(param & 0xff)); + + // if lastParam==1 Send Spi END CMD + if (lastParam == 1) + spiTransfer(END_CMD); +} + +/* Cmd Struct Message */ +/* _________________________________________________________________________________ */ +/*| START CMD | C/R | CMD |[TOT LEN]| N.PARAM | PARAM LEN | PARAM | .. | END CMD | */ +/*|___________|______|______|_________|_________|___________|________|____|_________| */ +/*| 8 bit | 1bit | 7bit | 8bit | 8bit | 8bit | nbytes | .. | 8bit | */ +/*|___________|______|______|_________|_________|___________|________|____|_________| */ + +void SpiDrv::sendCmd(uint8_t cmd, uint8_t numParam) +{ + // Send Spi START CMD + spiTransfer(START_CMD); + + // Send Spi C + cmd + spiTransfer(cmd & ~(REPLY_FLAG)); + + // Send Spi totLen + //spiTransfer(totLen); + + // Send Spi numParam + spiTransfer(numParam); + + // If numParam == 0 send END CMD + if (numParam == 0) + spiTransfer(END_CMD); + +} + +int SpiDrv::available() +{ + return (digitalRead(NINA_GPIOIRQ) != LOW); +} + +SpiDrv spiDrv; diff --git a/lib/WiFiNINA/src/utility/spi_drv.h b/lib/WiFiNINA/src/utility/spi_drv.h new file mode 100644 index 0000000..d8d1186 --- /dev/null +++ b/lib/WiFiNINA/src/utility/spi_drv.h @@ -0,0 +1,109 @@ +/* + spi_drv.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef SPI_Drv_h +#define SPI_Drv_h + +#include +#include "utility/wifi_spi.h" + +#define SPI_START_CMD_DELAY 10 + +#define NO_LAST_PARAM 0 +#define LAST_PARAM 1 + +#define DUMMY_DATA 0xFF + +#define WAIT_FOR_SLAVE_SELECT() \ + if (!SpiDrv::initialized) { \ + SpiDrv::begin(); \ + } \ + SpiDrv::waitForSlaveReady(); \ + SpiDrv::spiSlaveSelect(); + +class SpiDrv +{ +private: + //static bool waitSlaveReady(); + static void waitForSlaveSign(); + static void getParam(uint8_t* param); +public: + static bool initialized; + + static void begin(); + + static void end(); + + static void spiDriverInit(); + + static void spiSlaveSelect(); + + static void spiSlaveDeselect(); + + static char spiTransfer(volatile char data); + + static void waitForSlaveReady(bool const feed_watchdog = false); + + //static int waitSpiChar(char waitChar, char* readChar); + + static int waitSpiChar(unsigned char waitChar); + + static int readAndCheckChar(char checkChar, char* readChar); + + static char readChar(); + + static int waitResponseParams(uint8_t cmd, uint8_t numParam, tParam* params); + + static int waitResponseCmd(uint8_t cmd, uint8_t numParam, uint8_t* param, uint8_t* param_len); + + static int waitResponseData8(uint8_t cmd, uint8_t* param, uint8_t* param_len); + + static int waitResponseData16(uint8_t cmd, uint8_t* param, uint16_t* param_len); + /* + static int waitResponse(uint8_t cmd, tParam* params, uint8_t* numParamRead, uint8_t maxNumParams); + + static int waitResponse(uint8_t cmd, uint8_t numParam, uint8_t* param, uint16_t* param_len); +*/ + static int waitResponse(uint8_t cmd, uint8_t* numParamRead, uint8_t** params, uint8_t maxNumParams); + + static void sendParam(uint8_t* param, uint8_t param_len, uint8_t lastParam = NO_LAST_PARAM); + + static void sendParamNoLen(uint8_t* param, size_t param_len, uint8_t lastParam = NO_LAST_PARAM); + + static void sendParamLen8(uint8_t param_len); + + static void sendParamLen16(uint16_t param_len); + + static uint8_t readParamLen8(uint8_t* param_len = NULL); + + static uint16_t readParamLen16(uint16_t* param_len = NULL); + + static void sendBuffer(uint8_t* param, uint16_t param_len, uint8_t lastParam = NO_LAST_PARAM); + + static void sendParam(uint16_t param, uint8_t lastParam = NO_LAST_PARAM); + + static void sendCmd(uint8_t cmd, uint8_t numParam); + + static int available(); +}; + +extern SpiDrv spiDrv; + +#endif diff --git a/lib/WiFiNINA/src/utility/wifi_drv.cpp b/lib/WiFiNINA/src/utility/wifi_drv.cpp new file mode 100644 index 0000000..24beece --- /dev/null +++ b/lib/WiFiNINA/src/utility/wifi_drv.cpp @@ -0,0 +1,1262 @@ +/* + wifi_drv.cpp - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include + +#include "Arduino.h" +#include "utility/spi_drv.h" +#include "utility/wifi_drv.h" + +#define _DEBUG_ + +extern "C" { +#include "utility/wifi_spi.h" +#include "utility/wl_types.h" +#include "utility/debug.h" +} + +// Array of data to cache the information related to the networks discovered +char WiFiDrv::_networkSsid[][WL_SSID_MAX_LENGTH] = {{"1"},{"2"},{"3"},{"4"},{"5"}}; + +// Cached values of retrieved data +char WiFiDrv::_ssid[] = {0}; +uint8_t WiFiDrv::_bssid[] = {0}; +uint8_t WiFiDrv::_mac[] = {0}; +uint8_t WiFiDrv::_localIp[] = {0}; +uint8_t WiFiDrv::_subnetMask[] = {0}; +uint8_t WiFiDrv::_gatewayIp[] = {0}; +// Firmware version +char WiFiDrv::fwVersion[] = {0}; + + +// Private Methods + +void WiFiDrv::getNetworkData(uint8_t *ip, uint8_t *mask, uint8_t *gwip) +{ + tParam params[PARAM_NUMS_3] = { {0, (char*)ip}, {0, (char*)mask}, {0, (char*)gwip}}; + + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_IPADDR_CMD, PARAM_NUMS_1); + + uint8_t _dummy = DUMMY_DATA; + SpiDrv::sendParam(&_dummy, sizeof(_dummy), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + SpiDrv::waitResponseParams(GET_IPADDR_CMD, PARAM_NUMS_3, params); + + SpiDrv::spiSlaveDeselect(); +} + +void WiFiDrv::getRemoteData(uint8_t sock, uint8_t *ip, uint8_t *port) +{ + tParam params[PARAM_NUMS_2] = { {0, (char*)ip}, {0, (char*)port} }; + + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_REMOTE_DATA_CMD, PARAM_NUMS_1); + SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + SpiDrv::waitResponseParams(GET_REMOTE_DATA_CMD, PARAM_NUMS_2, params); + + SpiDrv::spiSlaveDeselect(); +} + + +// Public Methods + + +void WiFiDrv::wifiDriverInit() +{ + SpiDrv::begin(); +} + +void WiFiDrv::wifiDriverDeinit() +{ + SpiDrv::end(); +} + +int8_t WiFiDrv::wifiSetNetwork(const char* ssid, uint8_t ssid_len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_NET_CMD, PARAM_NUMS_1); + SpiDrv::sendParam((uint8_t*)ssid, ssid_len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 5 + ssid_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_NET_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + + return(_data == WIFI_SPI_ACK) ? WL_SUCCESS : WL_FAILURE; +} + +int8_t WiFiDrv::wifiSetPassphrase(const char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_PASSPHRASE_CMD, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)ssid, ssid_len, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)passphrase, len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 6 + ssid_len + len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_PASSPHRASE_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + + +int8_t WiFiDrv::wifiSetKey(const char* ssid, uint8_t ssid_len, uint8_t key_idx, const void *key, const uint8_t len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_KEY_CMD, PARAM_NUMS_3); + SpiDrv::sendParam((uint8_t*)ssid, ssid_len, NO_LAST_PARAM); + SpiDrv::sendParam(&key_idx, KEY_IDX_LEN, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)key, len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 8 + ssid_len + len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_KEY_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +void WiFiDrv::config(uint8_t validParams, uint32_t local_ip, uint32_t gateway, uint32_t subnet) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_IP_CONFIG_CMD, PARAM_NUMS_4); + SpiDrv::sendParam((uint8_t*)&validParams, 1, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&local_ip, 4, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&gateway, 4, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&subnet, 4, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_IP_CONFIG_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +void WiFiDrv::setDNS(uint8_t validParams, uint32_t dns_server1, uint32_t dns_server2) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_DNS_CONFIG_CMD, PARAM_NUMS_3); + SpiDrv::sendParam((uint8_t*)&validParams, 1, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&dns_server1, 4, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&dns_server2, 4, LAST_PARAM); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_DNS_CONFIG_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +void WiFiDrv::setHostname(const char* hostname) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_HOSTNAME_CMD, PARAM_NUMS_1); + SpiDrv::sendParam((uint8_t*)hostname, strlen(hostname), LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 5 + strlen(hostname); + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_HOSTNAME_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +int8_t WiFiDrv::disconnect() +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(DISCONNECT_CMD, PARAM_NUMS_1); + + uint8_t _dummy = DUMMY_DATA; + SpiDrv::sendParam(&_dummy, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + int8_t result = SpiDrv::waitResponseCmd(DISCONNECT_CMD, PARAM_NUMS_1, &_data, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return result; +} + +uint8_t WiFiDrv::getReasonCode() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_REASON_CODE_CMD, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 1; + uint8_t _dataLen = 0; + SpiDrv::waitResponseCmd(GET_REASON_CODE_CMD, PARAM_NUMS_1, &_data, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return _data; +} + +uint8_t WiFiDrv::getConnectionStatus() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_CONN_STATUS_CMD, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = -1; + uint8_t _dataLen = 0; + SpiDrv::waitResponseCmd(GET_CONN_STATUS_CMD, PARAM_NUMS_1, &_data, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return _data; +} + +uint8_t* WiFiDrv::getMacAddress() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_MACADDR_CMD, PARAM_NUMS_1); + + uint8_t _dummy = DUMMY_DATA; + SpiDrv::sendParam(&_dummy, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + SpiDrv::waitResponseCmd(GET_MACADDR_CMD, PARAM_NUMS_1, _mac, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return _mac; +} + +void WiFiDrv::getIpAddress(IPAddress& ip) +{ + getNetworkData(_localIp, _subnetMask, _gatewayIp); + ip = _localIp; +} + + void WiFiDrv::getSubnetMask(IPAddress& mask) + { + getNetworkData(_localIp, _subnetMask, _gatewayIp); + mask = _subnetMask; + } + + void WiFiDrv::getGatewayIP(IPAddress& ip) + { + getNetworkData(_localIp, _subnetMask, _gatewayIp); + ip = _gatewayIp; + } + +const char* WiFiDrv::getCurrentSSID() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_CURR_SSID_CMD, PARAM_NUMS_1); + + uint8_t _dummy = DUMMY_DATA; + SpiDrv::sendParam(&_dummy, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + memset(_ssid, 0x00, sizeof(_ssid)); + + // Wait for reply + uint8_t _dataLen = 0; + SpiDrv::waitResponseCmd(GET_CURR_SSID_CMD, PARAM_NUMS_1, (uint8_t*)_ssid, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return _ssid; +} + +uint8_t* WiFiDrv::getCurrentBSSID() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_CURR_BSSID_CMD, PARAM_NUMS_1); + + uint8_t _dummy = DUMMY_DATA; + SpiDrv::sendParam(&_dummy, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + SpiDrv::waitResponseCmd(GET_CURR_BSSID_CMD, PARAM_NUMS_1, _bssid, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return _bssid; +} + +int32_t WiFiDrv::getCurrentRSSI() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_CURR_RSSI_CMD, PARAM_NUMS_1); + + uint8_t _dummy = DUMMY_DATA; + SpiDrv::sendParam(&_dummy, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + int32_t rssi = 0; + SpiDrv::waitResponseCmd(GET_CURR_RSSI_CMD, PARAM_NUMS_1, (uint8_t*)&rssi, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + return rssi; +} + +uint8_t WiFiDrv::getCurrentEncryptionType() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_CURR_ENCT_CMD, PARAM_NUMS_1); + + uint8_t _dummy = DUMMY_DATA; + SpiDrv::sendParam(&_dummy, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t dataLen = 0; + uint8_t encType = 0; + SpiDrv::waitResponseCmd(GET_CURR_ENCT_CMD, PARAM_NUMS_1, (uint8_t*)&encType, &dataLen); + + SpiDrv::spiSlaveDeselect(); + + return encType; +} + +int8_t WiFiDrv::startScanNetworks() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(START_SCAN_NETWORKS, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + + if (!SpiDrv::waitResponseCmd(START_SCAN_NETWORKS, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + + SpiDrv::spiSlaveDeselect(); + + return ((int8_t)_data == WL_FAILURE)? _data : (int8_t)WL_SUCCESS; +} + + +uint8_t WiFiDrv::getScanNetworks() +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(SCAN_NETWORKS, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t ssidListNum = 0; + SpiDrv::waitResponse(SCAN_NETWORKS, &ssidListNum, (uint8_t**)_networkSsid, WL_NETWORKS_LIST_MAXNUM); + + SpiDrv::spiSlaveDeselect(); + + return ssidListNum; +} + +const char* WiFiDrv::getSSIDNetoworks(uint8_t networkItem) +{ + if (networkItem >= WL_NETWORKS_LIST_MAXNUM) + return (char*)NULL; + + return _networkSsid[networkItem]; +} + +uint8_t WiFiDrv::getEncTypeNetowrks(uint8_t networkItem) +{ + if (networkItem >= WL_NETWORKS_LIST_MAXNUM) + return ENC_TYPE_UNKNOWN; + + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_IDX_ENCT_CMD, PARAM_NUMS_1); + + SpiDrv::sendParam(&networkItem, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t dataLen = 0; + uint8_t encType = 0; + SpiDrv::waitResponseCmd(GET_IDX_ENCT_CMD, PARAM_NUMS_1, (uint8_t*)&encType, &dataLen); + + SpiDrv::spiSlaveDeselect(); + + return encType; +} + +uint8_t* WiFiDrv::getBSSIDNetowrks(uint8_t networkItem, uint8_t* bssid) +{ + if (networkItem >= WL_NETWORKS_LIST_MAXNUM) + return NULL; + + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_IDX_BSSID, PARAM_NUMS_1); + + SpiDrv::sendParam(&networkItem, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t dataLen = 0; + SpiDrv::waitResponseCmd(GET_IDX_BSSID, PARAM_NUMS_1, (uint8_t*)bssid, &dataLen); + + SpiDrv::spiSlaveDeselect(); + + return bssid; +} + +uint8_t WiFiDrv::getChannelNetowrks(uint8_t networkItem) +{ + if (networkItem >= WL_NETWORKS_LIST_MAXNUM) + return 0; + + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_IDX_CHANNEL_CMD, PARAM_NUMS_1); + + SpiDrv::sendParam(&networkItem, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t dataLen = 0; + uint8_t channel = 0; + SpiDrv::waitResponseCmd(GET_IDX_CHANNEL_CMD, PARAM_NUMS_1, (uint8_t*)&channel, &dataLen); + + SpiDrv::spiSlaveDeselect(); + + return channel; +} + +int32_t WiFiDrv::getRSSINetoworks(uint8_t networkItem) +{ + if (networkItem >= WL_NETWORKS_LIST_MAXNUM) + return 0; + int32_t networkRssi = 0; + + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(GET_IDX_RSSI_CMD, PARAM_NUMS_1); + + SpiDrv::sendParam(&networkItem, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t dataLen = 0; + SpiDrv::waitResponseCmd(GET_IDX_RSSI_CMD, PARAM_NUMS_1, (uint8_t*)&networkRssi, &dataLen); + + SpiDrv::spiSlaveDeselect(); + + return networkRssi; +} + +uint8_t WiFiDrv::reqHostByName(const char* aHostname) +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(REQ_HOST_BY_NAME_CMD, PARAM_NUMS_1); + SpiDrv::sendParam((uint8_t*)aHostname, strlen(aHostname), LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 5 + strlen(aHostname); + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + uint8_t result = SpiDrv::waitResponseCmd(REQ_HOST_BY_NAME_CMD, PARAM_NUMS_1, &_data, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + + if (result) { + result = (_data == 1); + } + + return result; +} + +int WiFiDrv::getHostByName(IPAddress& aResult) +{ + uint8_t _ipAddr[WL_IPV4_LENGTH]; + IPAddress dummy(0xFF,0xFF,0xFF,0xFF); + int result = 0; + + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_HOST_BY_NAME_CMD, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(GET_HOST_BY_NAME_CMD, PARAM_NUMS_1, _ipAddr, &_dataLen)) + { + WARN("error waitResponse"); + }else{ + aResult = _ipAddr; + result = (aResult != dummy); + } + SpiDrv::spiSlaveDeselect(); + return result; +} + +int WiFiDrv::getHostByName(const char* aHostname, IPAddress& aResult) +{ + if (reqHostByName(aHostname)) + { + return getHostByName(aResult); + }else{ + return 0; + } +} + +const char* WiFiDrv::getFwVersion() +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_FW_VERSION_CMD, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(GET_FW_VERSION_CMD, PARAM_NUMS_1, (uint8_t*)fwVersion, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + return fwVersion; +} + +uint32_t WiFiDrv::getTime() +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_TIME_CMD, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + uint32_t _data = 0; + if (!SpiDrv::waitResponseCmd(GET_TIME_CMD, PARAM_NUMS_1, (uint8_t*)&_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +void WiFiDrv::setPowerMode(uint8_t mode) +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(SET_POWER_MODE_CMD, PARAM_NUMS_1); + + SpiDrv::sendParam(&mode, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t dataLen = 0; + uint8_t data = 0; + SpiDrv::waitResponseCmd(SET_POWER_MODE_CMD, PARAM_NUMS_1, &data, &dataLen); + + SpiDrv::spiSlaveDeselect(); +} + +int8_t WiFiDrv::wifiSetApNetwork(const char* ssid, uint8_t ssid_len, uint8_t channel) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_AP_NET_CMD, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)ssid, ssid_len); + SpiDrv::sendParam(&channel, 1, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 3 + ssid_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_AP_NET_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + + return(_data == WIFI_SPI_ACK) ? WL_SUCCESS : WL_FAILURE; +} + +int8_t WiFiDrv::wifiSetApPassphrase(const char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len, uint8_t channel) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_AP_PASSPHRASE_CMD, PARAM_NUMS_3); + SpiDrv::sendParam((uint8_t*)ssid, ssid_len, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)passphrase, len, NO_LAST_PARAM); + SpiDrv::sendParam(&channel, 1, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 4 + ssid_len + len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_AP_PASSPHRASE_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +int8_t WiFiDrv::wifiSetEnterprise(uint8_t eapType, const char* ssid, uint8_t ssid_len, const char *username, const uint8_t username_len, const char *password, const uint8_t password_len, const char *identity, const uint8_t identity_len, const char* ca_cert, uint16_t ca_cert_len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_ENT_CMD, PARAM_NUMS_6); + SpiDrv::sendBuffer(&eapType, sizeof(eapType)); + SpiDrv::sendBuffer((uint8_t*)ssid, ssid_len); + SpiDrv::sendBuffer((uint8_t*)username, username_len); + SpiDrv::sendBuffer((uint8_t*)password, password_len); + SpiDrv::sendBuffer((uint8_t*)identity, identity_len); + SpiDrv::sendBuffer((uint8_t*)ca_cert, ca_cert_len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 15 + sizeof(eapType) + ssid_len + username_len + password_len + identity_len + ca_cert_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_ENT_CMD, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +int16_t WiFiDrv::ping(uint32_t ipAddress, uint8_t ttl) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(PING_CMD, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)&ipAddress, sizeof(ipAddress), NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&ttl, sizeof(ttl), LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint16_t _data; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(PING_CMD, PARAM_NUMS_1, (uint8_t*)&_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_PING_ERROR; + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +void WiFiDrv::debug(uint8_t on) +{ + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(SET_DEBUG_CMD, PARAM_NUMS_1); + + SpiDrv::sendParam(&on, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t dataLen = 0; + uint8_t data = 0; + SpiDrv::waitResponseCmd(SET_DEBUG_CMD, PARAM_NUMS_1, &data, &dataLen); + + SpiDrv::spiSlaveDeselect(); +} + +float WiFiDrv::getTemperature() +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(GET_TEMPERATURE_CMD, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _dataLen = 0; + float _data = 0; + if (!SpiDrv::waitResponseCmd(GET_TEMPERATURE_CMD, PARAM_NUMS_1, (uint8_t*)&_data, &_dataLen)) + { + WARN("error waitResponse"); + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +void WiFiDrv::pinMode(uint8_t pin, uint8_t mode) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_PIN_MODE, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)&pin, 1, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&mode, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_PIN_MODE, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +void WiFiDrv::digitalWrite(uint8_t pin, uint8_t value) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_DIGITAL_WRITE, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)&pin, 1, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&value, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_DIGITAL_WRITE, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +void WiFiDrv::analogWrite(uint8_t pin, uint8_t value) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(SET_ANALOG_WRITE, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)&pin, 1, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&value, 1, LAST_PARAM); + + // pad to multiple of 4 + SpiDrv::readChar(); + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(SET_ANALOG_WRITE, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); +} + +int8_t WiFiDrv::downloadFile(const char* url, uint8_t url_len, const char *filename, uint8_t filename_len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(DOWNLOAD_FILE, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)url, url_len, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)filename, filename_len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 6 + url_len + filename_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(DOWNLOAD_FILE, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +int8_t WiFiDrv::downloadOTA(const char* url, uint8_t url_len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + SpiDrv::sendCmd(DOWNLOAD_OTA, PARAM_NUMS_1); + SpiDrv::sendParam((uint8_t*)url, url_len, LAST_PARAM); + + // pad to multiple of 4 + int commandSize = 5 + url_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + if (!SpiDrv::waitResponseCmd(DOWNLOAD_OTA, PARAM_NUMS_1, &_data, &_dataLen)) + { + WARN("error waitResponse"); + _data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + return _data; +} + +int8_t WiFiDrv::renameFile(const char * old_file_name, uint8_t const old_file_name_len, const char * new_file_name, uint8_t const new_file_name_len) +{ + WAIT_FOR_SLAVE_SELECT(); + /* Send Command */ + SpiDrv::sendCmd(RENAME_FILE, PARAM_NUMS_2); + SpiDrv::sendParam((uint8_t*)old_file_name, old_file_name_len, NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)new_file_name, new_file_name_len, LAST_PARAM); + + /* pad to multiple of 4 */ + int commandSize = 6 + old_file_name_len + new_file_name_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + /* Wait the reply elaboration */ + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + /* Wait for reply */ + uint8_t data = 0; + uint8_t dataLen = 0; + if (!SpiDrv::waitResponseCmd(RENAME_FILE, PARAM_NUMS_1, &data, &dataLen)) + { + WARN("error waitResponse"); + data = WL_FAILURE; + } + SpiDrv::spiSlaveDeselect(); + return data; +} + +int8_t WiFiDrv::fileOperation(uint8_t operation, const char *filename, uint8_t filename_len, uint32_t offset, uint8_t* buffer, uint32_t len) +{ + WAIT_FOR_SLAVE_SELECT(); + // Send Command + uint8_t numParams = PARAM_NUMS_3; + if (operation == WRITE_FILE) { + numParams = PARAM_NUMS_4; + } + + SpiDrv::sendCmd(operation, numParams); + SpiDrv::sendParam((uint8_t*)&offset, sizeof(offset), NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)&len, sizeof(len), NO_LAST_PARAM); + SpiDrv::sendParam((uint8_t*)filename, filename_len, (operation == WRITE_FILE) ? NO_LAST_PARAM : LAST_PARAM); + if (operation == WRITE_FILE) { + SpiDrv::sendParamNoLen((uint8_t*)buffer, len, LAST_PARAM); + } + + // pad to multiple of 4 + int commandSize = 4 + numParams + sizeof(offset) + sizeof(len) + filename_len; + while (commandSize % 4) { + SpiDrv::readChar(); + commandSize++; + } + + SpiDrv::spiSlaveDeselect(); + //Wait the reply elaboration + SpiDrv::waitForSlaveReady(); + SpiDrv::spiSlaveSelect(); + + // Wait for reply + uint8_t _data = 0; + uint8_t _dataLen = 0; + SpiDrv::waitResponseCmd(operation, PARAM_NUMS_1, (operation == WRITE_FILE) ? &_data : buffer, &_dataLen); + + SpiDrv::spiSlaveDeselect(); + return _dataLen; +} + +void WiFiDrv::applyOTA() { + WAIT_FOR_SLAVE_SELECT(); + + // Send Command + SpiDrv::sendCmd(APPLY_OTA_COMMAND, PARAM_NUMS_0); + + SpiDrv::spiSlaveDeselect(); + + // don't wait for return; OTA operation should be fire and forget :) +} + + +WiFiDrv wiFiDrv; diff --git a/lib/WiFiNINA/src/utility/wifi_drv.h b/lib/WiFiNINA/src/utility/wifi_drv.h new file mode 100644 index 0000000..b641301 --- /dev/null +++ b/lib/WiFiNINA/src/utility/wifi_drv.h @@ -0,0 +1,326 @@ +/* + wifi_drv.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WiFi_Drv_h +#define WiFi_Drv_h + +#include +#include "utility/wifi_spi.h" +#include "IPAddress.h" +#include "WiFiUdp.h" +#include "WiFiClient.h" + +// Key index length +#define KEY_IDX_LEN 1 +// 100 msecs of delay to have the connection established +#define WL_DELAY_START_CONNECTION 100 +// firmware version string length +#define WL_FW_VER_LENGTH 6 + +class WiFiDrv +{ +private: + // settings of requested network + static char _networkSsid[WL_NETWORKS_LIST_MAXNUM][WL_SSID_MAX_LENGTH]; + + // firmware version string in the format a.b.c + static char fwVersion[WL_FW_VER_LENGTH]; + + // settings of current selected network + static char _ssid[WL_SSID_MAX_LENGTH]; + static uint8_t _bssid[WL_MAC_ADDR_LENGTH]; + static uint8_t _mac[WL_MAC_ADDR_LENGTH]; + static uint8_t _localIp[WL_IPV4_LENGTH]; + static uint8_t _subnetMask[WL_IPV4_LENGTH]; + static uint8_t _gatewayIp[WL_IPV4_LENGTH]; + + /* + * Get network Data information + */ + static void getNetworkData(uint8_t *ip, uint8_t *mask, uint8_t *gwip); + + static uint8_t reqHostByName(const char* aHostname); + + static int getHostByName(IPAddress& aResult); + + /* + * Get remote Data information on UDP socket + */ + static void getRemoteData(uint8_t sock, uint8_t *ip, uint8_t *port); + +public: + + /* + * Driver initialization + */ + static void wifiDriverInit(); + + static void wifiDriverDeinit(); + + /* + * Set the desired network which the connection manager should try to + * connect to. + * + * The ssid of the desired network should be specified. + * + * param ssid: The ssid of the desired network. + * param ssid_len: Length of ssid string. + * return: WL_SUCCESS or WL_FAILURE + */ + static int8_t wifiSetNetwork(const char* ssid, uint8_t ssid_len); + + /* Start WiFi connection with passphrase + * the most secure supported mode will be automatically selected + * + * param ssid: Pointer to the SSID string. + * param ssid_len: Length of ssid string. + * param passphrase: Passphrase. Valid characters in a passphrase + * must be between ASCII 32-126 (decimal). + * param len: Length of passphrase string. + * return: WL_SUCCESS or WL_FAILURE + */ + static int8_t wifiSetPassphrase(const char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len); + + /* Start WiFi connection with WEP encryption. + * Configure a key into the device. The key type (WEP-40, WEP-104) + * is determined by the size of the key (5 bytes for WEP-40, 13 bytes for WEP-104). + * + * param ssid: Pointer to the SSID string. + * param ssid_len: Length of ssid string. + * param key_idx: The key index to set. Valid values are 0-3. + * param key: Key input buffer. + * param len: Length of key string. + * return: WL_SUCCESS or WL_FAILURE + */ + static int8_t wifiSetKey(const char* ssid, uint8_t ssid_len, uint8_t key_idx, const void *key, const uint8_t len); + + static int8_t wifiSetApNetwork(const char* ssid, uint8_t ssid_len); + static int8_t wifiSetApPassphrase(const char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len); + + /* Set ip configuration disabling dhcp client + * + * param validParams: set the number of parameters that we want to change + * i.e. validParams = 1 means that we'll change only ip address + * validParams = 3 means that we'll change ip address, gateway and netmask + * param local_ip: Static ip configuration + * param gateway: Static gateway configuration + * param subnet: Static subnet mask configuration + */ + static void config(uint8_t validParams, uint32_t local_ip, uint32_t gateway, uint32_t subnet); + + /* Set DNS ip configuration + * + * param validParams: set the number of parameters that we want to change + * i.e. validParams = 1 means that we'll change only dns_server1 + * validParams = 2 means that we'll change dns_server1 and dns_server2 + * param dns_server1: Static DNS server1 configuration + * param dns_server2: Static DNS server2 configuration + */ + static void setDNS(uint8_t validParams, uint32_t dns_server1, uint32_t dns_server2); + + static void setHostname(const char* hostname); + + /* + * Disconnect from the network + * + * return: WL_SUCCESS or WL_FAILURE + */ + static int8_t disconnect(); + + static uint8_t getReasonCode(); + + /* + * Disconnect from the network + * + * return: one value of wl_status_t enum + */ + static uint8_t getConnectionStatus(); + + /* + * Get the interface MAC address. + * + * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + */ + static uint8_t* getMacAddress(); + + /* + * Get the interface IP address. + * + * return: copy the ip address value in IPAddress object + */ + static void getIpAddress(IPAddress& ip); + + /* + * Get the interface subnet mask address. + * + * return: copy the subnet mask address value in IPAddress object + */ + static void getSubnetMask(IPAddress& mask); + + /* + * Get the gateway ip address. + * + * return: copy the gateway ip address value in IPAddress object + */ + static void getGatewayIP(IPAddress& ip); + + /* + * Return the current SSID associated with the network + * + * return: ssid string + */ + static const char* getCurrentSSID(); + + /* + * Return the current BSSID associated with the network. + * It is the MAC address of the Access Point + * + * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH + */ + static uint8_t* getCurrentBSSID(); + + /* + * Return the current RSSI /Received Signal Strength in dBm) + * associated with the network + * + * return: signed value + */ + static int32_t getCurrentRSSI(); + + /* + * Return the Encryption Type associated with the network + * + * return: one value of wl_enc_type enum + */ + static uint8_t getCurrentEncryptionType(); + + /* + * Start scan WiFi networks available + * + * return: Number of discovered networks + */ + static int8_t startScanNetworks(); + + /* + * Get the networks available + * + * return: Number of discovered networks + */ + static uint8_t getScanNetworks(); + + /* + * Return the SSID discovered during the network scan. + * + * param networkItem: specify from which network item want to get the information + * + * return: ssid string of the specified item on the networks scanned list + */ + static const char* getSSIDNetoworks(uint8_t networkItem); + + /* + * Return the RSSI of the networks discovered during the scanNetworks + * + * param networkItem: specify from which network item want to get the information + * + * return: signed value of RSSI of the specified item on the networks scanned list + */ + static int32_t getRSSINetoworks(uint8_t networkItem); + + /* + * Return the encryption type of the networks discovered during the scanNetworks + * + * param networkItem: specify from which network item want to get the information + * + * return: encryption type (enum wl_enc_type) of the specified item on the networks scanned list + */ + static uint8_t getEncTypeNetowrks(uint8_t networkItem); + + static uint8_t* getBSSIDNetowrks(uint8_t networkItem, uint8_t* bssid); + + static uint8_t getChannelNetowrks(uint8_t networkItem); + + /* + * Resolve the given hostname to an IP address. + * param aHostname: Name to be resolved + * param aResult: IPAddress structure to store the returned IP address + * result: 1 if aIPAddrString was successfully converted to an IP address, + * else error code + */ + static int getHostByName(const char* aHostname, IPAddress& aResult); + + /* + * Get the firmware version + * result: version as string with this format a.b.c + */ + static const char* getFwVersion(); + + static uint32_t getTime(); + + static void setPowerMode(uint8_t mode); + + static int8_t wifiSetApNetwork(const char* ssid, uint8_t ssid_len, uint8_t channel); + static int8_t wifiSetApPassphrase(const char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len, uint8_t channel); + static int8_t wifiSetEnterprise(uint8_t eapType, + const char* ssid, uint8_t ssid_len, + const char *username, const uint8_t username_len, + const char *password, const uint8_t password_len, + const char *identity, const uint8_t identity_len, + const char* ca_cert, uint16_t ca_cert_len); + + + static int16_t ping(uint32_t ipAddress, uint8_t ttl); + + static void debug(uint8_t on); + static float getTemperature(); + static void pinMode(uint8_t pin, uint8_t mode); + static void digitalWrite(uint8_t pin, uint8_t value); + static void analogWrite(uint8_t pin, uint8_t value); + + static int8_t downloadFile(const char* url, uint8_t url_len, const char *filename, uint8_t filename_len); + static int8_t downloadOTA(const char* url, uint8_t url_len); + static int8_t renameFile(const char * old_file_name, uint8_t const old_file_name_len, const char * new_file_name, uint8_t const new_file_name_len); + + static int8_t fileOperation(uint8_t operation, const char *filename, uint8_t filename_len, uint32_t offset, uint8_t* buffer, uint32_t len); + + static int8_t readFile(const char *filename, uint8_t filename_len, uint32_t offset, uint8_t* buffer, uint32_t buffer_len) { + return fileOperation(READ_FILE, filename, filename_len, offset, buffer, buffer_len); + }; + static int8_t writeFile(const char *filename, uint8_t filename_len, uint32_t offset, uint8_t* buffer, uint32_t buffer_len) { + return fileOperation(WRITE_FILE, filename, filename_len, offset, buffer, buffer_len); + }; + static int8_t deleteFile(const char *filename, uint8_t filename_len) { + return fileOperation(DELETE_FILE, filename, filename_len, 0, NULL, 0); + }; + static int8_t existsFile(const char *filename, uint8_t filename_len, uint32_t* len) { + int32_t length = 0; + fileOperation(EXISTS_FILE, filename, filename_len, 0, (uint8_t*)&length, sizeof(length)); + *len = length; + return length >= 0; + }; + + static void applyOTA(); + + friend class WiFiUDP; + friend class WiFiClient; +}; + +extern WiFiDrv wiFiDrv; + +#endif diff --git a/lib/WiFiNINA/src/utility/wifi_spi.h b/lib/WiFiNINA/src/utility/wifi_spi.h new file mode 100644 index 0000000..0dc4681 --- /dev/null +++ b/lib/WiFiNINA/src/utility/wifi_spi.h @@ -0,0 +1,203 @@ +/* + wifi_spi.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef WiFi_Spi_h +#define WiFi_Spi_h + +#include +#include "utility/wl_definitions.h" + +#define CMD_FLAG 0 +#define REPLY_FLAG 1<<7 +#define DATA_FLAG 0x40 + +#define WIFI_SPI_ACK 1 +#define WIFI_SPI_ERR 0xFF + +#define TIMEOUT_CHAR 1000 + +//#define MAX_SOCK_NUM 4 /**< Maxmium number of socket */ +#define NO_SOCKET_AVAIL 255 + +#define START_CMD 0xE0 +#define END_CMD 0xEE +#define ERR_CMD 0xEF +#define CMD_POS 1 // Position of Command OpCode on SPI stream +#define PARAM_LEN_POS 2 // Position of Param len on SPI stream + + +enum { + SET_NET_CMD = 0x10, + SET_PASSPHRASE_CMD = 0x11, + SET_KEY_CMD = 0x12, +// TEST_CMD = 0x13, + SET_IP_CONFIG_CMD = 0x14, + SET_DNS_CONFIG_CMD = 0x15, + SET_HOSTNAME_CMD = 0x16, + SET_POWER_MODE_CMD = 0x17, + SET_AP_NET_CMD = 0x18, + SET_AP_PASSPHRASE_CMD = 0x19, + SET_DEBUG_CMD = 0x1A, + GET_TEMPERATURE_CMD = 0x1B, + GET_REASON_CODE_CMD = 0x1F, + + GET_CONN_STATUS_CMD = 0x20, + GET_IPADDR_CMD = 0x21, + GET_MACADDR_CMD = 0x22, + GET_CURR_SSID_CMD = 0x23, + GET_CURR_BSSID_CMD = 0x24, + GET_CURR_RSSI_CMD = 0x25, + GET_CURR_ENCT_CMD = 0x26, + SCAN_NETWORKS = 0x27, + START_SERVER_TCP_CMD= 0x28, + GET_STATE_TCP_CMD = 0x29, + DATA_SENT_TCP_CMD = 0x2A, + AVAIL_DATA_TCP_CMD = 0x2B, + GET_DATA_TCP_CMD = 0x2C, + START_CLIENT_TCP_CMD= 0x2D, + STOP_CLIENT_TCP_CMD = 0x2E, + GET_CLIENT_STATE_TCP_CMD= 0x2F, + DISCONNECT_CMD = 0x30, +// GET_IDX_SSID_CMD = 0x31, + GET_IDX_RSSI_CMD = 0x32, + GET_IDX_ENCT_CMD = 0x33, + REQ_HOST_BY_NAME_CMD= 0x34, + GET_HOST_BY_NAME_CMD= 0x35, + START_SCAN_NETWORKS = 0x36, + GET_FW_VERSION_CMD = 0x37, +// GET_TEST_CMD = 0x38, + SEND_DATA_UDP_CMD = 0x39, + GET_REMOTE_DATA_CMD = 0x3A, + GET_TIME_CMD = 0x3B, + GET_IDX_BSSID = 0x3C, + GET_IDX_CHANNEL_CMD = 0x3D, + PING_CMD = 0x3E, + GET_SOCKET_CMD = 0x3F, + + // All command with DATA_FLAG 0x40 send a 16bit Len + SET_ENT_CMD = 0x40, + + SEND_DATA_TCP_CMD = 0x44, + GET_DATABUF_TCP_CMD = 0x45, + INSERT_DATABUF_CMD = 0x46, + + // regular format commands + SET_PIN_MODE = 0x50, + SET_DIGITAL_WRITE = 0x51, + SET_ANALOG_WRITE = 0x52, + + // regular format commands + WRITE_FILE = 0x60, + READ_FILE = 0x61, + DELETE_FILE = 0x62, + EXISTS_FILE = 0x63, + DOWNLOAD_FILE = 0x64, + APPLY_OTA_COMMAND = 0x65, + RENAME_FILE = 0x66, + DOWNLOAD_OTA = 0x67, +}; + + +enum wl_tcp_state { + CLOSED = 0, + LISTEN = 1, + SYN_SENT = 2, + SYN_RCVD = 3, + ESTABLISHED = 4, + FIN_WAIT_1 = 5, + FIN_WAIT_2 = 6, + CLOSE_WAIT = 7, + CLOSING = 8, + LAST_ACK = 9, + TIME_WAIT = 10 +}; + + +enum numParams{ + PARAM_NUMS_0, + PARAM_NUMS_1, + PARAM_NUMS_2, + PARAM_NUMS_3, + PARAM_NUMS_4, + PARAM_NUMS_5, + PARAM_NUMS_6, + MAX_PARAM_NUMS +}; + +#define MAX_PARAMS MAX_PARAM_NUMS-1 +#define PARAM_LEN_SIZE 1 + +typedef struct __attribute__((__packed__)) +{ + uint8_t paramLen; + char* param; +}tParam; + +typedef struct __attribute__((__packed__)) +{ + uint16_t dataLen; + char* data; +}tDataParam; + + +typedef struct __attribute__((__packed__)) +{ + unsigned char cmd; + unsigned char tcmd; + unsigned char nParam; + tParam params[MAX_PARAMS]; +}tSpiMsg; + +typedef struct __attribute__((__packed__)) +{ + unsigned char cmd; + unsigned char tcmd; + unsigned char nParam; + tDataParam params[MAX_PARAMS]; +}tSpiMsgData; + + +typedef struct __attribute__((__packed__)) +{ + unsigned char cmd; + unsigned char tcmd; + //unsigned char totLen; + unsigned char nParam; +}tSpiHdr; + +typedef struct __attribute__((__packed__)) +{ + uint8_t paramLen; + uint32_t param; +}tLongParam; + +typedef struct __attribute__((__packed__)) +{ + uint8_t paramLen; + uint16_t param; +}tIntParam; + +typedef struct __attribute__((__packed__)) +{ + uint8_t paramLen; + uint8_t param; +}tByteParam; + +#endif diff --git a/lib/WiFiNINA/src/utility/wl_definitions.h b/lib/WiFiNINA/src/utility/wl_definitions.h new file mode 100644 index 0000000..dc14045 --- /dev/null +++ b/lib/WiFiNINA/src/utility/wl_definitions.h @@ -0,0 +1,77 @@ +/* + wl_definitions.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/* + * wl_definitions.h + * + * Created on: Mar 6, 2011 + * Author: dlafauci + */ + +#ifndef WL_DEFINITIONS_H_ +#define WL_DEFINITIONS_H_ + +// Maximum size of a SSID +#define WL_SSID_MAX_LENGTH 32 +// Length of passphrase. Valid lengths are 8-63. +#define WL_WPA_KEY_MAX_LENGTH 63 +// Length of key in bytes. Valid values are 5 and 13. +#define WL_WEP_KEY_MAX_LENGTH 13 +// Size of a MAC-address or BSSID +#define WL_MAC_ADDR_LENGTH 6 +// Size of a MAC-address or BSSID +#define WL_IPV4_LENGTH 4 +// Maximum size of a SSID list +#define WL_NETWORKS_LIST_MAXNUM 10 +// Maxmium number of socket +#define WIFI_MAX_SOCK_NUM 10 +// Socket not available constant +#define SOCK_NOT_AVAIL 255 +// Default state value for WiFi state field +#define NA_STATE -1 + +typedef enum { + WL_NO_SHIELD = 255, + WL_NO_MODULE = WL_NO_SHIELD, + WL_IDLE_STATUS = 0, + WL_NO_SSID_AVAIL, + WL_SCAN_COMPLETED, + WL_CONNECTED, + WL_CONNECT_FAILED, + WL_CONNECTION_LOST, + WL_DISCONNECTED, + WL_AP_LISTENING, + WL_AP_CONNECTED, + WL_AP_FAILED +} wl_status_t; + +/* Encryption modes */ +enum wl_enc_type { /* Values map to 802.11 encryption suites... */ + ENC_TYPE_WEP = 5, + ENC_TYPE_TKIP = 2, + ENC_TYPE_CCMP = 4, + /* ... except these two, 7 and 8 are reserved in 802.11-2007 */ + ENC_TYPE_NONE = 7, + ENC_TYPE_AUTO = 8, + + ENC_TYPE_UNKNOWN = 255 +}; + + +#endif /* WL_DEFINITIONS_H_ */ diff --git a/lib/WiFiNINA/src/utility/wl_types.h b/lib/WiFiNINA/src/utility/wl_types.h new file mode 100644 index 0000000..e1be74d --- /dev/null +++ b/lib/WiFiNINA/src/utility/wl_types.h @@ -0,0 +1,57 @@ +/* + wl_types.h - Library for Arduino Wifi shield. + Copyright (c) 2018 Arduino SA. All rights reserved. + Copyright (c) 2011-2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +/* + * wl_types.h + * + * Created on: Jul 30, 2010 + * Author: dlafauci + */ + + +#ifndef _WL_TYPES_H_ +#define _WL_TYPES_H_ + +#include + +typedef enum { + WL_FAILURE = -1, + WL_SUCCESS = 1, +} wl_error_code_t; + +/* Authentication modes */ +enum wl_auth_mode { + AUTH_MODE_INVALID, + AUTH_MODE_AUTO, + AUTH_MODE_OPEN_SYSTEM, + AUTH_MODE_SHARED_KEY, + AUTH_MODE_WPA, + AUTH_MODE_WPA2, + AUTH_MODE_WPA_PSK, + AUTH_MODE_WPA2_PSK +}; + +typedef enum { + WL_PING_DEST_UNREACHABLE = -1, + WL_PING_TIMEOUT = -2, + WL_PING_UNKNOWN_HOST = -3, + WL_PING_ERROR = -4 +} wl_ping_result_t; + +#endif //_WL_TYPES_H_ diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..6451896 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,19 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:megaatmega2560] +platform = atmelavr +board = megaatmega2560 +framework = arduino +monitor_speed = 115200 +lib_deps = + arduino-libraries/Servo@^1.1.8 + arduino-libraries/Ethernet@^2.0.1 + openenergymonitor/EmonLib@^1.1.0 diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..55aa177 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,405 @@ +//****************************************************************************************** +// File: ST_Anything_Multiples_EthernetW5x00_MEGA.ino +// Authors: Dan G Ogorchock & Daniel J Ogorchock (Father and Son) +// +// Summary: This Arduino Sketch, along with the ST_Anything library and the +// revised SmartThings +// library, demonstrates the ability of one Arduino + Ethernet W5x00 +// Shield to implement a multi input/output custom device for +// integration into SmartThings. The ST_Anything library takes care +// of all of the work to schedule device updates as well as all +// communications with the Ethernet W5x00 Shield. +// +// ST_Anything_Multiples implements the following ST Capabilities in +// multiples of 2 as a demo of what is possible with a single Arduino +// - 2 x Door Control devices (used typically for Garage Doors - +// input pin (contact sensor) and output pin (relay switch) +// - 2 x Contact Sensor devices (used to monitor magnetic door +// sensors) +// - 2 x Switch devices (used to turn on a digital output (e.g. +// LED, relay, etc...) +// - 2 x Water Sensor devices (using an analog input pin to measure +// voltage from a water detector board) +// - 2 x Illuminance Measurement devices (using a photoresitor +// attached to ananlog input) +// - 2 x Voltage Measurement devices (using a photoresitor attached +// to ananlog input) +// - 2 x Smoke Detector devices (using simple digital input) +// - 2 x Carbon Monoxide Detector devices (using simple digital +// input) +// - 2 x Motion devices (used to detect motion) +// - 2 x Temperature Measurement devices (Temperature from DHT22 +// device) +// - 2 x Humidity Measurement devices (Humidity from DHT22 device) +// - 2 x Relay Switch devices (used to turn on a digital output for +// a set number of cycles And On/Off times (e.g.relay, etc...)) +// - 2 x Button devices (sends "pushed" if held for less than 1 +// second, else sends "held" +// - 2 x Alarm devices - 1 siren only, 1 siren and strobe (using +// simple digital outputs) +// - 2 x Dimmer Switch devices - uses 2 digital outputs, one for +// on/off and one for pwm level +// - 2 x MQ-2 Smoke Detector devices (using simple analog input +// compared to user defined limit) +// +// During the development of this re-usable library, it became +// apparent that the Arduino UNO R3's very limited 2K of SRAM was +// very limiting in the number of devices that could be implemented +// simultaneously. A tremendous amount of effort has gone into +// reducing the SRAM usage, including siginificant improvements to +// the SmartThings Arduino library. +// +// Note: This sketch was fully tested on an Arduino MEGA 2560 using +// the Ethernet W5x00 Shield. +// +// Change History: +// +// Date Who What +// ---- --- ---- +// 2015-01-03 Dan & Daniel Original Creation +// 2017-02-12 Dan Ogorchock Revised to use the new SMartThings v2.0 library +// 2017-04-16 Dan Ogorchock New sketch to demonstrate multiple SmartThings +// Capabilties of each type 2017-04-22 Dan Ogorchock Added Voltage, Carbon +// Monoxide, and Alarm with Strobe 2017-07-04 Dan Ogorchock Added MQ-2 +// based Smoke Detection +// +//****************************************************************************************** +//****************************************************************************************** +// SmartThings Library for Arduino Ethernet W5x00 Shield +//****************************************************************************************** +#include //Library to provide API to the SmartThings Ethernet W5x00 Shield + +//****************************************************************************************** +// ST_Anything Library +//****************************************************************************************** +#include //Constants.h is designed to be modified by the end user to adjust behavior of the ST_Anything library +#include //Generic Device Class, inherited by Sensor and Executor classes +#include //Master Brain of ST_Anything library that ties everything together and performs ST Shield communications +#include //Generic Executor Class, typically receives data from ST Cloud (e.g. Switch) +#include //Generic Interrupt "Sensor" Class, waits for change of state on digital input +#include //Generic Polling "Sensor" Class, polls Arduino pins periodically +#include //Generic Sensor Class, typically provides data to ST Cloud (e.g. Temperature, Motion, etc...) + +#include //Implements Executor (EX)as an Alarm capability with Siren and Strobe via digital outputs to relays +#include //Implements an Executor (EX) via a digital output to a relay +#include //Implements an Executor (EX) for a switch (on/off) and pwm output (level) uses 2 digital output pins +#include //Implements an Interrupt Sensor (IS) to monitor the status of a digital input pin for button presses +#include //Implements an Interrupt Sensor (IS) to monitor the status of a digital input pin +#include //Implements an Interrupt Sensor (IS) to monitor the status of a digital input pin +#include //Implements an Interrupt Sensor (IS) and Executor to monitor the status of a digital input pin and control a digital output pin +#include //Implements an Interrupt Sensor (IS) to detect motion via a PIR sensor on a digital input pin +#include //Implements an Interrupt Sensor (IS) to monitor the status of a digital input pin +#include //Implements a Polling Sensor (PS) to measure light levels via a photo resistor on an analog input pin +#include //Implements an Polling Sensor (PS) to monitor the status of an analog input pin from a MQ2 sensor +#include //Implements a Polling Sensor (PS) to measure Temperature and Humidity via DHT library +#include //Implements a Polling Sensor (PS) to measure voltage on an analog input pin +#include //Implements a Polling Sensor (PS) to measure presence of water (i.e. leak detector) on an analog input pin +#include //Implements a Sensor to control a digital output pin with timing/cycle repeat capabilities + +//********************************************************************************************************** +// Define which Arduino Pins will be used for each device +// Notes: Arduino communicates with both the W5x00 and SD card using the SPI +// bus (through the ICSP header). +// This is on digital pins 10, 11, 12, and 13 on the Uno and pins 50, +// 51, and 52 on the Mega. On both boards, pin 10 is used to select the +// W5x00 and pin 4 for the SD card. These pins cannot be used for +// general I/O. On the Mega, the hardware SS pin, 53, is not used to +// select either the W5x00 or the SD card, but it must be kept as an +// output or the SPI interface won't work. See +// https://www.arduino.cc/en/Main/ArduinoEthernetShieldV1 for details on +// the W5x00 Sield +//********************************************************************************************************** +//"RESERVED" pins for W5x00 Ethernet Shield - best to avoid +#define PIN_4_RESERVED 4 // reserved by W5x00 Shield on both UNO and MEGA +#define PIN_1O_RESERVED 10 // reserved by W5x00 Shield on both UNO and MEGA +#define PIN_11_RESERVED 11 // reserved by W5x00 Shield on UNO +#define PIN_12_RESERVED 12 // reserved by W5x00 Shield on UNO +#define PIN_13_RESERVED 13 // reserved by W5x00 Shield on UNO +#define PIN_50_RESERVED 50 // reserved by W5x00 Shield on MEGA +#define PIN_51_RESERVED 51 // reserved by W5x00 Shield on MEGA +#define PIN_52_RESERVED 52 // reserved by W5x00 Shield on MEGA +#define PIN_53_RESERVED 53 // reserved by W5x00 Shield on MEGA + +// Analog Pins +#define PIN_WATER_1 A0 // SmartThings Capability "Water Sensor" +#define PIN_WATER_2 A1 // SmartThings Capability "Water Sensor" +#define PIN_ILLUMINANCE_1 A2 // SmartThings Capability "Illuminance Measurement" +#define PIN_ILLUMINANCE_2 A3 // SmartThings Capability "Illuminance Measurement" +#define PIN_VOLTAGE_1 A4 // SmartThings Capability "Voltage Measurement" +#define PIN_VOLTAGE_2 A5 // SmartThings Capability "Voltage Measurement" +#define PIN_SMOKE_3 A8 // SmartThings Capability "Smoke Detector" +#define PIN_SMOKE_4 A9 // SmartThings Capability "Smoke Detector" + +// Digital Pins +#define PIN_TEMPERATUREHUMIDITY_1 \ + 22 // SmartThings Capabilities "Temperature Measurement" and "Relative + // Humidity Measurement" +#define PIN_TEMPERATUREHUMIDITY_2 \ + 23 // SmartThings Capabilities "Temperature Measurement" and "Relative + // Humidity Measurement" +#define PIN_MOTION_1 24 // SmartThings Capability "Motion Sensor" +#define PIN_MOTION_2 25 // SmartThings Capability "Motion Sensor" +#define PIN_CONTACT_1 26 // SmartThings Capability "Contact Sensor" +#define PIN_CONTACT_2 27 // SmartThings Capability "Contact Sensor" +#define PIN_SWITCH_1 28 // SmartThings Capability "Switch" +#define PIN_SWITCH_2 29 // SmartThings Capability "Switch" +#define PIN_TIMEDRELAY_1 30 // SmartThings Capability "Relay Switch" +#define PIN_TIMEDRELAY_2 31 // SmartThings Capability "Relay Switch" +#define PIN_SMOKE_1 32 // SmartThings Capability "Smoke Detector" +#define PIN_SMOKE_2 33 // SmartThings Capability "Smoke Detector" +#define PIN_ALARM_1 34 // SmartThings Capability "Alarm" +#define PIN_ALARM_2 40 // SmartThings Capability "Alarm" +#define PIN_STROBE_2 41 // SmartThings Capability "Alarm" +#define PIN_CO_1 42 // SmartThings Capability "Carbon Monoxide Detector" +#define PIN_CO_2 43 // SmartThings Capability "Carbon Monoxide Detector" + +// Dimmer Switch Pins +#define PIN_DIMMERLEVEL_1 \ + 44 // SmartThings Capability "Switch Level" NOTE: MUST BE A PWM CAPABLE PIN! +#define PIN_DIMMERSWITCH_1 45 // SmartThings Capability "Switch" +#define PIN_DIMMERLEVEL_2 \ + 46 // SmartThings Capability "Switch Level" NOTE: MUST BE A PWM CAPABLE PIN! +#define PIN_DIMMERSWITCH_2 47 // SmartThings Capability "Switch" + +// Garage Door Pins +#define PIN_DOORCONTROL_CONTACT_1 35 // SmartThings Capabilty "Door Control" +#define PIN_DOORCONTROL_RELAY_1 36 // SmartThings Capabilty "Door Control" +#define PIN_DOORCONTROL_CONTACT_2 37 // SmartThings Capabilty "Door Control" +#define PIN_DOORCONTROL_RELAY_2 38 // SmartThings Capabilty "Door Control" + +// Pushbutton Pins +#define PIN_BUTTON1 48 // SmartThings Capabilty Button / Holdable Button +#define PIN_BUTTON2 49 // SmartThings Capabilty Button / Holdable Button + +//****************************************************************************************** +// W5x00 Ethernet Shield Information +//****************************************************************************************** + +// NOTE - If your shield came with a MAC address sticker - please use that MAC +// address! + +// MAC address, leave first octet 0x06, change others to be unique +byte mac[] = {0x06, 0x02, 0x03, 0x04, 0x05, 0x06}; + +// Arduino device IP Address +IPAddress ip(10, 10, 0, 99); + +// Router gateway +IPAddress gateway(10, 10, 0, 1); + +// LAN subnet mask +IPAddress subnet(255, 255, 255, 0); + +// DNS server +IPAddress dnsserver(10, 10, 0, 1); + +// port to run the http server on +const unsigned int serverPort = 8090; + +// Smartthings Hub Information +// IPAddress hubIp(192, 168, 1, 149); // smartthings hub ip // <---You +// must edit this line! const unsigned int hubPort = 39500; // smartthings hub +// port + +// Hubitat Hub Information + +// hubitat hub ip +IPAddress hubIp(192, 168, 88, 251); + +// hubitat hub port +const unsigned int hubPort = 39501; + +//****************************************************************************************** +// st::Everything::callOnMsgSend() optional callback routine. This is a sniffer +// to monitor +// data being sent to ST. This allows a user to act on data changes locally +// within the Arduino sktech withotu having to rely on the ST Cloud for +// time-critical tasks. +//****************************************************************************************** +void callback(const String &msg) { + // Uncomment if it weould be desirable to using this function + // Serial.print(F("ST_Anything_Miltiples Callback: Sniffed data = ")); + // Serial.println(msg); + + // TODO: Add local logic here to take action when a device's value/state is + // changed + + // Masquerade as the ThingShield to send data to the Arduino, as if from the + // ST Cloud (uncomment and edit following line(s) as you see fit) + // st::receiveSmartString("Put your command here!"); //use same strings that + // the Device Handler would send +} + +//****************************************************************************************** +// Arduino Setup() routine +//****************************************************************************************** +void setup() { + //****************************************************************************************** + // Declare each Device that is attached to the Arduino + // Notes: - For each device, there is typically a corresponding "tile" + // defined in your + // SmartThings Device Hanlder Groovy code, except when using new + // COMPOSITE Device Handler + // - For details on each device's constructor arguments below, please + // refer to the + // corresponding header (.h) and program (.cpp) files. + // - The name assigned to each device (1st argument below) must match + // the Groovy + // Device Handler names. (Note: "temphumid" below is the exception + // to this rule as the DHT sensors produce both "temperature" and + // "humidity". Data from that particular sensor is sent to the ST + // Hub in two separate updates, one for "temperature" and one for + // "humidity") + // - The new Composite Device Handler is comprised of a Parent DH and + // various Child + // DH's. The names used below MUST not be changed for the Automatic + // Creation of child devices to work properly. Simply increment the + // number by +1 for each duplicate device (e.g. contact1, contact2, + // contact3, etc...) You can rename the Child Devices to match your + // specific use case in the ST Phone Application. + //****************************************************************************************** + // Polling Sensors + static st::PS_Water sensor1(F("water1"), 60, 0, PIN_WATER_1, 200); + static st::PS_Water sensor2(F("water2"), 60, 10, PIN_WATER_2, 200); + static st::PS_Illuminance sensor3(F("illuminance1"), 60, 20, + PIN_ILLUMINANCE_1, 0, 1023, 0, 1000); + static st::PS_Illuminance sensor4(F("illuminance2"), 60, 30, + PIN_ILLUMINANCE_2, 0, 1023, 0, 1000); + static st::PS_TemperatureHumidity sensor5( + F("temphumid1"), 60, 40, PIN_TEMPERATUREHUMIDITY_1, + st::PS_TemperatureHumidity::DHT22, "temperature1", "humidity1"); + static st::PS_TemperatureHumidity sensor6( + F("temphumid2"), 60, 50, PIN_TEMPERATUREHUMIDITY_2, + st::PS_TemperatureHumidity::DHT22, "temperature2", "humidity2"); + static st::PS_Voltage sensor7(F("voltage1"), 60, 55, PIN_VOLTAGE_1, 0, 1023, + 0, 5000); + static st::PS_Voltage sensor8(F("voltage2"), 60, 57, PIN_VOLTAGE_2, 0, 1023, + 0, 5000); + static st::PS_MQ2_Smoke sensor23(F("smoke3"), 10, 3, PIN_SMOKE_3, 300); + static st::PS_MQ2_Smoke sensor24(F("smoke4"), 10, 5, PIN_SMOKE_4, 300); + + // Interrupt Sensors + static st::IS_Motion sensor9(F("motion1"), PIN_MOTION_1, HIGH, false, 500); + static st::IS_Motion sensor10(F("motion2"), PIN_MOTION_2, HIGH, false, 500); + static st::IS_Contact sensor11(F("contact1"), PIN_CONTACT_1, LOW, true, 500); + static st::IS_Contact sensor12(F("contact2"), PIN_CONTACT_2, LOW, true, 500); + static st::IS_Smoke sensor13(F("smoke1"), PIN_SMOKE_1, HIGH, true, 500); + static st::IS_Smoke sensor14(F("smoke2"), PIN_SMOKE_2, HIGH, true, 500); + static st::IS_DoorControl sensor15(F("doorControl1"), + PIN_DOORCONTROL_CONTACT_1, LOW, true, + PIN_DOORCONTROL_RELAY_1, LOW, true, 1000); + static st::IS_DoorControl sensor16(F("doorControl2"), + PIN_DOORCONTROL_CONTACT_2, LOW, true, + PIN_DOORCONTROL_RELAY_2, LOW, true, 1000); + static st::IS_Button sensor17(F("button1"), PIN_BUTTON1, 1000, LOW, true, + 500); + static st::IS_Button sensor18(F("button2"), PIN_BUTTON2, 1000, LOW, true, + 500); + static st::IS_CarbonMonoxide sensor19(F("carbonMonoxide1"), PIN_CO_1, HIGH, + true, 500); + static st::IS_CarbonMonoxide sensor20(F("carbonMonoxide2"), PIN_CO_2, HIGH, + true, 500); + + // Special sensors/executors (uses portions of both polling and executor + // classes) + static st::S_TimedRelay sensor21(F("relaySwitch1"), PIN_TIMEDRELAY_1, LOW, + true, 3000, 0, 1); + static st::S_TimedRelay sensor22(F("relaySwitch2"), PIN_TIMEDRELAY_2, LOW, + true, 3000, 0, 1); + + // Executors + static st::EX_Switch executor1(F("switch1"), PIN_SWITCH_1, LOW, true); + static st::EX_Switch executor2(F("switch2"), PIN_SWITCH_2, LOW, true); + static st::EX_Alarm executor3(F("alarm1"), PIN_ALARM_1, LOW, true); + static st::EX_Alarm executor4(F("alarm2"), PIN_ALARM_2, LOW, true, + PIN_STROBE_2); + static st::EX_Switch_Dim executor5(F("dimmerSwitch1"), PIN_DIMMERSWITCH_1, + PIN_DIMMERLEVEL_1, LOW, false); + static st::EX_Switch_Dim executor6(F("dimmerSwitch2"), PIN_DIMMERSWITCH_2, + PIN_DIMMERLEVEL_2, LOW, false); + + //***************************************************************************** + // Configure debug print output from each main class + //***************************************************************************** + st::Everything::debug = true; + st::Executor::debug = true; + st::Device::debug = true; + st::PollingSensor::debug = true; + st::InterruptSensor::debug = true; + + //***************************************************************************** + // Initialize the "Everything" Class + //***************************************************************************** + + // Initialize the optional local callback routine (safe to comment out if not + // desired) + st::Everything::callOnMsgSend = callback; + + // Create the SmartThings EthernetW5x00 Communications Object + // STATIC IP Assignment - Recommended + st::Everything::SmartThing = new st::SmartThingsEthernetW5x00( + mac, ip, gateway, subnet, dnsserver, serverPort, hubIp, hubPort, + st::receiveSmartString); + + // DHCP IP Assigment - Must set your router's DHCP server to provice a static + // IP address for this device's MAC address st::Everything::SmartThing = new + // st::SmartThingsEthernetW5x00(mac, serverPort, hubIp, hubPort, + // st::receiveSmartString); + + // Run the Everything class' init() routine which establishes Ethernet + // communications with the SmartThings Hub + st::Everything::init(); + + //***************************************************************************** + // Add each sensor to the "Everything" Class + //***************************************************************************** + st::Everything::addSensor(&sensor1); + st::Everything::addSensor(&sensor2); + st::Everything::addSensor(&sensor3); + st::Everything::addSensor(&sensor4); + st::Everything::addSensor(&sensor5); + st::Everything::addSensor(&sensor6); + st::Everything::addSensor(&sensor7); + st::Everything::addSensor(&sensor8); + st::Everything::addSensor(&sensor9); + st::Everything::addSensor(&sensor10); + st::Everything::addSensor(&sensor11); + st::Everything::addSensor(&sensor12); + st::Everything::addSensor(&sensor13); + st::Everything::addSensor(&sensor14); + st::Everything::addSensor(&sensor15); + st::Everything::addSensor(&sensor16); + st::Everything::addSensor(&sensor17); + st::Everything::addSensor(&sensor18); + st::Everything::addSensor(&sensor19); + st::Everything::addSensor(&sensor20); + st::Everything::addSensor(&sensor21); + st::Everything::addSensor(&sensor22); + st::Everything::addSensor(&sensor23); + st::Everything::addSensor(&sensor24); + + //***************************************************************************** + // Add each executor to the "Everything" Class + //***************************************************************************** + st::Everything::addExecutor(&executor1); + st::Everything::addExecutor(&executor2); + st::Everything::addExecutor(&executor3); + st::Everything::addExecutor(&executor4); + st::Everything::addExecutor(&executor5); + st::Everything::addExecutor(&executor6); + + //***************************************************************************** + // Initialize each of the devices which were added to the Everything Class + //***************************************************************************** + st::Everything::initDevices(); +} + +//****************************************************************************************** +// Arduino Loop() routine +//****************************************************************************************** +void loop() { + //***************************************************************************** + // Execute the Everything run method which takes care of "Everything" + //***************************************************************************** + st::Everything::run(); +} diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html