├── .gitignore
├── .travis.yml
├── .vscode
├── extensions.json
└── settings.json
├── CMakeLists.txt
├── README.md
├── data
├── bundle.js
└── index.html
├── include
└── README
├── lib
├── BmeHelper
│ ├── BmeHelper.cpp
│ ├── BmeHelper.h
│ └── library.json
├── BsecHelper
│ ├── BsecHelper.cpp
│ ├── BsecHelper.h
│ └── library.json
├── Co2Helper
│ ├── Co2Helper.cpp
│ ├── Co2Helper.h
│ └── library.json
├── I2Cdev
│ ├── I2Cdev.cpp
│ ├── I2Cdev.h
│ ├── keywords.txt
│ └── library.json
├── KnobHelper
│ ├── KnobHelper.cpp
│ ├── KnobHelper.h
│ └── library.json
├── LedHelper
│ ├── LedHelper.cpp
│ ├── LedHelper.h
│ └── library.json
├── MPU6050
│ ├── MPU6050.cpp
│ ├── MPU6050.h
│ └── library.json
├── MpuHelper
│ ├── MpuHelper.cpp
│ ├── MpuHelper.h
│ └── library.json
├── WaveshareHelper
│ ├── WaveshareHelper.cpp
│ ├── WaveshareHelper.h
│ └── library.json
├── WebServerHelper
│ ├── WebServerHelper.cpp
│ ├── WebServerHelper.h
│ └── library.json
└── WiFiHelper
│ ├── WiFiHelper.cpp
│ ├── WiFiHelper.h
│ └── library.json
├── partitions_custom.csv
├── platformio.ini
├── screenshots
├── aqiLed_wiring.png
├── aqiled.png
├── co2.png
├── co2_wiring.png
├── cube.png
├── cube_wiring.png
├── display.png
├── display_wiring.png
├── firmware.png
├── knob.png
├── knob_wiring.png
├── mpu6050.png
├── sleep.png
├── updateWebsite.png
├── upload.png
├── website.png
└── wifi.png
├── src
├── CMakeLists.txt
├── aqiLed.cpp
├── co2.cpp
├── cube.cpp
├── display.cpp
└── knob.cpp
└── test
└── README
/.gitignore:
--------------------------------------------------------------------------------
1 | .pio
2 | .vscode/.browse.c_cpp.db*
3 | .vscode/c_cpp_properties.json
4 | .vscode/launch.json
5 | .vscode/ipch
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | # Continuous Integration (CI) is the practice, in software
2 | # engineering, of merging all developer working copies with a shared mainline
3 | # several times a day < https://docs.platformio.org/page/ci/index.html >
4 | #
5 | # Documentation:
6 | #
7 | # * Travis CI Embedded Builds with PlatformIO
8 | # < https://docs.travis-ci.com/user/integration/platformio/ >
9 | #
10 | # * PlatformIO integration with Travis CI
11 | # < https://docs.platformio.org/page/ci/travis.html >
12 | #
13 | # * User Guide for `platformio ci` command
14 | # < https://docs.platformio.org/page/userguide/cmd_ci.html >
15 | #
16 | #
17 | # Please choose one of the following templates (proposed below) and uncomment
18 | # it (remove "# " before each line) or use own configuration according to the
19 | # Travis CI documentation (see above).
20 | #
21 |
22 |
23 | #
24 | # Template #1: General project. Test it using existing `platformio.ini`.
25 | #
26 |
27 | # language: python
28 | # python:
29 | # - "2.7"
30 | #
31 | # sudo: false
32 | # cache:
33 | # directories:
34 | # - "~/.platformio"
35 | #
36 | # install:
37 | # - pip install -U platformio
38 | # - platformio update
39 | #
40 | # script:
41 | # - platformio run
42 |
43 |
44 | #
45 | # Template #2: The project is intended to be used as a library with examples.
46 | #
47 |
48 | # language: python
49 | # python:
50 | # - "2.7"
51 | #
52 | # sudo: false
53 | # cache:
54 | # directories:
55 | # - "~/.platformio"
56 | #
57 | # env:
58 | # - PLATFORMIO_CI_SRC=path/to/test/file.c
59 | # - PLATFORMIO_CI_SRC=examples/file.ino
60 | # - PLATFORMIO_CI_SRC=path/to/test/directory
61 | #
62 | # install:
63 | # - pip install -U platformio
64 | # - platformio update
65 | #
66 | # script:
67 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N
68 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | // See http://go.microsoft.com/fwlink/?LinkId=827846
3 | // for the documentation about the extensions.json format
4 | "recommendations": [
5 | "platformio.platformio-ide"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.associations": {
3 | "functional": "cpp",
4 | "array": "cpp",
5 | "deque": "cpp",
6 | "string": "cpp",
7 | "unordered_map": "cpp",
8 | "unordered_set": "cpp",
9 | "vector": "cpp",
10 | "initializer_list": "cpp",
11 | "regex": "cpp",
12 | "*.tcc": "cpp",
13 | "bitset": "cpp",
14 | "fstream": "cpp",
15 | "istream": "cpp",
16 | "ostream": "cpp",
17 | "sstream": "cpp",
18 | "streambuf": "cpp",
19 | "system_error": "cpp",
20 | "tuple": "cpp",
21 | "iosfwd": "cpp",
22 | "limits": "cpp",
23 | "cstdlib": "cpp",
24 | "*.txt": "cpp",
25 | "random": "cpp",
26 | "type_traits": "cpp",
27 | "utility": "cpp"
28 | },
29 | "C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: Google, IndentWidth: 2, ColumnLimit: 0 }",
30 | "editor.formatOnSave": true
31 | }
32 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.16.0)
2 | include($ENV{IDF_PATH}/tools/cmake/project.cmake)
3 | project(espbs)
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # espbs
2 |
3 | Collection of my ESP32 projects.
4 |
5 | The project is set up with [platformIO](https://platformio.org/), and I'm using VS-Code as a code editor.
6 | https://randomnerdtutorials.com/vs-code-platformio-ide-esp32-esp8266-arduino/#1a
7 |
8 | To reuse and maintain the base libraries, I decided to create one single project for different applications, switchable in the platform.ini.
9 |
10 | The bundled configuration website is already part of this project (data) and stored on a separate spiffs partition on the ESP. If you want to adjust the website, please see [espjs project](https://github.com/Lillifee/espjs)
11 |
12 | Please let me know if you have ideas, improvements, or problems during setup. I'm also interested in your projects and willing to add them to the repository. If you have fancy 3d prints for an application, send me a message, and I will add them to the readme.
13 |
14 | ## Switch application
15 |
16 | To switch the application from e.g. cube to knob
17 |
18 | - open the platformio.ini file
19 | - check the [board](https://docs.platformio.org/en/latest/boards/index.html) type (lolin_d32, lolin32, wemos_d1_mini32 etc.)
20 | - comment the cube section
21 | - uncomment the knob section
22 |
23 | ## Upload the project
24 |
25 | You can eigher run the commands in the platformIO terminal or just use the PlatformIO tab in VSCode
26 |
27 | ### `pio run -t upload` - Build and upload the firmware
28 |
29 | ### `pio run -t uploadfs` - Build and upload the website partition
30 |
31 |
32 |
33 | 
34 |
35 | - `Upload` - build and upload the firmware (firmware.bin)
36 | - `Upload Filesystem Image` - Upload the website partition (spiffs.bin)
37 |
38 | ## Setup
39 |
40 | On the first startup, the ESP creates an access point called "espbs" to configure your Wi-Fi settings.
41 | Connect to the WLAN `espbs` with password `password`. Open the browser with http://192.168.4.1, and add your Wi-Fi settings.
42 |
43 | 
44 |
45 | I would also recommend using a static IP address to improve the startup time of the ESP.
46 | You can also assign a host name. This set the MDNS host name and allows you to connect to your ESP with `http://{yourHostName}.local` in your network.
47 |
48 | 
49 |
50 | After applying the changes, the ESP will reboot and connect to your network.
51 |
52 |  Some applications are running in deep-sleep to reduce power consumption.
53 | If you finished the configuraiton, don't forget to send the esp to deep sleep with the sleep button in the right bottom corner of the "Update" section.
54 |
55 | To change the settings while the esp is in sleep mode, you can press the RESET button on the ESP to start the webserver again.
56 |
57 | The reset button will not affect your settings, so if you misconfigured your ESP (e.g. wrong Wi-Fi settings) you can erase the flash from the PlatformIO menu and start from scratch.
58 |
59 | ## Update firmware
60 |
61 | Once the espbs is running, it's possible to update the firmware over the web interface.
62 | This can be quite handy if you want to update several devices on your network. e.g. multiple CO2 sensors.
63 |
64 | - Navigate to the platformIO section in VS Code and press `Build`
65 | - If you have done changes on the website (data) use `Build Filesystem Image`
66 | - Once the build is finished you should find a firmware.bin and a spiffs.bin (website) in your output folder /.pio/build/{board_name}/
67 |
68 | Open the website and upload the new firmware.
69 |
70 | -  Press the update firmware button and choose the firmware.bin file.
71 | -  Press the update website button and choose the spiffs.bin file.
72 |
73 | # Applications
74 |
75 | # Cube
76 |
77 | The cube is a remote control for 6 different functions. It uses an MPU6050 to figure out which side is on top and send a UDP request into your network. To save the battery life, the ESP32 remains in a deep sleep until the cube gets rotated. I switch four different light scenes in my living room and control the blinds with the remaining sides.
78 |
79 | I made this cube out of a parquet floor because I had no 3d printer back then. Send me your design's and I will add a link here.
80 |
81 | 
82 |
83 | ### Hardware
84 |
85 | - MPU6050 - GY512
86 | - ESP LOLIN32
87 | - 3,7V 1100mAh Lithium Akku
88 |
89 | 
90 |
91 | INT - is used to wake up from deep sleep. Feel free to use another pin and change it in the ./src/cube.cpp
92 | esp_sleep_enable_ext0_wakeup(GPIO_NUM_33, 1);
93 |
94 | ### Optimization
95 |
96 | I also found a nice article about optimizing for power consumption:
97 | https://bitbanksoftware.blogspot.com/2018/10/how-low-can-it-go-optimizing-for-power.html
98 |
99 | 1. Remove the voltage regulator and bridge it.
100 | 2. Remove the LED
101 |
102 | 
103 |
104 | # CO2
105 |
106 | The co2 sends the air quality as a UDP request to your home automation. I added two separate sensors to measure air quality in my living room, the MHZ-19 for the CO2 measurements, and a Bosh BME680 for the overall air quality. This application doesn't use deep sleep, and the website is running all the time. Therefore it's not necessary to send the ESP to deep sleep after configuration.
107 |
108 | You can find the 3d printing files on https://www.prusaprinters.org/prints/47612-air-quality-sensor-case-esp32
109 |
110 | 
111 |
112 | ### BSEC - Bosch Sensortec
113 |
114 | To run the BSECHelper with BME680 for additional IAQ (indoor air quality) - check the BSEC-Arduino-library.
115 | The library is not included in this repo.
116 | https://github.com/BoschSensortec/BSEC-Arduino-library
117 |
118 | Copy the library into ./pio/libdeps/BSECSoftwareLibrary and enable the special build flags in the platformio.ini
119 |
120 | ### Hardware
121 |
122 | - BME680 - pimoroni
123 | - MH-Z19 CO2 sensor
124 | - ESP LOLIN32
125 |
126 | 
127 |
128 | # Display
129 |
130 | The display uses a waveshare 7.5 inch display to visualize the values of your smart home. I use it to visualize the power consumption and the air quality in the living room. To save the battery life, the ESP32 remains in deep sleep and updates in the configured interval. At the moment, the displayed values are not configurable, but you can adjust it to your needs in the lib/WaveshareHelper library.
131 |
132 | You can find the 3d printing files on https://www.prusaprinters.org/prints/47605-e-paper-display-stand-esp32
133 |
134 | 
135 |
136 | ### Hardware
137 |
138 | - ESP LOLIN32
139 | - Waveshare 7.5 inch e-paper display
140 | - 3,7V 1100mAh Lithium Akku
141 |
142 | 
143 |
144 | # Knob
145 |
146 | The knob uses a rotary encoder to e.g. dim the light over Wi-Fi.
147 | To save the battery life, the ESP32 remains in a deep sleep until the knob gets pressed. On rotation, the current value is sent as a UDP packet into the network to my home automation server. After a few seconds without value change, the ESP goes back to deep sleep.
148 |
149 | You can find the 3d printing files on https://www.prusaprinters.org/prints/47614-wifi-knob-esp32
150 |
151 | 
152 |
153 | ### Hardware
154 |
155 | - ESP LOLIN32 lite
156 | - Rotary encoder
157 | - 3,7V 1100mAh Lithium Akku
158 |
159 | 
160 |
161 | Feel free to change the wiring in ./lib/KnobHelper/KnobHelper.h and the wakeup pin in ./src/knob.cpp
162 |
163 | # Air quality lamp
164 |
165 | The AQI-Led uses a BME680 and a LED ring (WS2812) to visualize the IAQ (Indoor air quality).
166 | There are different modes to change the visualization on the website.
167 |
168 | - The rainbow mode uses individual LEDs like a progress bar. 0 LEDs (excellent) to 24 LEDs (bad).
169 | - The color change mode uses all LEDs and indicates the IAQ as a color. Green (excellent) to red (bad)
170 |
171 | Besides the brightness, minimum value, there are also some animations to create ambient light.
172 |
173 | You can find the 3d printing files on https://www.prusaprinters.org/prints/49874-air-quality-lamp
174 |
175 | 
176 |
177 | ### Hardware
178 |
179 | - ESP LOLIN32
180 | - BME680 (BlueDot)
181 | - LED ring (WS2812)
182 |
183 | 
184 |
--------------------------------------------------------------------------------
/data/index.html:
--------------------------------------------------------------------------------
1 |
ESP You need to enable JavaScript to run this app.
--------------------------------------------------------------------------------
/include/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for project header files.
3 |
4 | A header file is a file containing C declarations and macro definitions
5 | to be shared between several project source files. You request the use of a
6 | header file in your project source file (C, C++, etc) located in `src` folder
7 | by including it, with the C preprocessing directive `#include'.
8 |
9 | ```src/main.c
10 |
11 | #include "header.h"
12 |
13 | int main (void)
14 | {
15 | ...
16 | }
17 | ```
18 |
19 | Including a header file produces the same results as copying the header file
20 | into each source file that needs it. Such copying would be time-consuming
21 | and error-prone. With a header file, the related declarations appear
22 | in only one place. If they need to be changed, they can be changed in one
23 | place, and programs that include the header file will automatically use the
24 | new version when next recompiled. The header file eliminates the labor of
25 | finding and changing all the copies as well as the risk that a failure to
26 | find one copy will result in inconsistencies within a program.
27 |
28 | In C, the usual convention is to give header files names that end with `.h'.
29 | It is most portable to use only letters, digits, dashes, and underscores in
30 | header file names, and at most one dot.
31 |
32 | Read more about using header files in official GCC documentation:
33 |
34 | * Include Syntax
35 | * Include Operation
36 | * Once-Only Headers
37 | * Computed Includes
38 |
39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
40 |
--------------------------------------------------------------------------------
/lib/BmeHelper/BmeHelper.cpp:
--------------------------------------------------------------------------------
1 | #include "BmeHelper.h"
2 |
3 | void BmeHelperClass::read() {
4 | preferences.begin("bme", true);
5 | host = preferences.getString("host");
6 | port = preferences.getInt("port", 3333);
7 | requestInterval = preferences.getInt("reqInterval", 60000);
8 | preferences.end();
9 | }
10 |
11 | void BmeHelperClass::write() {
12 | preferences.begin("bme", false);
13 | preferences.putString("host", host);
14 | preferences.putInt("port", port);
15 | preferences.putInt("reqInterval", requestInterval);
16 | preferences.end();
17 | }
18 |
19 | void BmeHelperClass::setup() {
20 | unsigned long setupStartTime = millis();
21 | Serial.println("Setup BME680 helper");
22 |
23 | if (!bme.begin(0x76)) {
24 | Serial.println("Could not find a valid BME680 sensor, check wiring!");
25 | return;
26 | }
27 |
28 | bme.setTemperatureOversampling(BME680_OS_8X);
29 | bme.setHumidityOversampling(BME680_OS_2X);
30 | bme.setPressureOversampling(BME680_OS_4X);
31 | bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
32 | bme.setGasHeater(320, 150); // 320*C for 150 ms
33 |
34 | read();
35 |
36 | setupDuration = millis() - setupStartTime;
37 | Serial.print("Setup CO2 helper took ");
38 | Serial.println(setupDuration);
39 | }
40 |
41 | void BmeHelperClass::loop() {
42 | if (millis() - readTimer >= 10000) {
43 | readValues();
44 | readTimer = millis();
45 | }
46 | if (millis() - requestTimer >= requestInterval) {
47 | sendValues();
48 | requestTimer = millis();
49 | }
50 | }
51 |
52 | void BmeHelperClass::sleep() {
53 | }
54 |
55 | void BmeHelperClass::readValues() {
56 | if (!bme.performReading()) {
57 | Serial.println("Failed to perform reading :(");
58 | return;
59 | }
60 |
61 | temp = bme.temperature;
62 | pressure = bme.pressure / 100.0;
63 | humidity = bme.humidity;
64 | gas = bme.gas_resistance / 1000.0;
65 | altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);
66 |
67 | Serial.print("Temp (C): ");
68 | Serial.print(temp);
69 |
70 | Serial.print(" Humidity (%): ");
71 | Serial.print(humidity);
72 |
73 | Serial.print(" Pressure (hPa): ");
74 | Serial.print(pressure);
75 |
76 | Serial.print(" Altitude (m): ");
77 | Serial.print(altitude);
78 |
79 | Serial.print(" Gas (KOhms): ");
80 | Serial.println(gas);
81 | }
82 |
83 | void BmeHelperClass::sendValues() {
84 | if (host.length() == 0) return;
85 | if (!WiFiHelper.connect()) return;
86 | unsigned long requestStartTime = millis();
87 |
88 | StaticJsonDocument<128> doc;
89 |
90 | udp.beginPacket(host.c_str(), port);
91 |
92 | doc["btmp"] = temp;
93 | doc["humidity"] = humidity;
94 | doc["pressure"] = pressure;
95 | doc["gas"] = gas;
96 | doc["altitude"] = altitude;
97 |
98 | serializeJson(doc, udp);
99 |
100 | udp.println();
101 | udp.endPacket();
102 |
103 | requestDuration = millis() - requestStartTime;
104 | Serial.print("Send UDP request ");
105 | Serial.println(requestDuration);
106 | }
107 |
108 | void BmeHelperClass::server() {
109 | Serial.println("Setup BME server");
110 |
111 | WebServerHelper.server.on("/api/bme", HTTP_GET, [this](AsyncWebServerRequest *request) {
112 | int args = request->args();
113 |
114 | if (args > 0) {
115 | request->send(200, "text/plain", "message received");
116 | Serial.println("Update BME settings");
117 |
118 | if (request->hasArg("host")) host = request->arg("host");
119 | if (request->hasArg("port")) port = request->arg("port").toInt();
120 | if (request->hasArg("requestInterval")) requestInterval = request->arg("requestInterval").toInt();
121 |
122 | write();
123 |
124 | } else {
125 | AsyncJsonResponse *response = new AsyncJsonResponse();
126 | response->addHeader("Server", "ESP Async Web Server");
127 | JsonVariant &root = response->getRoot();
128 |
129 | root["setupDuration"] = setupDuration;
130 | root["requestDuration"] = requestDuration;
131 |
132 | root["host"] = host;
133 | root["port"] = port;
134 |
135 | root["requestInterval"] = requestInterval;
136 |
137 | root["temp"] = temp;
138 | root["humidity"] = humidity;
139 | root["pressure"] = pressure;
140 | root["gas"] = gas;
141 | root["altitude"] = altitude;
142 |
143 | response->setLength();
144 | request->send(response);
145 | }
146 | });
147 | }
148 |
149 | BmeHelperClass BmeHelper;
150 |
--------------------------------------------------------------------------------
/lib/BmeHelper/BmeHelper.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef BmeHelper_h
3 | #define BmeHelper_h
4 |
5 | #include "Adafruit_BME680.h"
6 | #include "Adafruit_Sensor.h"
7 | #include "Arduino.h"
8 | #include "ArduinoJson.h"
9 | #include "AsyncJson.h"
10 | #include "HTTPClient.h"
11 | #include "SPI.h"
12 | #include "WebServerHelper.h"
13 | #include "WiFiUdp.h"
14 |
15 | #define SEALEVELPRESSURE_HPA (1013.25)
16 |
17 | class BmeHelperClass {
18 | private:
19 | WiFiUDP udp;
20 | Adafruit_BME680 bme;
21 | Preferences preferences;
22 |
23 | int32_t requestInterval;
24 | unsigned long readTimer = 0;
25 | unsigned long requestTimer = 0;
26 |
27 | String host;
28 | int32_t port;
29 |
30 | void read();
31 | void write();
32 |
33 | void readValues();
34 | void sendValues();
35 |
36 | unsigned long requestDuration;
37 | unsigned long setupDuration;
38 |
39 | public:
40 | float temp, humidity, pressure, gas, altitude;
41 |
42 | void setup();
43 | void server();
44 | void loop();
45 | void sleep();
46 | };
47 |
48 | extern BmeHelperClass BmeHelper;
49 |
50 | #endif
--------------------------------------------------------------------------------
/lib/BmeHelper/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "BmeHelper",
3 | "version": "1.0.0"
4 | }
--------------------------------------------------------------------------------
/lib/BsecHelper/BsecHelper.cpp:
--------------------------------------------------------------------------------
1 | #include "BsecHelper.h"
2 |
3 | const uint8_t bsec_config_iaq[] = {
4 | #include "config/generic_33v_3s_4d/bsec_iaq.txt"
5 | };
6 |
7 | void BsecHelperClass::read() {
8 | preferences.begin("bsec", true);
9 | host = preferences.getString("host");
10 | port = preferences.getInt("port", 3333);
11 | requestInterval = preferences.getInt("reqInterval", 60000);
12 | hasState = preferences.getBool("hasState", false);
13 | tempOffset = preferences.getFloat("tempOffset", 13.5f);
14 | preferences.getBytes("state", bsecState, BSEC_MAX_STATE_BLOB_SIZE);
15 | preferences.end();
16 | }
17 |
18 | void BsecHelperClass::write() {
19 | preferences.begin("bsec", false);
20 | preferences.putString("host", host);
21 | preferences.putInt("port", port);
22 | preferences.putInt("reqInterval", requestInterval);
23 | preferences.putFloat("tempOffset", tempOffset);
24 | preferences.end();
25 | }
26 |
27 | void BsecHelperClass::writeState(bool set) {
28 | iaqSensor.getState(bsecState);
29 | Serial.println("Write State set: " + set ? "true" : "false");
30 | for (uint8_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE; i++) {
31 | Serial.print(bsecState[i], HEX);
32 | }
33 | Serial.println("");
34 |
35 | preferences.begin("bsec", false);
36 | preferences.putBool("hasState", set);
37 | preferences.putBytes("state", bsecState, BSEC_MAX_STATE_BLOB_SIZE);
38 | preferences.end();
39 | }
40 |
41 | void BsecHelperClass::checkSensor() {
42 | if (iaqSensor.status != BSEC_OK) {
43 | Serial.println("BSEC error code : " + String(iaqSensor.status));
44 | }
45 | if (iaqSensor.bme680Status != BME680_OK) {
46 | Serial.println("BME680 error code : " + String(iaqSensor.bme680Status));
47 | }
48 | }
49 |
50 | void BsecHelperClass::setup(uint8_t i2cAddr) {
51 | unsigned long setupStartTime = millis();
52 | Serial.println("Setup BSEC helper");
53 |
54 | Wire.begin();
55 | iaqSensor.begin(i2cAddr, Wire);
56 | iaqSensor.setConfig(bsec_config_iaq);
57 |
58 | bsec_virtual_sensor_t sensorList[10] = {
59 | BSEC_OUTPUT_RAW_TEMPERATURE,
60 | BSEC_OUTPUT_RAW_PRESSURE,
61 | BSEC_OUTPUT_RAW_HUMIDITY,
62 | BSEC_OUTPUT_RAW_GAS,
63 | BSEC_OUTPUT_IAQ,
64 | BSEC_OUTPUT_STATIC_IAQ,
65 | BSEC_OUTPUT_CO2_EQUIVALENT,
66 | BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
67 | BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
68 | BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
69 | };
70 |
71 | iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP);
72 |
73 | checkSensor();
74 | read();
75 |
76 | if (hasState) {
77 | Serial.println("Setup BSEC SetState");
78 | iaqSensor.setState(bsecState);
79 | }
80 |
81 | iaqSensor.setTemperatureOffset(tempOffset);
82 | Serial.print("Setup BSEC helper temp offset ");
83 | Serial.println(tempOffset);
84 |
85 | udp.begin(port);
86 |
87 | setupDuration = millis() - setupStartTime;
88 | Serial.print("Setup BSEC helper took ");
89 | Serial.println(setupDuration);
90 | }
91 |
92 | void BsecHelperClass::loop() {
93 | readValues();
94 |
95 | if (millis() - requestTimer >= requestInterval) {
96 | sendValues();
97 | requestTimer = millis();
98 | }
99 | }
100 |
101 | void BsecHelperClass::sleep() {
102 | }
103 |
104 | void BsecHelperClass::readValues() {
105 | if (iaqSensor.run()) { // If new data is available
106 | Serial.print(String(iaqSensor.rawTemperature));
107 | Serial.print(", " + String(iaqSensor.pressure));
108 | Serial.print(", " + String(iaqSensor.rawHumidity));
109 | Serial.print(", " + String(iaqSensor.gasResistance));
110 | Serial.print(", " + String(iaqSensor.iaq));
111 | Serial.print(", " + String(iaqSensor.iaqAccuracy));
112 | Serial.print(", " + String(iaqSensor.temperature));
113 | Serial.print(", " + String(iaqSensor.humidity));
114 | Serial.print(", " + String(iaqSensor.staticIaq));
115 | Serial.print(", " + String(iaqSensor.co2Equivalent));
116 | Serial.print(", " + String(iaqSensor.breathVocEquivalent));
117 |
118 | Serial.println("");
119 | updateState();
120 | } else {
121 | checkSensor();
122 | }
123 | }
124 |
125 | void BsecHelperClass::updateState() {
126 | if (stateUpdateCounter == 0) {
127 | if (iaqSensor.iaqAccuracy >= 3) {
128 | stateUpdateCounter++;
129 | writeState(true);
130 | }
131 | } else {
132 | if ((stateUpdateCounter * STATE_SAVE_PERIOD) < millis()) {
133 | stateUpdateCounter++;
134 | writeState(true);
135 | }
136 | }
137 | }
138 |
139 | void BsecHelperClass::sendValues() {
140 | if (host.length() == 0) return;
141 | if (!WiFiHelper.connect()) return;
142 | unsigned long requestStartTime = millis();
143 |
144 | StaticJsonDocument<300> doc;
145 |
146 | udp.beginPacket(host.c_str(), port);
147 |
148 | doc["rtmp"] = iaqSensor.rawTemperature;
149 | doc["pressure"] = iaqSensor.pressure;
150 | doc["humidity"] = iaqSensor.rawHumidity;
151 | doc["gasResistance"] = iaqSensor.gasResistance;
152 | doc["iaq"] = iaqSensor.iaq;
153 | doc["iaqAccuracy"] = iaqSensor.iaqAccuracy;
154 | doc["temperature"] = iaqSensor.temperature;
155 | doc["humidity"] = iaqSensor.humidity;
156 | doc["staticIaq"] = iaqSensor.staticIaq;
157 | doc["co2Equivalent"] = iaqSensor.co2Equivalent;
158 | doc["breathVocEquivalent"] = iaqSensor.breathVocEquivalent;
159 |
160 | serializeJson(doc, udp);
161 |
162 | udp.println();
163 | udp.endPacket();
164 |
165 | requestDuration = millis() - requestStartTime;
166 | Serial.print("Send UDP request ");
167 | Serial.println(requestDuration);
168 | }
169 |
170 | void BsecHelperClass::server() {
171 | Serial.println("Setup BSEC server");
172 |
173 | WebServerHelper.server.on("/api/bsec", HTTP_GET, [this](AsyncWebServerRequest *request) {
174 | int args = request->args();
175 |
176 | if (args > 0) {
177 | request->send(200, "text/plain", "message received");
178 | Serial.println("Update BSEC settings");
179 |
180 | if (request->hasArg("host")) host = request->arg("host");
181 | if (request->hasArg("port")) port = request->arg("port").toInt();
182 | if (request->hasArg("requestInterval")) requestInterval = request->arg("requestInterval").toInt();
183 | if (request->hasArg("tempOffset")) tempOffset = request->arg("tempOffset").toFloat();
184 |
185 | write();
186 | ESP.restart();
187 |
188 | } else {
189 | AsyncJsonResponse *response = new AsyncJsonResponse();
190 | response->addHeader("Server", "ESP Async Web Server");
191 | JsonVariant &root = response->getRoot();
192 |
193 | root["setupDuration"] = setupDuration;
194 | root["requestDuration"] = requestDuration;
195 |
196 | root["host"] = host;
197 | root["port"] = port;
198 |
199 | root["requestInterval"] = requestInterval;
200 | root["tempOffset"] = tempOffset;
201 |
202 | root["rtmp"] = iaqSensor.rawTemperature;
203 | root["pressure"] = iaqSensor.pressure;
204 | root["rawHumidity"] = iaqSensor.rawHumidity;
205 | root["gasResistance"] = iaqSensor.gasResistance;
206 | root["iaq"] = iaqSensor.iaq;
207 | root["iaqAccuracy"] = iaqSensor.iaqAccuracy;
208 | root["temperature"] = iaqSensor.temperature;
209 | root["humidity"] = iaqSensor.humidity;
210 | root["staticIaq"] = iaqSensor.staticIaq;
211 | root["co2Equivalent"] = iaqSensor.co2Equivalent;
212 | root["breathVocEquivalent"] = iaqSensor.breathVocEquivalent;
213 |
214 | response->setLength();
215 | request->send(response);
216 | }
217 | });
218 |
219 | WebServerHelper.server.on("/api/bsecState", HTTP_GET, [this](AsyncWebServerRequest *request) {
220 | writeState(!request->hasArg("reset"));
221 | request->send(200, "text/plain", "message received");
222 | ESP.restart();
223 | });
224 | }
225 |
226 | BsecHelperClass BsecHelper;
227 |
--------------------------------------------------------------------------------
/lib/BsecHelper/BsecHelper.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef BsecHelper_h
3 | #define BsecHelper_h
4 |
5 | #include "Arduino.h"
6 | #include "ArduinoJson.h"
7 | #include "AsyncJson.h"
8 | #include "HTTPClient.h"
9 | #include "Preferences.h"
10 | #include "WebServerHelper.h"
11 | #include "WiFiUdp.h"
12 | #include "WifiHelper.h"
13 | #include "bsec.h"
14 |
15 | #define STATE_SAVE_PERIOD UINT32_C(360 * 60 * 1000) // 360 minutes - 4 times a day
16 |
17 | class BsecHelperClass {
18 | private:
19 | WiFiUDP udp;
20 | Preferences preferences;
21 |
22 | int32_t requestInterval;
23 | unsigned long readTimer = 0;
24 | unsigned long requestTimer = 0;
25 |
26 | uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
27 | uint16_t stateUpdateCounter = 0;
28 |
29 | String host;
30 | int32_t port;
31 | bool hasState;
32 | float tempOffset;
33 |
34 | void read();
35 | void write();
36 |
37 | void checkSensor();
38 | void readValues();
39 | void sendValues();
40 |
41 | void updateState();
42 | void writeState(bool write);
43 |
44 | unsigned long requestDuration;
45 | unsigned long setupDuration;
46 |
47 | public:
48 | Bsec iaqSensor;
49 |
50 | void setup(uint8_t i2cAddr);
51 | void server();
52 | void loop();
53 | void sleep();
54 | };
55 |
56 | extern BsecHelperClass BsecHelper;
57 |
58 | #endif
--------------------------------------------------------------------------------
/lib/BsecHelper/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "BsecHelper",
3 | "version": "1.0.0"
4 | }
--------------------------------------------------------------------------------
/lib/Co2Helper/Co2Helper.cpp:
--------------------------------------------------------------------------------
1 | #include "Co2Helper.h"
2 |
3 | Co2HelperClass::Co2HelperClass() : hwSerial(2){};
4 |
5 | void Co2HelperClass::read() {
6 | preferences.begin("co2", true);
7 | host = preferences.getString("host");
8 | port = preferences.getInt("port", 3333);
9 | autoCalibration = preferences.getBool("autoCalib", false);
10 | requestInterval = preferences.getInt("reqInterval", 60000);
11 | preferences.end();
12 | }
13 |
14 | void Co2HelperClass::write() {
15 | preferences.begin("co2", false);
16 | preferences.putString("host", host);
17 | preferences.putInt("port", port);
18 | preferences.putBool("autoCalib", autoCalibration);
19 | preferences.putInt("reqInterval", requestInterval);
20 | preferences.end();
21 | }
22 |
23 | void Co2HelperClass::setup() {
24 | unsigned long setupStartTime = millis();
25 | Serial.println("Setup CO2 helper");
26 |
27 | read();
28 |
29 | hwSerial.begin(9600);
30 |
31 | mhz19.begin(hwSerial);
32 | mhz19.autoCalibration(autoCalibration);
33 |
34 | udp.begin(port);
35 |
36 | setupDuration = millis() - setupStartTime;
37 | Serial.print("Setup CO2 helper took ");
38 | Serial.println(setupDuration);
39 | }
40 |
41 | void Co2HelperClass::loop() {
42 | if (millis() - readTimer >= 10000) {
43 | readValues();
44 | readTimer = millis();
45 | }
46 | if (millis() - requestTimer >= requestInterval) {
47 | sendValues();
48 | requestTimer = millis();
49 | }
50 | }
51 |
52 | void Co2HelperClass::sleep() {
53 | }
54 |
55 | void Co2HelperClass::readValues() {
56 | int readCo2 = mhz19.getCO2();
57 | float readTemp = mhz19.getTemperature(true);
58 |
59 | if (mhz19.errorCode == RESULT_OK && readCo2 != 0) {
60 | co2 = readCo2;
61 | temp = readTemp;
62 |
63 | Serial.print("CO2 (ppm): ");
64 | Serial.print(co2);
65 |
66 | Serial.print(" Temperature (C): ");
67 | Serial.println(temp);
68 | } else {
69 | Serial.print("Failed to read co2 sensor ");
70 | Serial.println(String(mhz19.errorCode));
71 | }
72 | }
73 |
74 | void Co2HelperClass::sendValues() {
75 | if (host.length() == 0) return;
76 | if (!WiFiHelper.connect()) return;
77 | unsigned long requestStartTime = millis();
78 |
79 | StaticJsonDocument<45> doc;
80 |
81 | udp.beginPacket(host.c_str(), port);
82 |
83 | doc["co2"] = co2;
84 | doc["ctmp"] = temp;
85 | serializeJson(doc, udp);
86 |
87 | udp.println();
88 | udp.endPacket();
89 |
90 | requestDuration = millis() - requestStartTime;
91 | Serial.print("Send UDP request ");
92 | Serial.println(requestDuration);
93 | }
94 |
95 | void Co2HelperClass::server() {
96 | Serial.println("Setup CO2 server");
97 |
98 | WebServerHelper.server.on("/api/co2", HTTP_GET, [this](AsyncWebServerRequest *request) {
99 | int args = request->args();
100 |
101 | if (args > 0) {
102 | request->send(200, "text/plain", "message received");
103 | Serial.println("Update CO2 settings");
104 |
105 | if (request->hasArg("host")) host = request->arg("host");
106 | if (request->hasArg("port")) port = request->arg("port").toInt();
107 | if (request->hasArg("autoCalibration")) autoCalibration = request->arg("autoCalibration") == "1";
108 | if (request->hasArg("requestInterval")) requestInterval = request->arg("requestInterval").toInt();
109 |
110 | write();
111 |
112 | } else {
113 | AsyncJsonResponse *response = new AsyncJsonResponse();
114 | response->addHeader("Server", "ESP Async Web Server");
115 | JsonVariant &root = response->getRoot();
116 |
117 | root["setupDuration"] = setupDuration;
118 | root["requestDuration"] = requestDuration;
119 |
120 | root["host"] = host;
121 | root["port"] = port;
122 |
123 | root["autoCalibration"] = autoCalibration ? 1 : 0;
124 | root["requestInterval"] = requestInterval;
125 |
126 | root["co2"] = co2;
127 | root["temp"] = temp;
128 |
129 | response->setLength();
130 | request->send(response);
131 | }
132 | });
133 |
134 | WebServerHelper.server.on("/api/co2Calibrate", HTTP_GET, [this](AsyncWebServerRequest *request) {
135 | mhz19.autoCalibration(false);
136 | mhz19.calibrate();
137 |
138 | request->send(200, "text/plain", "message received");
139 | });
140 | }
141 |
142 | Co2HelperClass Co2Helper;
143 |
--------------------------------------------------------------------------------
/lib/Co2Helper/Co2Helper.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef Co2Helper_h
3 | #define Co2Helper_h
4 |
5 | #include "Arduino.h"
6 | #include "ArduinoJson.h"
7 | #include "AsyncJson.h"
8 | #include "HTTPClient.h"
9 | #include "MHZ19.h"
10 | #include "Preferences.h"
11 | #include "WebServerHelper.h"
12 | #include "WiFiHelper.h"
13 | #include "WiFiUdp.h"
14 |
15 | class Co2HelperClass {
16 | private:
17 | MHZ19 mhz19;
18 | WiFiUDP udp;
19 | Preferences preferences;
20 |
21 | int32_t requestInterval;
22 | unsigned long readTimer = 0;
23 | unsigned long requestTimer = 0;
24 |
25 | String host;
26 | int32_t port;
27 | boolean autoCalibration;
28 |
29 | void read();
30 | void write();
31 |
32 | void readValues();
33 | void sendValues();
34 |
35 | unsigned long requestDuration;
36 | unsigned long setupDuration;
37 |
38 | public:
39 | Co2HelperClass();
40 | HardwareSerial hwSerial;
41 |
42 | float temp;
43 | int co2;
44 |
45 | void setup();
46 | void server();
47 | void loop();
48 | void sleep();
49 | };
50 |
51 | extern Co2HelperClass Co2Helper;
52 |
53 | #endif
--------------------------------------------------------------------------------
/lib/Co2Helper/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Co2Helper",
3 | "version": "1.0.0"
4 | }
--------------------------------------------------------------------------------
/lib/I2Cdev/I2Cdev.cpp:
--------------------------------------------------------------------------------
1 | // I2Cdev library collection - Main I2C device class
2 | // Abstracts bit and byte I2C R/W functions into a convenient class
3 | // 2013-06-05 by Jeff Rowberg
4 | //
5 | // Changelog:
6 | // 2013-05-06 - add Francesco Ferrara's Fastwire v0.24 implementation with small modifications
7 | // 2013-05-05 - fix issue with writing bit values to words (Sasquatch/Farzanegan)
8 | // 2012-06-09 - fix major issue with reading > 32 bytes at a time with Arduino Wire
9 | // - add compiler warnings when using outdated or IDE or limited I2Cdev implementation
10 | // 2011-11-01 - fix write*Bits mask calculation (thanks sasquatch @ Arduino forums)
11 | // 2011-10-03 - added automatic Arduino version detection for ease of use
12 | // 2011-10-02 - added Gene Knight's NBWire TwoWire class implementation with small modifications
13 | // 2011-08-31 - added support for Arduino 1.0 Wire library (methods are different from 0.x)
14 | // 2011-08-03 - added optional timeout parameter to read* methods to easily change from default
15 | // 2011-08-02 - added support for 16-bit registers
16 | // - fixed incorrect Doxygen comments on some methods
17 | // - added timeout value for read operations (thanks mem @ Arduino forums)
18 | // 2011-07-30 - changed read/write function structures to return success or byte counts
19 | // - made all methods static for multi-device memory savings
20 | // 2011-07-28 - initial release
21 |
22 | /* ============================================
23 | I2Cdev device library code is placed under the MIT license
24 | Copyright (c) 2013 Jeff Rowberg
25 |
26 | Permission is hereby granted, free of charge, to any person obtaining a copy
27 | of this software and associated documentation files (the "Software"), to deal
28 | in the Software without restriction, including without limitation the rights
29 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30 | copies of the Software, and to permit persons to whom the Software is
31 | furnished to do so, subject to the following conditions:
32 |
33 | The above copyright notice and this permission notice shall be included in
34 | all copies or substantial portions of the Software.
35 |
36 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
39 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
42 | THE SOFTWARE.
43 | ===============================================
44 | */
45 |
46 | #include "I2Cdev.h"
47 |
48 | #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE
49 |
50 | #ifdef I2CDEV_IMPLEMENTATION_WARNINGS
51 | #if ARDUINO < 100
52 | #warning Using outdated Arduino IDE with Wire library is functionally limiting.
53 | #warning Arduino IDE v1.6.5+ with I2Cdev Fastwire implementation is recommended.
54 | #warning This I2Cdev implementation does not support:
55 | #warning - Repeated starts conditions
56 | #warning - Timeout detection (some Wire requests block forever)
57 | #elif ARDUINO == 100
58 | #warning Using outdated Arduino IDE with Wire library is functionally limiting.
59 | #warning Arduino IDE v1.6.5+ with I2Cdev Fastwire implementation is recommended.
60 | #warning This I2Cdev implementation does not support:
61 | #warning - Repeated starts conditions
62 | #warning - Timeout detection (some Wire requests block forever)
63 | #elif ARDUINO > 100
64 | /*#warning Using current Arduino IDE with Wire library is functionally limiting.
65 | #warning Arduino IDE v1.6.5+ with I2CDEV_BUILTIN_FASTWIRE implementation is recommended.
66 | #warning This I2Cdev implementation does not support:
67 | #warning - Timeout detection (some Wire requests block forever)*/
68 | #endif
69 | #endif
70 |
71 | #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
72 |
73 | //#error The I2CDEV_BUILTIN_FASTWIRE implementation is known to be broken right now. Patience, Iago!
74 |
75 | #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
76 |
77 | #ifdef I2CDEV_IMPLEMENTATION_WARNINGS
78 | #warning Using I2CDEV_BUILTIN_NBWIRE implementation may adversely affect interrupt detection.
79 | #warning This I2Cdev implementation does not support:
80 | #warning - Repeated starts conditions
81 | #endif
82 |
83 | // NBWire implementation based heavily on code by Gene Knight
84 | // Originally posted on the Arduino forum at http://arduino.cc/forum/index.php/topic,70705.0.html
85 | // Originally offered to the i2cdevlib project at http://arduino.cc/forum/index.php/topic,68210.30.html
86 | TwoWire Wire;
87 |
88 | #endif
89 |
90 | #ifndef BUFFER_LENGTH
91 | // band-aid fix for platforms without Wire-defined BUFFER_LENGTH (removed from some official implementations)
92 | #define BUFFER_LENGTH 32
93 | #endif
94 |
95 | /** Default constructor.
96 | */
97 | I2Cdev::I2Cdev() {
98 | }
99 |
100 | /** Read a single bit from an 8-bit device register.
101 | * @param devAddr I2C slave device address
102 | * @param regAddr Register regAddr to read from
103 | * @param bitNum Bit position to read (0-7)
104 | * @param data Container for single bit value
105 | * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
106 | * @return Status of read operation (true = success)
107 | */
108 | int8_t I2Cdev::readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout) {
109 | uint8_t b;
110 | uint8_t count = readByte(devAddr, regAddr, &b, timeout);
111 | *data = b & (1 << bitNum);
112 | return count;
113 | }
114 |
115 | /** Read a single bit from a 16-bit device register.
116 | * @param devAddr I2C slave device address
117 | * @param regAddr Register regAddr to read from
118 | * @param bitNum Bit position to read (0-15)
119 | * @param data Container for single bit value
120 | * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
121 | * @return Status of read operation (true = success)
122 | */
123 | int8_t I2Cdev::readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout) {
124 | uint16_t b;
125 | uint8_t count = readWord(devAddr, regAddr, &b, timeout);
126 | *data = b & (1 << bitNum);
127 | return count;
128 | }
129 |
130 | /** Read multiple bits from an 8-bit device register.
131 | * @param devAddr I2C slave device address
132 | * @param regAddr Register regAddr to read from
133 | * @param bitStart First bit position to read (0-7)
134 | * @param length Number of bits to read (not more than 8)
135 | * @param data Container for right-aligned value (i.e. '101' read from any bitStart position will equal 0x05)
136 | * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
137 | * @return Status of read operation (true = success)
138 | */
139 | int8_t I2Cdev::readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout) {
140 | // 01101001 read byte
141 | // 76543210 bit numbers
142 | // xxx args: bitStart=4, length=3
143 | // 010 masked
144 | // -> 010 shifted
145 | uint8_t count, b;
146 | if ((count = readByte(devAddr, regAddr, &b, timeout)) != 0) {
147 | uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1);
148 | b &= mask;
149 | b >>= (bitStart - length + 1);
150 | *data = b;
151 | }
152 | return count;
153 | }
154 |
155 | /** Read multiple bits from a 16-bit device register.
156 | * @param devAddr I2C slave device address
157 | * @param regAddr Register regAddr to read from
158 | * @param bitStart First bit position to read (0-15)
159 | * @param length Number of bits to read (not more than 16)
160 | * @param data Container for right-aligned value (i.e. '101' read from any bitStart position will equal 0x05)
161 | * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
162 | * @return Status of read operation (1 = success, 0 = failure, -1 = timeout)
163 | */
164 | int8_t I2Cdev::readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout) {
165 | // 1101011001101001 read byte
166 | // fedcba9876543210 bit numbers
167 | // xxx args: bitStart=12, length=3
168 | // 010 masked
169 | // -> 010 shifted
170 | uint8_t count;
171 | uint16_t w;
172 | if ((count = readWord(devAddr, regAddr, &w, timeout)) != 0) {
173 | uint16_t mask = ((1 << length) - 1) << (bitStart - length + 1);
174 | w &= mask;
175 | w >>= (bitStart - length + 1);
176 | *data = w;
177 | }
178 | return count;
179 | }
180 |
181 | /** Read single byte from an 8-bit device register.
182 | * @param devAddr I2C slave device address
183 | * @param regAddr Register regAddr to read from
184 | * @param data Container for byte value read from device
185 | * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
186 | * @return Status of read operation (true = success)
187 | */
188 | int8_t I2Cdev::readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout) {
189 | return readBytes(devAddr, regAddr, 1, data, timeout);
190 | }
191 |
192 | /** Read single word from a 16-bit device register.
193 | * @param devAddr I2C slave device address
194 | * @param regAddr Register regAddr to read from
195 | * @param data Container for word value read from device
196 | * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
197 | * @return Status of read operation (true = success)
198 | */
199 | int8_t I2Cdev::readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout) {
200 | return readWords(devAddr, regAddr, 1, data, timeout);
201 | }
202 |
203 | /** Read multiple bytes from an 8-bit device register.
204 | * @param devAddr I2C slave device address
205 | * @param regAddr First register regAddr to read from
206 | * @param length Number of bytes to read
207 | * @param data Buffer to store read data in
208 | * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
209 | * @return Number of bytes read (-1 indicates failure)
210 | */
211 | int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout) {
212 | #ifdef I2CDEV_SERIAL_DEBUG
213 | Serial.print("I2C (0x");
214 | Serial.print(devAddr, HEX);
215 | Serial.print(") reading ");
216 | Serial.print(length, DEC);
217 | Serial.print(" bytes from 0x");
218 | Serial.print(regAddr, HEX);
219 | Serial.print("...");
220 | #endif
221 |
222 | int8_t count = 0;
223 | uint32_t t1 = millis();
224 |
225 | #if (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE)
226 |
227 | #if (ARDUINO < 100)
228 | // Arduino v00xx (before v1.0), Wire library
229 |
230 | // I2C/TWI subsystem uses internal buffer that breaks with large data requests
231 | // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
232 | // smaller chunks instead of all at once
233 | for (uint8_t k = 0; k < length; k += min((int)length, BUFFER_LENGTH)) {
234 | Wire.beginTransmission(devAddr);
235 | Wire.send(regAddr);
236 | Wire.endTransmission();
237 | Wire.beginTransmission(devAddr);
238 | Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH));
239 |
240 | for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) {
241 | data[count] = Wire.receive();
242 | #ifdef I2CDEV_SERIAL_DEBUG
243 | Serial.print(data[count], HEX);
244 | if (count + 1 < length) Serial.print(" ");
245 | #endif
246 | }
247 |
248 | Wire.endTransmission();
249 | }
250 | #elif (ARDUINO == 100)
251 | // Arduino v1.0.0, Wire library
252 | // Adds standardized write() and read() stream methods instead of send() and receive()
253 |
254 | // I2C/TWI subsystem uses internal buffer that breaks with large data requests
255 | // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
256 | // smaller chunks instead of all at once
257 | for (uint8_t k = 0; k < length; k += min((int)length, BUFFER_LENGTH)) {
258 | Wire.beginTransmission(devAddr);
259 | Wire.write(regAddr);
260 | Wire.endTransmission();
261 | Wire.beginTransmission(devAddr);
262 | Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH));
263 |
264 | for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) {
265 | data[count] = Wire.read();
266 | #ifdef I2CDEV_SERIAL_DEBUG
267 | Serial.print(data[count], HEX);
268 | if (count + 1 < length) Serial.print(" ");
269 | #endif
270 | }
271 |
272 | Wire.endTransmission();
273 | }
274 | #elif (ARDUINO > 100)
275 | // Arduino v1.0.1+, Wire library
276 | // Adds official support for repeated start condition, yay!
277 |
278 | // I2C/TWI subsystem uses internal buffer that breaks with large data requests
279 | // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
280 | // smaller chunks instead of all at once
281 | for (uint8_t k = 0; k < length; k += min((int)length, BUFFER_LENGTH)) {
282 | Wire.beginTransmission(devAddr);
283 | Wire.write(regAddr);
284 | Wire.endTransmission();
285 | Wire.beginTransmission(devAddr);
286 | Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH));
287 |
288 | for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) {
289 | data[count] = Wire.read();
290 | #ifdef I2CDEV_SERIAL_DEBUG
291 | Serial.print(data[count], HEX);
292 | if (count + 1 < length) Serial.print(" ");
293 | #endif
294 | }
295 | }
296 | #endif
297 |
298 | #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE)
299 |
300 | // Fastwire library
301 | // no loop required for fastwire
302 | uint8_t status = Fastwire::readBuf(devAddr << 1, regAddr, data, length);
303 | if (status == 0) {
304 | count = length; // success
305 | } else {
306 | count = -1; // error
307 | }
308 |
309 | #endif
310 |
311 | // check for timeout
312 | if (timeout > 0 && millis() - t1 >= timeout && count < length) count = -1; // timeout
313 |
314 | #ifdef I2CDEV_SERIAL_DEBUG
315 | Serial.print(". Done (");
316 | Serial.print(count, DEC);
317 | Serial.println(" read).");
318 | #endif
319 |
320 | return count;
321 | }
322 |
323 | /** Read multiple words from a 16-bit device register.
324 | * @param devAddr I2C slave device address
325 | * @param regAddr First register regAddr to read from
326 | * @param length Number of words to read
327 | * @param data Buffer to store read data in
328 | * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout)
329 | * @return Number of words read (-1 indicates failure)
330 | */
331 | int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout) {
332 | #ifdef I2CDEV_SERIAL_DEBUG
333 | Serial.print("I2C (0x");
334 | Serial.print(devAddr, HEX);
335 | Serial.print(") reading ");
336 | Serial.print(length, DEC);
337 | Serial.print(" words from 0x");
338 | Serial.print(regAddr, HEX);
339 | Serial.print("...");
340 | #endif
341 |
342 | int8_t count = 0;
343 | uint32_t t1 = millis();
344 |
345 | #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE
346 |
347 | #if (ARDUINO < 100)
348 | // Arduino v00xx (before v1.0), Wire library
349 |
350 | // I2C/TWI subsystem uses internal buffer that breaks with large data requests
351 | // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
352 | // smaller chunks instead of all at once
353 | for (uint8_t k = 0; k < length * 2; k += min(length * 2, BUFFER_LENGTH)) {
354 | Wire.beginTransmission(devAddr);
355 | Wire.send(regAddr);
356 | Wire.endTransmission();
357 | Wire.beginTransmission(devAddr);
358 | Wire.requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes
359 |
360 | bool msb = true; // starts with MSB, then LSB
361 | for (; Wire.available() && count < length && (timeout == 0 || millis() - t1 < timeout);) {
362 | if (msb) {
363 | // first byte is bits 15-8 (MSb=15)
364 | data[count] = Wire.receive() << 8;
365 | } else {
366 | // second byte is bits 7-0 (LSb=0)
367 | data[count] |= Wire.receive();
368 | #ifdef I2CDEV_SERIAL_DEBUG
369 | Serial.print(data[count], HEX);
370 | if (count + 1 < length) Serial.print(" ");
371 | #endif
372 | count++;
373 | }
374 | msb = !msb;
375 | }
376 |
377 | Wire.endTransmission();
378 | }
379 | #elif (ARDUINO == 100)
380 | // Arduino v1.0.0, Wire library
381 | // Adds standardized write() and read() stream methods instead of send() and receive()
382 |
383 | // I2C/TWI subsystem uses internal buffer that breaks with large data requests
384 | // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
385 | // smaller chunks instead of all at once
386 | for (uint8_t k = 0; k < length * 2; k += min(length * 2, BUFFER_LENGTH)) {
387 | Wire.beginTransmission(devAddr);
388 | Wire.write(regAddr);
389 | Wire.endTransmission();
390 | Wire.beginTransmission(devAddr);
391 | Wire.requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes
392 |
393 | bool msb = true; // starts with MSB, then LSB
394 | for (; Wire.available() && count < length && (timeout == 0 || millis() - t1 < timeout);) {
395 | if (msb) {
396 | // first byte is bits 15-8 (MSb=15)
397 | data[count] = Wire.read() << 8;
398 | } else {
399 | // second byte is bits 7-0 (LSb=0)
400 | data[count] |= Wire.read();
401 | #ifdef I2CDEV_SERIAL_DEBUG
402 | Serial.print(data[count], HEX);
403 | if (count + 1 < length) Serial.print(" ");
404 | #endif
405 | count++;
406 | }
407 | msb = !msb;
408 | }
409 |
410 | Wire.endTransmission();
411 | }
412 | #elif (ARDUINO > 100)
413 | // Arduino v1.0.1+, Wire library
414 | // Adds official support for repeated start condition, yay!
415 |
416 | // I2C/TWI subsystem uses internal buffer that breaks with large data requests
417 | // so if user requests more than BUFFER_LENGTH bytes, we have to do it in
418 | // smaller chunks instead of all at once
419 | for (uint8_t k = 0; k < length * 2; k += min(length * 2, BUFFER_LENGTH)) {
420 | Wire.beginTransmission(devAddr);
421 | Wire.write(regAddr);
422 | Wire.endTransmission();
423 | Wire.beginTransmission(devAddr);
424 | Wire.requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes
425 |
426 | bool msb = true; // starts with MSB, then LSB
427 | for (; Wire.available() && count < length && (timeout == 0 || millis() - t1 < timeout);) {
428 | if (msb) {
429 | // first byte is bits 15-8 (MSb=15)
430 | data[count] = Wire.read() << 8;
431 | } else {
432 | // second byte is bits 7-0 (LSb=0)
433 | data[count] |= Wire.read();
434 | #ifdef I2CDEV_SERIAL_DEBUG
435 | Serial.print(data[count], HEX);
436 | if (count + 1 < length) Serial.print(" ");
437 | #endif
438 | count++;
439 | }
440 | msb = !msb;
441 | }
442 |
443 | Wire.endTransmission();
444 | }
445 | #endif
446 |
447 | #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE)
448 |
449 | // Fastwire library
450 | // no loop required for fastwire
451 | uint8_t intermediate[(uint8_t)length*2];
452 | uint8_t status = Fastwire::readBuf(devAddr << 1, regAddr, intermediate, (uint8_t)(length * 2));
453 | if (status == 0) {
454 | count = length; // success
455 | for (uint8_t i = 0; i < length; i++) {
456 | data[i] = (intermediate[2*i] << 8) | intermediate[2*i + 1];
457 | }
458 | } else {
459 | count = -1; // error
460 | }
461 |
462 | #endif
463 |
464 | if (timeout > 0 && millis() - t1 >= timeout && count < length) count = -1; // timeout
465 |
466 | #ifdef I2CDEV_SERIAL_DEBUG
467 | Serial.print(". Done (");
468 | Serial.print(count, DEC);
469 | Serial.println(" read).");
470 | #endif
471 |
472 | return count;
473 | }
474 |
475 | /** write a single bit in an 8-bit device register.
476 | * @param devAddr I2C slave device address
477 | * @param regAddr Register regAddr to write to
478 | * @param bitNum Bit position to write (0-7)
479 | * @param value New bit value to write
480 | * @return Status of operation (true = success)
481 | */
482 | bool I2Cdev::writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data) {
483 | uint8_t b;
484 | readByte(devAddr, regAddr, &b);
485 | b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum));
486 | return writeByte(devAddr, regAddr, b);
487 | }
488 |
489 | /** write a single bit in a 16-bit device register.
490 | * @param devAddr I2C slave device address
491 | * @param regAddr Register regAddr to write to
492 | * @param bitNum Bit position to write (0-15)
493 | * @param value New bit value to write
494 | * @return Status of operation (true = success)
495 | */
496 | bool I2Cdev::writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data) {
497 | uint16_t w;
498 | readWord(devAddr, regAddr, &w);
499 | w = (data != 0) ? (w | (1 << bitNum)) : (w & ~(1 << bitNum));
500 | return writeWord(devAddr, regAddr, w);
501 | }
502 |
503 | /** Write multiple bits in an 8-bit device register.
504 | * @param devAddr I2C slave device address
505 | * @param regAddr Register regAddr to write to
506 | * @param bitStart First bit position to write (0-7)
507 | * @param length Number of bits to write (not more than 8)
508 | * @param data Right-aligned value to write
509 | * @return Status of operation (true = success)
510 | */
511 | bool I2Cdev::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data) {
512 | // 010 value to write
513 | // 76543210 bit numbers
514 | // xxx args: bitStart=4, length=3
515 | // 00011100 mask byte
516 | // 10101111 original value (sample)
517 | // 10100011 original & ~mask
518 | // 10101011 masked | value
519 | uint8_t b;
520 | if (readByte(devAddr, regAddr, &b) != 0) {
521 | uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1);
522 | data <<= (bitStart - length + 1); // shift data into correct position
523 | data &= mask; // zero all non-important bits in data
524 | b &= ~(mask); // zero all important bits in existing byte
525 | b |= data; // combine data with existing byte
526 | return writeByte(devAddr, regAddr, b);
527 | } else {
528 | return false;
529 | }
530 | }
531 |
532 | /** Write multiple bits in a 16-bit device register.
533 | * @param devAddr I2C slave device address
534 | * @param regAddr Register regAddr to write to
535 | * @param bitStart First bit position to write (0-15)
536 | * @param length Number of bits to write (not more than 16)
537 | * @param data Right-aligned value to write
538 | * @return Status of operation (true = success)
539 | */
540 | bool I2Cdev::writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data) {
541 | // 010 value to write
542 | // fedcba9876543210 bit numbers
543 | // xxx args: bitStart=12, length=3
544 | // 0001110000000000 mask word
545 | // 1010111110010110 original value (sample)
546 | // 1010001110010110 original & ~mask
547 | // 1010101110010110 masked | value
548 | uint16_t w;
549 | if (readWord(devAddr, regAddr, &w) != 0) {
550 | uint16_t mask = ((1 << length) - 1) << (bitStart - length + 1);
551 | data <<= (bitStart - length + 1); // shift data into correct position
552 | data &= mask; // zero all non-important bits in data
553 | w &= ~(mask); // zero all important bits in existing word
554 | w |= data; // combine data with existing word
555 | return writeWord(devAddr, regAddr, w);
556 | } else {
557 | return false;
558 | }
559 | }
560 |
561 | /** Write single byte to an 8-bit device register.
562 | * @param devAddr I2C slave device address
563 | * @param regAddr Register address to write to
564 | * @param data New byte value to write
565 | * @return Status of operation (true = success)
566 | */
567 | bool I2Cdev::writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data) {
568 | return writeBytes(devAddr, regAddr, 1, &data);
569 | }
570 |
571 | /** Write single word to a 16-bit device register.
572 | * @param devAddr I2C slave device address
573 | * @param regAddr Register address to write to
574 | * @param data New word value to write
575 | * @return Status of operation (true = success)
576 | */
577 | bool I2Cdev::writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data) {
578 | return writeWords(devAddr, regAddr, 1, &data);
579 | }
580 |
581 | /** Write multiple bytes to an 8-bit device register.
582 | * @param devAddr I2C slave device address
583 | * @param regAddr First register address to write to
584 | * @param length Number of bytes to write
585 | * @param data Buffer to copy new data from
586 | * @return Status of operation (true = success)
587 | */
588 | bool I2Cdev::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t* data) {
589 | #ifdef I2CDEV_SERIAL_DEBUG
590 | Serial.print("I2C (0x");
591 | Serial.print(devAddr, HEX);
592 | Serial.print(") writing ");
593 | Serial.print(length, DEC);
594 | Serial.print(" bytes to 0x");
595 | Serial.print(regAddr, HEX);
596 | Serial.print("...");
597 | #endif
598 | uint8_t status = 0;
599 | #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE)
600 | Wire.beginTransmission(devAddr);
601 | Wire.send((uint8_t) regAddr); // send address
602 | #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \
603 | || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \
604 | || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE)
605 | Wire.beginTransmission(devAddr);
606 | Wire.write((uint8_t) regAddr); // send address
607 | #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE)
608 | Fastwire::beginTransmission(devAddr);
609 | Fastwire::write(regAddr);
610 | #endif
611 | for (uint8_t i = 0; i < length; i++) {
612 | #ifdef I2CDEV_SERIAL_DEBUG
613 | Serial.print(data[i], HEX);
614 | if (i + 1 < length) Serial.print(" ");
615 | #endif
616 | #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE)
617 | Wire.send((uint8_t) data[i]);
618 | #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \
619 | || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \
620 | || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE)
621 | Wire.write((uint8_t) data[i]);
622 | #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE)
623 | Fastwire::write((uint8_t) data[i]);
624 | #endif
625 | }
626 | #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE)
627 | Wire.endTransmission();
628 | #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \
629 | || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \
630 | || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE)
631 | status = Wire.endTransmission();
632 | #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE)
633 | Fastwire::stop();
634 | //status = Fastwire::endTransmission();
635 | #endif
636 | #ifdef I2CDEV_SERIAL_DEBUG
637 | Serial.println(". Done.");
638 | #endif
639 | return status == 0;
640 | }
641 |
642 | /** Write multiple words to a 16-bit device register.
643 | * @param devAddr I2C slave device address
644 | * @param regAddr First register address to write to
645 | * @param length Number of words to write
646 | * @param data Buffer to copy new data from
647 | * @return Status of operation (true = success)
648 | */
649 | bool I2Cdev::writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t* data) {
650 | #ifdef I2CDEV_SERIAL_DEBUG
651 | Serial.print("I2C (0x");
652 | Serial.print(devAddr, HEX);
653 | Serial.print(") writing ");
654 | Serial.print(length, DEC);
655 | Serial.print(" words to 0x");
656 | Serial.print(regAddr, HEX);
657 | Serial.print("...");
658 | #endif
659 | uint8_t status = 0;
660 | #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE)
661 | Wire.beginTransmission(devAddr);
662 | Wire.send(regAddr); // send address
663 | #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \
664 | || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \
665 | || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE)
666 | Wire.beginTransmission(devAddr);
667 | Wire.write(regAddr); // send address
668 | #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE)
669 | Fastwire::beginTransmission(devAddr);
670 | Fastwire::write(regAddr);
671 | #endif
672 | for (uint8_t i = 0; i < length; i++) {
673 | #ifdef I2CDEV_SERIAL_DEBUG
674 | Serial.print(data[i], HEX);
675 | if (i + 1 < length) Serial.print(" ");
676 | #endif
677 | #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE)
678 | Wire.send((uint8_t)(data[i] >> 8)); // send MSB
679 | Wire.send((uint8_t)data[i]); // send LSB
680 | #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \
681 | || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \
682 | || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE)
683 | Wire.write((uint8_t)(data[i] >> 8)); // send MSB
684 | Wire.write((uint8_t)data[i]); // send LSB
685 | #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE)
686 | Fastwire::write((uint8_t)(data[i] >> 8)); // send MSB
687 | status = Fastwire::write((uint8_t)data[i]); // send LSB
688 | if (status != 0) break;
689 | #endif
690 | }
691 | #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE)
692 | Wire.endTransmission();
693 | #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \
694 | || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \
695 | || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE)
696 | status = Wire.endTransmission();
697 | #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE)
698 | Fastwire::stop();
699 | //status = Fastwire::endTransmission();
700 | #endif
701 | #ifdef I2CDEV_SERIAL_DEBUG
702 | Serial.println(". Done.");
703 | #endif
704 | return status == 0;
705 | }
706 |
707 | /** Default timeout value for read operations.
708 | * Set this to 0 to disable timeout detection.
709 | */
710 | uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT;
711 |
712 | #if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
713 | // I2C library
714 | //////////////////////
715 | // Copyright(C) 2012
716 | // Francesco Ferrara
717 | // ferrara[at]libero[point]it
718 | //////////////////////
719 |
720 | /*
721 | FastWire
722 | - 0.24 added stop
723 | - 0.23 added reset
724 |
725 | This is a library to help faster programs to read I2C devices.
726 | Copyright(C) 2012 Francesco Ferrara
727 | occhiobello at gmail dot com
728 | [used by Jeff Rowberg for I2Cdevlib with permission]
729 | */
730 |
731 | boolean Fastwire::waitInt() {
732 | int l = 250;
733 | while (!(TWCR & (1 << TWINT)) && l-- > 0);
734 | return l > 0;
735 | }
736 |
737 | void Fastwire::setup(int khz, boolean pullup) {
738 | TWCR = 0;
739 | #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__)
740 | // activate internal pull-ups for twi (PORTC bits 4 & 5)
741 | // as per note from atmega8 manual pg167
742 | if (pullup) PORTC |= ((1 << 4) | (1 << 5));
743 | else PORTC &= ~((1 << 4) | (1 << 5));
744 | #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
745 | // activate internal pull-ups for twi (PORTC bits 0 & 1)
746 | if (pullup) PORTC |= ((1 << 0) | (1 << 1));
747 | else PORTC &= ~((1 << 0) | (1 << 1));
748 | #else
749 | // activate internal pull-ups for twi (PORTD bits 0 & 1)
750 | // as per note from atmega128 manual pg204
751 | if (pullup) PORTD |= ((1 << 0) | (1 << 1));
752 | else PORTD &= ~((1 << 0) | (1 << 1));
753 | #endif
754 |
755 | TWSR = 0; // no prescaler => prescaler = 1
756 | TWBR = ((16000L / khz) - 16) / 2; // change the I2C clock rate
757 | TWCR = 1 << TWEN; // enable twi module, no interrupt
758 | }
759 |
760 | // added by Jeff Rowberg 2013-05-07:
761 | // Arduino Wire-style "beginTransmission" function
762 | // (takes 7-bit device address like the Wire method, NOT 8-bit: 0x68, not 0xD0/0xD1)
763 | byte Fastwire::beginTransmission(byte device) {
764 | byte twst, retry;
765 | retry = 2;
766 | do {
767 | TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO) | (1 << TWSTA);
768 | if (!waitInt()) return 1;
769 | twst = TWSR & 0xF8;
770 | if (twst != TW_START && twst != TW_REP_START) return 2;
771 |
772 | //Serial.print(device, HEX);
773 | //Serial.print(" ");
774 | TWDR = device << 1; // send device address without read bit (1)
775 | TWCR = (1 << TWINT) | (1 << TWEN);
776 | if (!waitInt()) return 3;
777 | twst = TWSR & 0xF8;
778 | } while (twst == TW_MT_SLA_NACK && retry-- > 0);
779 | if (twst != TW_MT_SLA_ACK) return 4;
780 | return 0;
781 | }
782 |
783 | byte Fastwire::writeBuf(byte device, byte address, byte *data, byte num) {
784 | byte twst, retry;
785 |
786 | retry = 2;
787 | do {
788 | TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO) | (1 << TWSTA);
789 | if (!waitInt()) return 1;
790 | twst = TWSR & 0xF8;
791 | if (twst != TW_START && twst != TW_REP_START) return 2;
792 |
793 | //Serial.print(device, HEX);
794 | //Serial.print(" ");
795 | TWDR = device & 0xFE; // send device address without read bit (1)
796 | TWCR = (1 << TWINT) | (1 << TWEN);
797 | if (!waitInt()) return 3;
798 | twst = TWSR & 0xF8;
799 | } while (twst == TW_MT_SLA_NACK && retry-- > 0);
800 | if (twst != TW_MT_SLA_ACK) return 4;
801 |
802 | //Serial.print(address, HEX);
803 | //Serial.print(" ");
804 | TWDR = address; // send data to the previously addressed device
805 | TWCR = (1 << TWINT) | (1 << TWEN);
806 | if (!waitInt()) return 5;
807 | twst = TWSR & 0xF8;
808 | if (twst != TW_MT_DATA_ACK) return 6;
809 |
810 | for (byte i = 0; i < num; i++) {
811 | //Serial.print(data[i], HEX);
812 | //Serial.print(" ");
813 | TWDR = data[i]; // send data to the previously addressed device
814 | TWCR = (1 << TWINT) | (1 << TWEN);
815 | if (!waitInt()) return 7;
816 | twst = TWSR & 0xF8;
817 | if (twst != TW_MT_DATA_ACK) return 8;
818 | }
819 | //Serial.print("\n");
820 |
821 | return 0;
822 | }
823 |
824 | byte Fastwire::write(byte value) {
825 | byte twst;
826 | //Serial.println(value, HEX);
827 | TWDR = value; // send data
828 | TWCR = (1 << TWINT) | (1 << TWEN);
829 | if (!waitInt()) return 1;
830 | twst = TWSR & 0xF8;
831 | if (twst != TW_MT_DATA_ACK) return 2;
832 | return 0;
833 | }
834 |
835 | byte Fastwire::readBuf(byte device, byte address, byte *data, byte num) {
836 | byte twst, retry;
837 |
838 | retry = 2;
839 | do {
840 | TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO) | (1 << TWSTA);
841 | if (!waitInt()) return 16;
842 | twst = TWSR & 0xF8;
843 | if (twst != TW_START && twst != TW_REP_START) return 17;
844 |
845 | //Serial.print(device, HEX);
846 | //Serial.print(" ");
847 | TWDR = device & 0xfe; // send device address to write
848 | TWCR = (1 << TWINT) | (1 << TWEN);
849 | if (!waitInt()) return 18;
850 | twst = TWSR & 0xF8;
851 | } while (twst == TW_MT_SLA_NACK && retry-- > 0);
852 | if (twst != TW_MT_SLA_ACK) return 19;
853 |
854 | //Serial.print(address, HEX);
855 | //Serial.print(" ");
856 | TWDR = address; // send data to the previously addressed device
857 | TWCR = (1 << TWINT) | (1 << TWEN);
858 | if (!waitInt()) return 20;
859 | twst = TWSR & 0xF8;
860 | if (twst != TW_MT_DATA_ACK) return 21;
861 |
862 | /***/
863 |
864 | retry = 2;
865 | do {
866 | TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO) | (1 << TWSTA);
867 | if (!waitInt()) return 22;
868 | twst = TWSR & 0xF8;
869 | if (twst != TW_START && twst != TW_REP_START) return 23;
870 |
871 | //Serial.print(device, HEX);
872 | //Serial.print(" ");
873 | TWDR = device | 0x01; // send device address with the read bit (1)
874 | TWCR = (1 << TWINT) | (1 << TWEN);
875 | if (!waitInt()) return 24;
876 | twst = TWSR & 0xF8;
877 | } while (twst == TW_MR_SLA_NACK && retry-- > 0);
878 | if (twst != TW_MR_SLA_ACK) return 25;
879 |
880 | for (uint8_t i = 0; i < num; i++) {
881 | if (i == num - 1)
882 | TWCR = (1 << TWINT) | (1 << TWEN);
883 | else
884 | TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
885 | if (!waitInt()) return 26;
886 | twst = TWSR & 0xF8;
887 | if (twst != TW_MR_DATA_ACK && twst != TW_MR_DATA_NACK) return twst;
888 | data[i] = TWDR;
889 | //Serial.print(data[i], HEX);
890 | //Serial.print(" ");
891 | }
892 | //Serial.print("\n");
893 | stop();
894 |
895 | return 0;
896 | }
897 |
898 | void Fastwire::reset() {
899 | TWCR = 0;
900 | }
901 |
902 | byte Fastwire::stop() {
903 | TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
904 | if (!waitInt()) return 1;
905 | return 0;
906 | }
907 | #endif
908 |
909 | #if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
910 | // NBWire implementation based heavily on code by Gene Knight
911 | // Originally posted on the Arduino forum at http://arduino.cc/forum/index.php/topic,70705.0.html
912 | // Originally offered to the i2cdevlib project at http://arduino.cc/forum/index.php/topic,68210.30.html
913 |
914 | /*
915 | call this version 1.0
916 |
917 | Offhand, the only funky part that I can think of is in nbrequestFrom, where the buffer
918 | length and index are set *before* the data is actually read. The problem is that these
919 | are variables local to the TwoWire object, and by the time we actually have read the
920 | data, and know what the length actually is, we have no simple access to the object's
921 | variables. The actual bytes read *is* given to the callback function, though.
922 |
923 | The ISR code for a slave receiver is commented out. I don't have that setup, and can't
924 | verify it at this time. Save it for 2.0!
925 |
926 | The handling of the read and write processes here is much like in the demo sketch code:
927 | the process is broken down into sequential functions, where each registers the next as a
928 | callback, essentially.
929 |
930 | For example, for the Read process, twi_read00 just returns if TWI is not yet in a
931 | ready state. When there's another interrupt, and the interface *is* ready, then it
932 | sets up the read, starts it, and registers twi_read01 as the function to call after
933 | the *next* interrupt. twi_read01, then, just returns if the interface is still in a
934 | "reading" state. When the reading is done, it copies the information to the buffer,
935 | cleans up, and calls the user-requested callback function with the actual number of
936 | bytes read.
937 |
938 | The writing is similar.
939 |
940 | Questions, comments and problems can go to Gene@Telobot.com.
941 |
942 | Thumbs Up!
943 | Gene Knight
944 |
945 | */
946 |
947 | uint8_t TwoWire::rxBuffer[NBWIRE_BUFFER_LENGTH];
948 | uint8_t TwoWire::rxBufferIndex = 0;
949 | uint8_t TwoWire::rxBufferLength = 0;
950 |
951 | uint8_t TwoWire::txAddress = 0;
952 | uint8_t TwoWire::txBuffer[NBWIRE_BUFFER_LENGTH];
953 | uint8_t TwoWire::txBufferIndex = 0;
954 | uint8_t TwoWire::txBufferLength = 0;
955 |
956 | //uint8_t TwoWire::transmitting = 0;
957 | void (*TwoWire::user_onRequest)(void);
958 | void (*TwoWire::user_onReceive)(int);
959 |
960 | static volatile uint8_t twi_transmitting;
961 | static volatile uint8_t twi_state;
962 | static uint8_t twi_slarw;
963 | static volatile uint8_t twi_error;
964 | static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH];
965 | static volatile uint8_t twi_masterBufferIndex;
966 | static uint8_t twi_masterBufferLength;
967 | static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH];
968 | static volatile uint8_t twi_rxBufferIndex;
969 | //static volatile uint8_t twi_Interrupt_Continue_Command;
970 | static volatile uint8_t twi_Return_Value;
971 | static volatile uint8_t twi_Done;
972 | void (*twi_cbendTransmissionDone)(int);
973 | void (*twi_cbreadFromDone)(int);
974 |
975 | void twi_init() {
976 | // initialize state
977 | twi_state = TWI_READY;
978 |
979 | // activate internal pull-ups for twi
980 | // as per note from atmega8 manual pg167
981 | sbi(PORTC, 4);
982 | sbi(PORTC, 5);
983 |
984 | // initialize twi prescaler and bit rate
985 | cbi(TWSR, TWPS0); // TWI Status Register - Prescaler bits
986 | cbi(TWSR, TWPS1);
987 |
988 | /* twi bit rate formula from atmega128 manual pg 204
989 | SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
990 | note: TWBR should be 10 or higher for master mode
991 | It is 72 for a 16mhz Wiring board with 100kHz TWI */
992 |
993 | TWBR = ((CPU_FREQ / TWI_FREQ) - 16) / 2; // bitrate register
994 | // enable twi module, acks, and twi interrupt
995 |
996 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA);
997 |
998 | /* TWEN - TWI Enable Bit
999 | TWIE - TWI Interrupt Enable
1000 | TWEA - TWI Enable Acknowledge Bit
1001 | TWINT - TWI Interrupt Flag
1002 | TWSTA - TWI Start Condition
1003 | */
1004 | }
1005 |
1006 | typedef struct {
1007 | uint8_t address;
1008 | uint8_t* data;
1009 | uint8_t length;
1010 | uint8_t wait;
1011 | uint8_t i;
1012 | } twi_Write_Vars;
1013 |
1014 | twi_Write_Vars *ptwv = 0;
1015 | static void (*fNextInterruptFunction)(void) = 0;
1016 |
1017 | void twi_Finish(byte bRetVal) {
1018 | if (ptwv) {
1019 | free(ptwv);
1020 | ptwv = 0;
1021 | }
1022 | twi_Done = 0xFF;
1023 | twi_Return_Value = bRetVal;
1024 | fNextInterruptFunction = 0;
1025 | }
1026 |
1027 | uint8_t twii_WaitForDone(uint16_t timeout) {
1028 | uint32_t endMillis = millis() + timeout;
1029 | while (!twi_Done && (timeout == 0 || millis() < endMillis)) continue;
1030 | return twi_Return_Value;
1031 | }
1032 |
1033 | void twii_SetState(uint8_t ucState) {
1034 | twi_state = ucState;
1035 | }
1036 |
1037 | void twii_SetError(uint8_t ucError) {
1038 | twi_error = ucError ;
1039 | }
1040 |
1041 | void twii_InitBuffer(uint8_t ucPos, uint8_t ucLength) {
1042 | twi_masterBufferIndex = 0;
1043 | twi_masterBufferLength = ucLength;
1044 | }
1045 |
1046 | void twii_CopyToBuf(uint8_t* pData, uint8_t ucLength) {
1047 | uint8_t i;
1048 | for (i = 0; i < ucLength; ++i) {
1049 | twi_masterBuffer[i] = pData[i];
1050 | }
1051 | }
1052 |
1053 | void twii_CopyFromBuf(uint8_t *pData, uint8_t ucLength) {
1054 | uint8_t i;
1055 | for (i = 0; i < ucLength; ++i) {
1056 | pData[i] = twi_masterBuffer[i];
1057 | }
1058 | }
1059 |
1060 | void twii_SetSlaRW(uint8_t ucSlaRW) {
1061 | twi_slarw = ucSlaRW;
1062 | }
1063 |
1064 | void twii_SetStart() {
1065 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA);
1066 | }
1067 |
1068 | void twi_write01() {
1069 | if (TWI_MTX == twi_state) return; // blocking test
1070 | twi_transmitting = 0 ;
1071 | if (twi_error == 0xFF)
1072 | twi_Finish (0); // success
1073 | else if (twi_error == TW_MT_SLA_NACK)
1074 | twi_Finish (2); // error: address send, nack received
1075 | else if (twi_error == TW_MT_DATA_NACK)
1076 | twi_Finish (3); // error: data send, nack received
1077 | else
1078 | twi_Finish (4); // other twi error
1079 | if (twi_cbendTransmissionDone) return twi_cbendTransmissionDone(twi_Return_Value);
1080 | return;
1081 | }
1082 |
1083 |
1084 | void twi_write00() {
1085 | if (TWI_READY != twi_state) return; // blocking test
1086 | if (TWI_BUFFER_LENGTH < ptwv -> length) {
1087 | twi_Finish(1); // end write with error 1
1088 | return;
1089 | }
1090 | twi_Done = 0x00; // show as working
1091 | twii_SetState(TWI_MTX); // to transmitting
1092 | twii_SetError(0xFF); // to No Error
1093 | twii_InitBuffer(0, ptwv -> length); // pointer and length
1094 | twii_CopyToBuf(ptwv -> data, ptwv -> length); // get the data
1095 | twii_SetSlaRW((ptwv -> address << 1) | TW_WRITE); // write command
1096 | twii_SetStart(); // start the cycle
1097 | fNextInterruptFunction = twi_write01; // next routine
1098 | return twi_write01();
1099 | }
1100 |
1101 | void twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait) {
1102 | uint8_t i;
1103 | ptwv = (twi_Write_Vars *)malloc(sizeof(twi_Write_Vars));
1104 | ptwv -> address = address;
1105 | ptwv -> data = data;
1106 | ptwv -> length = length;
1107 | ptwv -> wait = wait;
1108 | fNextInterruptFunction = twi_write00;
1109 | return twi_write00();
1110 | }
1111 |
1112 | void twi_read01() {
1113 | if (TWI_MRX == twi_state) return; // blocking test
1114 | if (twi_masterBufferIndex < ptwv -> length) ptwv -> length = twi_masterBufferIndex;
1115 | twii_CopyFromBuf(ptwv -> data, ptwv -> length);
1116 | twi_Finish(ptwv -> length);
1117 | if (twi_cbreadFromDone) return twi_cbreadFromDone(twi_Return_Value);
1118 | return;
1119 | }
1120 |
1121 | void twi_read00() {
1122 | if (TWI_READY != twi_state) return; // blocking test
1123 | if (TWI_BUFFER_LENGTH < ptwv -> length) twi_Finish(0); // error return
1124 | twi_Done = 0x00; // show as working
1125 | twii_SetState(TWI_MRX); // reading
1126 | twii_SetError(0xFF); // reset error
1127 | twii_InitBuffer(0, ptwv -> length - 1); // init to one less than length
1128 | twii_SetSlaRW((ptwv -> address << 1) | TW_READ); // read command
1129 | twii_SetStart(); // start cycle
1130 | fNextInterruptFunction = twi_read01;
1131 | return twi_read01();
1132 | }
1133 |
1134 | void twi_readFrom(uint8_t address, uint8_t* data, uint8_t length) {
1135 | uint8_t i;
1136 |
1137 | ptwv = (twi_Write_Vars *)malloc(sizeof(twi_Write_Vars));
1138 | ptwv -> address = address;
1139 | ptwv -> data = data;
1140 | ptwv -> length = length;
1141 | fNextInterruptFunction = twi_read00;
1142 | return twi_read00();
1143 | }
1144 |
1145 | void twi_reply(uint8_t ack) {
1146 | // transmit master read ready signal, with or without ack
1147 | if (ack){
1148 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA);
1149 | } else {
1150 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT);
1151 | }
1152 | }
1153 |
1154 | void twi_stop(void) {
1155 | // send stop condition
1156 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO);
1157 |
1158 | // wait for stop condition to be exectued on bus
1159 | // TWINT is not set after a stop condition!
1160 | while (TWCR & _BV(TWSTO)) {
1161 | continue;
1162 | }
1163 |
1164 | // update twi state
1165 | twi_state = TWI_READY;
1166 | }
1167 |
1168 | void twi_releaseBus(void) {
1169 | // release bus
1170 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT);
1171 |
1172 | // update twi state
1173 | twi_state = TWI_READY;
1174 | }
1175 |
1176 | SIGNAL(TWI_vect) {
1177 | switch (TW_STATUS) {
1178 | // All Master
1179 | case TW_START: // sent start condition
1180 | case TW_REP_START: // sent repeated start condition
1181 | // copy device address and r/w bit to output register and ack
1182 | TWDR = twi_slarw;
1183 | twi_reply(1);
1184 | break;
1185 |
1186 | // Master Transmitter
1187 | case TW_MT_SLA_ACK: // slave receiver acked address
1188 | case TW_MT_DATA_ACK: // slave receiver acked data
1189 | // if there is data to send, send it, otherwise stop
1190 | if (twi_masterBufferIndex < twi_masterBufferLength) {
1191 | // copy data to output register and ack
1192 | TWDR = twi_masterBuffer[twi_masterBufferIndex++];
1193 | twi_reply(1);
1194 | } else {
1195 | twi_stop();
1196 | }
1197 | break;
1198 |
1199 | case TW_MT_SLA_NACK: // address sent, nack received
1200 | twi_error = TW_MT_SLA_NACK;
1201 | twi_stop();
1202 | break;
1203 |
1204 | case TW_MT_DATA_NACK: // data sent, nack received
1205 | twi_error = TW_MT_DATA_NACK;
1206 | twi_stop();
1207 | break;
1208 |
1209 | case TW_MT_ARB_LOST: // lost bus arbitration
1210 | twi_error = TW_MT_ARB_LOST;
1211 | twi_releaseBus();
1212 | break;
1213 |
1214 | // Master Receiver
1215 | case TW_MR_DATA_ACK: // data received, ack sent
1216 | // put byte into buffer
1217 | twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
1218 |
1219 | case TW_MR_SLA_ACK: // address sent, ack received
1220 | // ack if more bytes are expected, otherwise nack
1221 | if (twi_masterBufferIndex < twi_masterBufferLength) {
1222 | twi_reply(1);
1223 | } else {
1224 | twi_reply(0);
1225 | }
1226 | break;
1227 |
1228 | case TW_MR_DATA_NACK: // data received, nack sent
1229 | // put final byte into buffer
1230 | twi_masterBuffer[twi_masterBufferIndex++] = TWDR;
1231 |
1232 | case TW_MR_SLA_NACK: // address sent, nack received
1233 | twi_stop();
1234 | break;
1235 |
1236 | // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case
1237 |
1238 | // Slave Receiver (NOT IMPLEMENTED YET)
1239 | /*
1240 | case TW_SR_SLA_ACK: // addressed, returned ack
1241 | case TW_SR_GCALL_ACK: // addressed generally, returned ack
1242 | case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack
1243 | case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack
1244 | // enter slave receiver mode
1245 | twi_state = TWI_SRX;
1246 |
1247 | // indicate that rx buffer can be overwritten and ack
1248 | twi_rxBufferIndex = 0;
1249 | twi_reply(1);
1250 | break;
1251 |
1252 | case TW_SR_DATA_ACK: // data received, returned ack
1253 | case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack
1254 | // if there is still room in the rx buffer
1255 | if (twi_rxBufferIndex < TWI_BUFFER_LENGTH) {
1256 | // put byte in buffer and ack
1257 | twi_rxBuffer[twi_rxBufferIndex++] = TWDR;
1258 | twi_reply(1);
1259 | } else {
1260 | // otherwise nack
1261 | twi_reply(0);
1262 | }
1263 | break;
1264 |
1265 | case TW_SR_STOP: // stop or repeated start condition received
1266 | // put a null char after data if there's room
1267 | if (twi_rxBufferIndex < TWI_BUFFER_LENGTH) {
1268 | twi_rxBuffer[twi_rxBufferIndex] = 0;
1269 | }
1270 |
1271 | // sends ack and stops interface for clock stretching
1272 | twi_stop();
1273 |
1274 | // callback to user defined callback
1275 | twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex);
1276 |
1277 | // since we submit rx buffer to "wire" library, we can reset it
1278 | twi_rxBufferIndex = 0;
1279 |
1280 | // ack future responses and leave slave receiver state
1281 | twi_releaseBus();
1282 | break;
1283 |
1284 | case TW_SR_DATA_NACK: // data received, returned nack
1285 | case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack
1286 | // nack back at master
1287 | twi_reply(0);
1288 | break;
1289 |
1290 | // Slave Transmitter
1291 | case TW_ST_SLA_ACK: // addressed, returned ack
1292 | case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack
1293 | // enter slave transmitter mode
1294 | twi_state = TWI_STX;
1295 |
1296 | // ready the tx buffer index for iteration
1297 | twi_txBufferIndex = 0;
1298 |
1299 | // set tx buffer length to be zero, to verify if user changes it
1300 | twi_txBufferLength = 0;
1301 |
1302 | // request for txBuffer to be filled and length to be set
1303 | // note: user must call twi_transmit(bytes, length) to do this
1304 | twi_onSlaveTransmit();
1305 |
1306 | // if they didn't change buffer & length, initialize it
1307 | if (0 == twi_txBufferLength) {
1308 | twi_txBufferLength = 1;
1309 | twi_txBuffer[0] = 0x00;
1310 | }
1311 |
1312 | // transmit first byte from buffer, fall through
1313 |
1314 | case TW_ST_DATA_ACK: // byte sent, ack returned
1315 | // copy data to output register
1316 | TWDR = twi_txBuffer[twi_txBufferIndex++];
1317 |
1318 | // if there is more to send, ack, otherwise nack
1319 | if (twi_txBufferIndex < twi_txBufferLength) {
1320 | twi_reply(1);
1321 | } else {
1322 | twi_reply(0);
1323 | }
1324 | break;
1325 |
1326 | case TW_ST_DATA_NACK: // received nack, we are done
1327 | case TW_ST_LAST_DATA: // received ack, but we are done already!
1328 | // ack future responses
1329 | twi_reply(1);
1330 | // leave slave receiver state
1331 | twi_state = TWI_READY;
1332 | break;
1333 | */
1334 |
1335 | // all
1336 | case TW_NO_INFO: // no state information
1337 | break;
1338 |
1339 | case TW_BUS_ERROR: // bus error, illegal stop/start
1340 | twi_error = TW_BUS_ERROR;
1341 | twi_stop();
1342 | break;
1343 | }
1344 |
1345 | if (fNextInterruptFunction) return fNextInterruptFunction();
1346 | }
1347 |
1348 | TwoWire::TwoWire() { }
1349 |
1350 | void TwoWire::begin(void) {
1351 | rxBufferIndex = 0;
1352 | rxBufferLength = 0;
1353 |
1354 | txBufferIndex = 0;
1355 | txBufferLength = 0;
1356 |
1357 | twi_init();
1358 | }
1359 |
1360 | void TwoWire::beginTransmission(uint8_t address) {
1361 | //beginTransmission((uint8_t)address);
1362 |
1363 | // indicate that we are transmitting
1364 | twi_transmitting = 1;
1365 |
1366 | // set address of targeted slave
1367 | txAddress = address;
1368 |
1369 | // reset tx buffer iterator vars
1370 | txBufferIndex = 0;
1371 | txBufferLength = 0;
1372 | }
1373 |
1374 | uint8_t TwoWire::endTransmission(uint16_t timeout) {
1375 | // transmit buffer (blocking)
1376 | //int8_t ret =
1377 | twi_cbendTransmissionDone = NULL;
1378 | twi_writeTo(txAddress, txBuffer, txBufferLength, 1);
1379 | int8_t ret = twii_WaitForDone(timeout);
1380 |
1381 | // reset tx buffer iterator vars
1382 | txBufferIndex = 0;
1383 | txBufferLength = 0;
1384 |
1385 | // indicate that we are done transmitting
1386 | // twi_transmitting = 0;
1387 | return ret;
1388 | }
1389 |
1390 | void TwoWire::nbendTransmission(void (*function)(int)) {
1391 | twi_cbendTransmissionDone = function;
1392 | twi_writeTo(txAddress, txBuffer, txBufferLength, 1);
1393 | return;
1394 | }
1395 |
1396 | void TwoWire::send(uint8_t data) {
1397 | if (twi_transmitting) {
1398 | // in master transmitter mode
1399 | // don't bother if buffer is full
1400 | if (txBufferLength >= NBWIRE_BUFFER_LENGTH) {
1401 | return;
1402 | }
1403 |
1404 | // put byte in tx buffer
1405 | txBuffer[txBufferIndex] = data;
1406 | ++txBufferIndex;
1407 |
1408 | // update amount in buffer
1409 | txBufferLength = txBufferIndex;
1410 | } else {
1411 | // in slave send mode
1412 | // reply to master
1413 | //twi_transmit(&data, 1);
1414 | }
1415 | }
1416 |
1417 | uint8_t TwoWire::receive(void) {
1418 | // default to returning null char
1419 | // for people using with char strings
1420 | uint8_t value = 0;
1421 |
1422 | // get each successive byte on each call
1423 | if (rxBufferIndex < rxBufferLength) {
1424 | value = rxBuffer[rxBufferIndex];
1425 | ++rxBufferIndex;
1426 | }
1427 |
1428 | return value;
1429 | }
1430 |
1431 | uint8_t TwoWire::requestFrom(uint8_t address, int quantity, uint16_t timeout) {
1432 | // clamp to buffer length
1433 | if (quantity > NBWIRE_BUFFER_LENGTH) {
1434 | quantity = NBWIRE_BUFFER_LENGTH;
1435 | }
1436 |
1437 | // perform blocking read into buffer
1438 | twi_cbreadFromDone = NULL;
1439 | twi_readFrom(address, rxBuffer, quantity);
1440 | uint8_t read = twii_WaitForDone(timeout);
1441 |
1442 | // set rx buffer iterator vars
1443 | rxBufferIndex = 0;
1444 | rxBufferLength = read;
1445 |
1446 | return read;
1447 | }
1448 |
1449 | void TwoWire::nbrequestFrom(uint8_t address, int quantity, void (*function)(int)) {
1450 | // clamp to buffer length
1451 | if (quantity > NBWIRE_BUFFER_LENGTH) {
1452 | quantity = NBWIRE_BUFFER_LENGTH;
1453 | }
1454 |
1455 | // perform blocking read into buffer
1456 | twi_cbreadFromDone = function;
1457 | twi_readFrom(address, rxBuffer, quantity);
1458 | //uint8_t read = twii_WaitForDone();
1459 |
1460 | // set rx buffer iterator vars
1461 | //rxBufferIndex = 0;
1462 | //rxBufferLength = read;
1463 |
1464 | rxBufferIndex = 0;
1465 | rxBufferLength = quantity; // this is a hack
1466 |
1467 | return; //read;
1468 | }
1469 |
1470 | uint8_t TwoWire::available(void) {
1471 | return rxBufferLength - rxBufferIndex;
1472 | }
1473 |
1474 | #endif
1475 |
--------------------------------------------------------------------------------
/lib/I2Cdev/I2Cdev.h:
--------------------------------------------------------------------------------
1 | // I2Cdev library collection - Main I2C device class header file
2 | // Abstracts bit and byte I2C R/W functions into a convenient class
3 | // 2013-06-05 by Jeff Rowberg
4 | //
5 | // Changelog:
6 | // 2020-01-20 - hardija : complete support for Teensy 3.x
7 | // 2015-10-30 - simondlevy : support i2c_t3 for Teensy3.1
8 | // 2013-05-06 - add Francesco Ferrara's Fastwire v0.24 implementation with small modifications
9 | // 2013-05-05 - fix issue with writing bit values to words (Sasquatch/Farzanegan)
10 | // 2012-06-09 - fix major issue with reading > 32 bytes at a time with Arduino Wire
11 | // - add compiler warnings when using outdated or IDE or limited I2Cdev implementation
12 | // 2011-11-01 - fix write*Bits mask calculation (thanks sasquatch @ Arduino forums)
13 | // 2011-10-03 - added automatic Arduino version detection for ease of use
14 | // 2011-10-02 - added Gene Knight's NBWire TwoWire class implementation with small modifications
15 | // 2011-08-31 - added support for Arduino 1.0 Wire library (methods are different from 0.x)
16 | // 2011-08-03 - added optional timeout parameter to read* methods to easily change from default
17 | // 2011-08-02 - added support for 16-bit registers
18 | // - fixed incorrect Doxygen comments on some methods
19 | // - added timeout value for read operations (thanks mem @ Arduino forums)
20 | // 2011-07-30 - changed read/write function structures to return success or byte counts
21 | // - made all methods static for multi-device memory savings
22 | // 2011-07-28 - initial release
23 |
24 | /* ============================================
25 | I2Cdev device library code is placed under the MIT license
26 | Copyright (c) 2013 Jeff Rowberg
27 |
28 | Permission is hereby granted, free of charge, to any person obtaining a copy
29 | of this software and associated documentation files (the "Software"), to deal
30 | in the Software without restriction, including without limitation the rights
31 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32 | copies of the Software, and to permit persons to whom the Software is
33 | furnished to do so, subject to the following conditions:
34 |
35 | The above copyright notice and this permission notice shall be included in
36 | all copies or substantial portions of the Software.
37 |
38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44 | THE SOFTWARE.
45 | ===============================================
46 | */
47 |
48 | #ifndef _I2CDEV_H_
49 | #define _I2CDEV_H_
50 |
51 | // -----------------------------------------------------------------------------
52 | // I2C interface implementation setting
53 | // -----------------------------------------------------------------------------
54 | #ifndef I2CDEV_IMPLEMENTATION
55 | #define I2CDEV_IMPLEMENTATION I2CDEV_ARDUINO_WIRE
56 | //#define I2CDEV_IMPLEMENTATION I2CDEV_TEENSY_3X_WIRE
57 | //#define I2CDEV_IMPLEMENTATION I2CDEV_BUILTIN_SBWIRE
58 | //#define I2CDEV_IMPLEMENTATION I2CDEV_BUILTIN_FASTWIRE
59 | #endif // I2CDEV_IMPLEMENTATION
60 |
61 | // comment this out if you are using a non-optimal IDE/implementation setting
62 | // but want the compiler to shut up about it
63 | #define I2CDEV_IMPLEMENTATION_WARNINGS
64 |
65 | // -----------------------------------------------------------------------------
66 | // I2C interface implementation options
67 | // -----------------------------------------------------------------------------
68 | #define I2CDEV_ARDUINO_WIRE 1 // Wire object from Arduino
69 | #define I2CDEV_BUILTIN_NBWIRE 2 // Tweaked Wire object from Gene Knight's NBWire project
70 | // ^^^ NBWire implementation is still buggy w/some interrupts!
71 | #define I2CDEV_BUILTIN_FASTWIRE 3 // FastWire object from Francesco Ferrara's project
72 | #define I2CDEV_I2CMASTER_LIBRARY 4 // I2C object from DSSCircuits I2C-Master Library at https://github.com/DSSCircuits/I2C-Master-Library
73 | #define I2CDEV_BUILTIN_SBWIRE 5 // I2C object from Shuning (Steve) Bian's SBWire Library at https://github.com/freespace/SBWire
74 | #define I2CDEV_TEENSY_3X_WIRE 6 // Teensy 3.x support using i2c_t3 library
75 |
76 | // -----------------------------------------------------------------------------
77 | // Arduino-style "Serial.print" debug constant (uncomment to enable)
78 | // -----------------------------------------------------------------------------
79 | //#define I2CDEV_SERIAL_DEBUG
80 |
81 | #ifdef ARDUINO
82 | #if ARDUINO < 100
83 | #include "WProgram.h"
84 | #else
85 | #include "Arduino.h"
86 | #endif
87 | #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
88 | #include
89 | #endif
90 | #if I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE
91 | #include
92 | #endif
93 | #if I2CDEV_IMPLEMENTATION == I2CDEV_I2CMASTER_LIBRARY
94 | #include
95 | #endif
96 | #if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE
97 | #include "SBWire.h"
98 | #endif
99 | #endif
100 |
101 | #ifdef SPARK
102 | #include
103 | #define ARDUINO 101
104 | #endif
105 |
106 |
107 | // 1000ms default read timeout (modify with "I2Cdev::readTimeout = [ms];")
108 | #define I2CDEV_DEFAULT_READ_TIMEOUT 1000
109 |
110 | class I2Cdev {
111 | public:
112 | I2Cdev();
113 |
114 | static int8_t readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
115 | static int8_t readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
116 | static int8_t readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
117 | static int8_t readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
118 | static int8_t readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
119 | static int8_t readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
120 | static int8_t readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
121 | static int8_t readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
122 |
123 | static bool writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data);
124 | static bool writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data);
125 | static bool writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data);
126 | static bool writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data);
127 | static bool writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data);
128 | static bool writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data);
129 | static bool writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data);
130 | static bool writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data);
131 |
132 | static uint16_t readTimeout;
133 | };
134 |
135 | #if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
136 | //////////////////////
137 | // FastWire 0.24
138 | // This is a library to help faster programs to read I2C devices.
139 | // Copyright(C) 2012
140 | // Francesco Ferrara
141 | //////////////////////
142 |
143 | /* Master */
144 | #define TW_START 0x08
145 | #define TW_REP_START 0x10
146 |
147 | /* Master Transmitter */
148 | #define TW_MT_SLA_ACK 0x18
149 | #define TW_MT_SLA_NACK 0x20
150 | #define TW_MT_DATA_ACK 0x28
151 | #define TW_MT_DATA_NACK 0x30
152 | #define TW_MT_ARB_LOST 0x38
153 |
154 | /* Master Receiver */
155 | #define TW_MR_ARB_LOST 0x38
156 | #define TW_MR_SLA_ACK 0x40
157 | #define TW_MR_SLA_NACK 0x48
158 | #define TW_MR_DATA_ACK 0x50
159 | #define TW_MR_DATA_NACK 0x58
160 |
161 | #define TW_OK 0
162 | #define TW_ERROR 1
163 |
164 | class Fastwire {
165 | private:
166 | static boolean waitInt();
167 |
168 | public:
169 | static void setup(int khz, boolean pullup);
170 | static byte beginTransmission(byte device);
171 | static byte write(byte value);
172 | static byte writeBuf(byte device, byte address, byte *data, byte num);
173 | static byte readBuf(byte device, byte address, byte *data, byte num);
174 | static void reset();
175 | static byte stop();
176 | };
177 | #endif
178 |
179 | #if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
180 | // NBWire implementation based heavily on code by Gene Knight
181 | // Originally posted on the Arduino forum at http://arduino.cc/forum/index.php/topic,70705.0.html
182 | // Originally offered to the i2cdevlib project at http://arduino.cc/forum/index.php/topic,68210.30.html
183 |
184 | #define NBWIRE_BUFFER_LENGTH 32
185 |
186 | class TwoWire {
187 | private:
188 | static uint8_t rxBuffer[];
189 | static uint8_t rxBufferIndex;
190 | static uint8_t rxBufferLength;
191 |
192 | static uint8_t txAddress;
193 | static uint8_t txBuffer[];
194 | static uint8_t txBufferIndex;
195 | static uint8_t txBufferLength;
196 |
197 | // static uint8_t transmitting;
198 | static void (*user_onRequest)(void);
199 | static void (*user_onReceive)(int);
200 | static void onRequestService(void);
201 | static void onReceiveService(uint8_t*, int);
202 |
203 | public:
204 | TwoWire();
205 | void begin();
206 | void begin(uint8_t);
207 | void begin(int);
208 | void beginTransmission(uint8_t);
209 | //void beginTransmission(int);
210 | uint8_t endTransmission(uint16_t timeout=0);
211 | void nbendTransmission(void (*function)(int)) ;
212 | uint8_t requestFrom(uint8_t, int, uint16_t timeout=0);
213 | //uint8_t requestFrom(int, int);
214 | void nbrequestFrom(uint8_t, int, void (*function)(int));
215 | void send(uint8_t);
216 | void send(uint8_t*, uint8_t);
217 | //void send(int);
218 | void send(char*);
219 | uint8_t available(void);
220 | uint8_t receive(void);
221 | void onReceive(void (*)(int));
222 | void onRequest(void (*)(void));
223 | };
224 |
225 | #define TWI_READY 0
226 | #define TWI_MRX 1
227 | #define TWI_MTX 2
228 | #define TWI_SRX 3
229 | #define TWI_STX 4
230 |
231 | #define TW_WRITE 0
232 | #define TW_READ 1
233 |
234 | #define TW_MT_SLA_NACK 0x20
235 | #define TW_MT_DATA_NACK 0x30
236 |
237 | #define CPU_FREQ 16000000L
238 | #define TWI_FREQ 100000L
239 | #define TWI_BUFFER_LENGTH 32
240 |
241 | /* TWI Status is in TWSR, in the top 5 bits: TWS7 - TWS3 */
242 |
243 | #define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|_BV(TWS3))
244 | #define TW_STATUS (TWSR & TW_STATUS_MASK)
245 | #define TW_START 0x08
246 | #define TW_REP_START 0x10
247 | #define TW_MT_SLA_ACK 0x18
248 | #define TW_MT_SLA_NACK 0x20
249 | #define TW_MT_DATA_ACK 0x28
250 | #define TW_MT_DATA_NACK 0x30
251 | #define TW_MT_ARB_LOST 0x38
252 | #define TW_MR_ARB_LOST 0x38
253 | #define TW_MR_SLA_ACK 0x40
254 | #define TW_MR_SLA_NACK 0x48
255 | #define TW_MR_DATA_ACK 0x50
256 | #define TW_MR_DATA_NACK 0x58
257 | #define TW_ST_SLA_ACK 0xA8
258 | #define TW_ST_ARB_LOST_SLA_ACK 0xB0
259 | #define TW_ST_DATA_ACK 0xB8
260 | #define TW_ST_DATA_NACK 0xC0
261 | #define TW_ST_LAST_DATA 0xC8
262 | #define TW_SR_SLA_ACK 0x60
263 | #define TW_SR_ARB_LOST_SLA_ACK 0x68
264 | #define TW_SR_GCALL_ACK 0x70
265 | #define TW_SR_ARB_LOST_GCALL_ACK 0x78
266 | #define TW_SR_DATA_ACK 0x80
267 | #define TW_SR_DATA_NACK 0x88
268 | #define TW_SR_GCALL_DATA_ACK 0x90
269 | #define TW_SR_GCALL_DATA_NACK 0x98
270 | #define TW_SR_STOP 0xA0
271 | #define TW_NO_INFO 0xF8
272 | #define TW_BUS_ERROR 0x00
273 |
274 | //#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
275 | //#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))
276 |
277 | #ifndef sbi // set bit
278 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
279 | #endif // sbi
280 |
281 | #ifndef cbi // clear bit
282 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
283 | #endif // cbi
284 |
285 | extern TwoWire Wire;
286 |
287 | #endif // I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
288 |
289 | #endif /* _I2CDEV_H_ */
290 |
--------------------------------------------------------------------------------
/lib/I2Cdev/keywords.txt:
--------------------------------------------------------------------------------
1 | #######################################
2 | # Syntax Coloring Map For I2Cdev
3 | #######################################
4 |
5 | #######################################
6 | # Datatypes (KEYWORD1)
7 | #######################################
8 | I2Cdev KEYWORD1
9 |
10 | #######################################
11 | # Methods and Functions (KEYWORD2)
12 | #######################################
13 |
14 | readBit KEYWORD2
15 | readBitW KEYWORD2
16 | readBits KEYWORD2
17 | readBitsW KEYWORD2
18 | readByte KEYWORD2
19 | readBytes KEYWORD2
20 | readWord KEYWORD2
21 | readWords KEYWORD2
22 | writeBit KEYWORD2
23 | writeBitW KEYWORD2
24 | writeBits KEYWORD2
25 | writeBitsW KEYWORD2
26 | writeByte KEYWORD2
27 | writeBytes KEYWORD2
28 | writeWord KEYWORD2
29 | writeWords KEYWORD2
30 |
31 | #######################################
32 | # Instances (KEYWORD2)
33 | #######################################
34 |
35 | #######################################
36 | # Constants (LITERAL1)
37 | #######################################
38 |
39 |
--------------------------------------------------------------------------------
/lib/I2Cdev/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "I2Cdevlib-Core",
3 | "keywords": "i2cdevlib, i2c",
4 | "description": "The I2C Device Library (I2Cdevlib) is a collection of uniform and well-documented classes to provide simple and intuitive interfaces to I2C devices.",
5 | "include": "Arduino/I2Cdev",
6 | "repository":
7 | {
8 | "type": "git",
9 | "url": "https://github.com/jrowberg/i2cdevlib.git"
10 | },
11 | "frameworks": "arduino",
12 | "platforms": "atmelavr",
13 | "dependencies": [
14 | {
15 | "name": "Wire"
16 | }
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/lib/KnobHelper/KnobHelper.cpp:
--------------------------------------------------------------------------------
1 | #include "KnobHelper.h"
2 | AiEsp32RotaryEncoder rotary = AiEsp32RotaryEncoder(ROTARY_ENCODER_A_PIN, ROTARY_ENCODER_B_PIN, ROTARY_ENCODER_BUTTON_PIN, ROTARY_ENCODER_VCC_PIN);
3 |
4 | void KnobHelperClass::read() {
5 | preferences.begin("knob", true);
6 | host = preferences.getString("host");
7 | port = preferences.getInt("port", 3333);
8 | preferences.end();
9 | }
10 |
11 | void KnobHelperClass::write() {
12 | preferences.begin("knob", false);
13 | preferences.putString("host", host);
14 | preferences.putInt("port", port);
15 | preferences.end();
16 | }
17 |
18 | void KnobHelperClass::setup() {
19 | unsigned long setupStartTime = millis();
20 | Serial.println("Setup Knob helper");
21 |
22 | read();
23 |
24 | // initialize rotary encoder
25 | rotary.begin();
26 | rotary.setup([] { rotary.readEncoder_ISR(); });
27 | rotary.setBoundaries(0, 100, false);
28 |
29 | setupDuration = millis() - setupStartTime;
30 | Serial.print("Setup knob helper took ");
31 | Serial.println(setupDuration);
32 | }
33 |
34 | void KnobHelperClass::loop() {
35 | readValues();
36 | sendValues();
37 | }
38 |
39 | void KnobHelperClass::sleep() {
40 | }
41 |
42 | void KnobHelperClass::readValues() {
43 | prevValue = value;
44 | pressed = false;
45 |
46 | // first lets handle rotary encoder button click
47 | if (rotary.currentButtonState() == BUT_RELEASED) {
48 | pressed = true;
49 | Serial.println("Button Pressed");
50 | }
51 |
52 | // lets see if anything changed
53 | // optionally we can ignore whenever there is no change
54 | int16_t encoderDelta = rotary.encoderChanged();
55 | if (encoderDelta == 0) return;
56 |
57 | // if value is changed compared to our last read
58 | if (encoderDelta != 0) {
59 | // now we need current value
60 | value = rotary.readEncoder();
61 |
62 | Serial.print("Value: ");
63 | Serial.println(value);
64 | }
65 | }
66 |
67 | void KnobHelperClass::sendValues() {
68 | if (value == prevValue && !pressed) return;
69 | if (host.length() == 0) return;
70 | if (!WiFiHelper.connect()) return;
71 | unsigned long requestStartTime = millis();
72 |
73 | StaticJsonDocument<32> doc;
74 |
75 | udp.beginPacket(host.c_str(), port);
76 |
77 | doc["value"] = value;
78 | doc["pressed"] = pressed;
79 | serializeJson(doc, udp);
80 |
81 | udp.println();
82 | udp.endPacket();
83 |
84 | requestDuration = millis() - requestStartTime;
85 | Serial.print("Send UDP request ");
86 | Serial.println(requestDuration);
87 | }
88 |
89 | void KnobHelperClass::server() {
90 | Serial.println("Setup Knob server");
91 |
92 | WebServerHelper.server.on("/api/knob", HTTP_GET, [this](AsyncWebServerRequest *request) {
93 | int args = request->args();
94 |
95 | if (args > 0) {
96 | request->send(200, "text/plain", "message received");
97 | Serial.println("Update knob settings");
98 |
99 | if (request->hasArg("host")) host = request->arg("host");
100 | if (request->hasArg("port")) port = request->arg("port").toInt();
101 |
102 | write();
103 |
104 | } else {
105 | AsyncJsonResponse *response = new AsyncJsonResponse();
106 | response->addHeader("Server", "ESP Async Web Server");
107 | JsonVariant &root = response->getRoot();
108 |
109 | root["value"] = value;
110 | root["setupDuration"] = setupDuration;
111 | root["requestDuration"] = requestDuration;
112 |
113 | root["host"] = host;
114 | root["port"] = port;
115 |
116 | response->setLength();
117 | request->send(response);
118 | }
119 | });
120 | }
121 |
122 | KnobHelperClass KnobHelper;
123 |
--------------------------------------------------------------------------------
/lib/KnobHelper/KnobHelper.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef KnobHelper_h
3 | #define KnobHelper_h
4 |
5 | #include "AiEsp32RotaryEncoder.h"
6 | #include "ArduinoJson.h"
7 | #include "AsyncJson.h"
8 | #include "I2Cdev.h"
9 | #include "MPU6050.h"
10 | #include "Preferences.h"
11 | #include "WebServerHelper.h"
12 | #include "WiFiHelper.h"
13 | #include "WiFiUdp.h"
14 | #include "Wire.h"
15 |
16 | /*
17 | connecting Rotary encoder
18 | CLK (A pin) - to any microcontroler intput pin with interrupt -> in this example pin 32
19 | DT (B pin) - to any microcontroler intput pin with interrupt -> in this example pin 21
20 | SW (button pin) - to any microcontroler intput pin -> in this example pin 25
21 | VCC - to microcontroler VCC (then set ROTARY_ENCODER_VCC_PIN -1) or in this example pin 25
22 | GND - to microcontroler GND
23 | */
24 | #define ROTARY_ENCODER_A_PIN 15
25 | #define ROTARY_ENCODER_B_PIN 4
26 | #define ROTARY_ENCODER_BUTTON_PIN 13
27 | #define ROTARY_ENCODER_VCC_PIN -1 /*put -1 of Rotary encoder Vcc is connected directly to 3,3V; else you can use declared output pin for powering rotary encoder */
28 | #define ROTARY_ENCODER_TEST_LIMITS = 2;
29 |
30 | class KnobHelperClass {
31 | private:
32 | WiFiUDP udp;
33 | Preferences preferences;
34 |
35 | String host;
36 | int32_t port;
37 |
38 | void read();
39 | void write();
40 |
41 | void readValues();
42 | void sendValues();
43 |
44 | unsigned long requestDuration;
45 | unsigned long setupDuration;
46 |
47 | int threshold;
48 | int testlimits = 2;
49 |
50 | public:
51 | int16_t value;
52 | int16_t prevValue;
53 | bool pressed;
54 |
55 | void setup();
56 | void server();
57 | void loop();
58 | void sleep();
59 | };
60 |
61 | extern KnobHelperClass KnobHelper;
62 |
63 | #endif
--------------------------------------------------------------------------------
/lib/KnobHelper/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "KnobHelper",
3 | "version": "1.0.0"
4 | }
--------------------------------------------------------------------------------
/lib/LedHelper/LedHelper.cpp:
--------------------------------------------------------------------------------
1 | #include "LedHelper.h"
2 |
3 | void LedHelperClass::read() {
4 | preferences.begin("Led", true);
5 | mode = preferences.getInt("mode", 0);
6 | brightness = preferences.getInt("brightness", 100);
7 | color = preferences.getInt("color", 0x808000);
8 | minValue = preferences.getInt("minValue", 25);
9 | maxValue = preferences.getInt("maxValue", 350);
10 | initHue = preferences.getInt("initHue", 96);
11 | endHue = preferences.getInt("endHue", 0);
12 | deltaHue = preferences.getInt("deltaHue", -4);
13 | preferences.end();
14 | }
15 |
16 | void LedHelperClass::write() {
17 | preferences.begin("Led", false);
18 | preferences.putInt("mode", mode);
19 | preferences.putInt("brightness", brightness);
20 | preferences.putInt("color", color);
21 | preferences.putInt("minValue", minValue);
22 | preferences.putInt("maxValue", maxValue);
23 | preferences.putInt("initHue", initHue);
24 | preferences.putInt("deltaHue", deltaHue);
25 | preferences.end();
26 | }
27 |
28 | void LedHelperClass::setup() {
29 | read();
30 | value = 0;
31 | displayValue = 0;
32 | FastLED.addLeds(leds, NUM_LEDS);
33 | FastLED.setBrightness(brightness);
34 | }
35 |
36 | int LedHelperClass::valueToNumLed() {
37 | int numLedsToLight = map(displayValue, minValue, maxValue, 0, NUM_LEDS);
38 | numLedsToLight = max(0, min(numLedsToLight, NUM_LEDS));
39 | return numLedsToLight;
40 | }
41 |
42 | int LedHelperClass::valueToHue() {
43 | int hue = map(displayValue, minValue, maxValue, initHue, endHue);
44 |
45 | return hue;
46 | }
47 |
48 | void LedHelperClass::fillColorsFromPalette(uint8_t colorIndex) {
49 | uint8_t brightness = 255;
50 |
51 | for (int i = 0; i < NUM_LEDS; i++) {
52 | leds[i] = ColorFromPalette(currentPalette, colorIndex, brightness, currentBlending);
53 | // TODO adjustable
54 | colorIndex += 3;
55 | }
56 | }
57 |
58 | bool LedHelperClass::animate() {
59 | switch (animation) {
60 | case 1:
61 | currentPalette = RainbowColors_p;
62 | currentBlending = LINEARBLEND;
63 | break;
64 | case 2:
65 | currentPalette = RainbowStripeColors_p;
66 | currentBlending = NOBLEND;
67 | break;
68 | case 3:
69 | currentPalette = CloudColors_p;
70 | currentBlending = LINEARBLEND;
71 | break;
72 | case 4:
73 | currentPalette = PartyColors_p;
74 | currentBlending = LINEARBLEND;
75 | break;
76 | case 5:
77 | currentPalette = OceanColors_p;
78 | currentBlending = LINEARBLEND;
79 | break;
80 | case 6:
81 | currentPalette = HeatColors_p;
82 | currentBlending = LINEARBLEND;
83 | break;
84 | case 7:
85 | currentPalette = ForestColors_p;
86 | currentBlending = LINEARBLEND;
87 | break;
88 | case 8:
89 | currentPalette = LavaColors_p;
90 | currentBlending = LINEARBLEND;
91 | break;
92 |
93 | default:
94 | return false;
95 | }
96 |
97 | static uint8_t startIndex = 0;
98 | // TODO adjustable
99 | startIndex = startIndex + 1; /* motion speed */
100 |
101 | fillColorsFromPalette(startIndex);
102 |
103 | FastLED.show();
104 | FastLED.delay(1000 / 100);
105 |
106 | return true;
107 | }
108 |
109 | void LedHelperClass::loop() {
110 | value = max(0, min(maxValue, value));
111 |
112 | if (test > 0) {
113 | if (test == 1) {
114 | value = maxValue;
115 | test++;
116 | } else {
117 | value = 0;
118 | test = 0;
119 | }
120 | }
121 |
122 | if (animate()) return;
123 |
124 | int startValue = displayValue;
125 | int range = abs(displayValue - value);
126 | for (int i = 0; i < range; i++) {
127 | fract8 f = (256 * i) / range;
128 | fract8 easeOutVal = ease8InOutQuad(f);
129 | displayValue = lerp16by8(startValue, value, easeOutVal);
130 |
131 | FastLED.clear();
132 | switch (mode) {
133 | case 0: {
134 | fill_rainbow(leds, valueToNumLed(), initHue, deltaHue);
135 | break;
136 | }
137 | case 1: {
138 | fill_solid(leds, valueToNumLed(), color);
139 | break;
140 | }
141 | case 2: {
142 | fill_solid(leds, NUM_LEDS, displayValue < minValue ? CHSV(0, 0, 0) : CHSV(valueToHue(), 255, 255));
143 | break;
144 | }
145 | default: {
146 | break;
147 | }
148 | }
149 |
150 | if (brightness == -1) {
151 | FastLED.setBrightness(map(displayValue, minValue, maxValue, 0, 255));
152 | } else {
153 | FastLED.setBrightness(brightness);
154 | }
155 |
156 | FastLED.show();
157 | FastLED.delay(5);
158 | }
159 |
160 | displayValue = value;
161 | }
162 |
163 | void LedHelperClass::sleep() {
164 | }
165 |
166 | void LedHelperClass::server() {
167 | Serial.println("Setup Led server");
168 |
169 | WebServerHelper.server.on("/api/led", HTTP_GET, [this](AsyncWebServerRequest *request) {
170 | int args = request->args();
171 |
172 | if (args > 0) {
173 | request->send(200, "text/plain", "message received");
174 | Serial.println("Update Led settings");
175 |
176 | if (request->hasArg("value")) value = request->arg("value").toInt();
177 | if (request->hasArg("brightness")) brightness = request->arg("brightness").toInt();
178 | if (request->hasArg("mode")) mode = request->arg("mode").toInt();
179 | if (request->hasArg("color")) color = request->arg("color").toInt();
180 | if (request->hasArg("min")) minValue = request->arg("min").toInt();
181 | if (request->hasArg("max")) maxValue = request->arg("max").toInt();
182 | if (request->hasArg("initHue")) initHue = request->arg("initHue").toInt();
183 | if (request->hasArg("deltaHue")) deltaHue = request->arg("deltaHue").toInt();
184 | if (request->hasArg("endHue")) endHue = request->arg("endHue").toInt();
185 | if (request->hasArg("animation")) animation = request->arg("animation").toInt();
186 |
187 | test = 1;
188 | write();
189 |
190 | } else {
191 | AsyncJsonResponse *response = new AsyncJsonResponse();
192 | response->addHeader("Server", "ESP Async Web Server");
193 | JsonVariant &root = response->getRoot();
194 |
195 | root["value"] = value;
196 | root["brightness"] = brightness;
197 | root["mode"] = mode;
198 | root["color"] = color;
199 | root["min"] = minValue;
200 | root["max"] = maxValue;
201 | root["initHue"] = initHue;
202 | root["deltaHue"] = deltaHue;
203 | root["endHue"] = endHue;
204 | root["animation"] = animation;
205 |
206 | response->setLength();
207 | request->send(response);
208 | }
209 | });
210 | }
211 |
212 | LedHelperClass LedHelper;
213 |
--------------------------------------------------------------------------------
/lib/LedHelper/LedHelper.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef LedHelper_h
3 | #define LedHelper_h
4 |
5 | #include "Arduino.h"
6 | #include "ArduinoJson.h"
7 | #include "AsyncJson.h"
8 | #include "FastLED.h"
9 | #include "Preferences.h"
10 | #include "WebServerHelper.h"
11 |
12 | #define DATA_PIN 13
13 | #define NUM_LEDS 24
14 | #define LED_TYPE WS2812
15 | #define COLOR_ORDER GRB
16 |
17 | class LedHelperClass {
18 | private:
19 | Preferences preferences;
20 | CRGB leds[NUM_LEDS];
21 |
22 | int mode;
23 | int color;
24 | int brightness;
25 | int initHue;
26 | int deltaHue;
27 | int endHue;
28 | int displayValue;
29 |
30 | void read();
31 | void write();
32 |
33 | int valueToNumLed();
34 | int valueToHue();
35 |
36 | bool animate();
37 | void fillColorsFromPalette(uint8_t colorIndex);
38 |
39 | CRGBPalette16 currentPalette;
40 | TBlendType currentBlending;
41 |
42 | public:
43 | int value;
44 | int minValue;
45 | int maxValue;
46 | int test;
47 | int animation;
48 |
49 | void setup();
50 | void server();
51 | void loop();
52 | void sleep();
53 | };
54 |
55 | extern LedHelperClass LedHelper;
56 |
57 | #endif
--------------------------------------------------------------------------------
/lib/LedHelper/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "LedHelper",
3 | "version": "1.0.0"
4 | }
--------------------------------------------------------------------------------
/lib/MPU6050/MPU6050.h:
--------------------------------------------------------------------------------
1 | // I2Cdev library collection - MPU6050 I2C device class
2 | // Based on InvenSense MPU-6050 register map document rev. 2.0, 5/19/2011 (RM-MPU-6000A-00)
3 | // 10/3/2011 by Jeff Rowberg
4 | // Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
5 | //
6 | // Changelog:
7 | // ... - ongoing debug release
8 |
9 | // NOTE: THIS IS ONLY A PARIAL RELEASE. THIS DEVICE CLASS IS CURRENTLY UNDERGOING ACTIVE
10 | // DEVELOPMENT AND IS STILL MISSING SOME IMPORTANT FEATURES. PLEASE KEEP THIS IN MIND IF
11 | // YOU DECIDE TO USE THIS PARTICULAR CODE FOR ANYTHING.
12 |
13 | /* ============================================
14 | I2Cdev device library code is placed under the MIT license
15 | Copyright (c) 2012 Jeff Rowberg
16 |
17 | Permission is hereby granted, free of charge, to any person obtaining a copy
18 | of this software and associated documentation files (the "Software"), to deal
19 | in the Software without restriction, including without limitation the rights
20 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21 | copies of the Software, and to permit persons to whom the Software is
22 | furnished to do so, subject to the following conditions:
23 |
24 | The above copyright notice and this permission notice shall be included in
25 | all copies or substantial portions of the Software.
26 |
27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33 | THE SOFTWARE.
34 | ===============================================
35 | */
36 |
37 | #ifndef _MPU6050_H_
38 | #define _MPU6050_H_
39 |
40 | #include "I2Cdev.h"
41 |
42 | // supporting link: http://forum.arduino.cc/index.php?&topic=143444.msg1079517#msg1079517
43 | // also: http://forum.arduino.cc/index.php?&topic=141571.msg1062899#msg1062899s
44 |
45 | #ifdef __AVR__
46 | #include
47 | #else
48 | //#define PROGMEM /* empty */
49 | //#define pgm_read_byte(x) (*(x))
50 | //#define pgm_read_word(x) (*(x))
51 | //#define pgm_read_float(x) (*(x))
52 | //#define PSTR(STR) STR
53 | #endif
54 |
55 |
56 | #define MPU6050_ADDRESS_AD0_LOW 0x68 // address pin low (GND), default for InvenSense evaluation board
57 | #define MPU6050_ADDRESS_AD0_HIGH 0x69 // address pin high (VCC)
58 | #define MPU6050_DEFAULT_ADDRESS MPU6050_ADDRESS_AD0_LOW
59 |
60 | #define MPU6050_RA_XG_OFFS_TC 0x00 //[7] PWR_MODE, [6:1] XG_OFFS_TC, [0] OTP_BNK_VLD
61 | #define MPU6050_RA_YG_OFFS_TC 0x01 //[7] PWR_MODE, [6:1] YG_OFFS_TC, [0] OTP_BNK_VLD
62 | #define MPU6050_RA_ZG_OFFS_TC 0x02 //[7] PWR_MODE, [6:1] ZG_OFFS_TC, [0] OTP_BNK_VLD
63 | #define MPU6050_RA_X_FINE_GAIN 0x03 //[7:0] X_FINE_GAIN
64 | #define MPU6050_RA_Y_FINE_GAIN 0x04 //[7:0] Y_FINE_GAIN
65 | #define MPU6050_RA_Z_FINE_GAIN 0x05 //[7:0] Z_FINE_GAIN
66 | #define MPU6050_RA_XA_OFFS_H 0x06 //[15:0] XA_OFFS
67 | #define MPU6050_RA_XA_OFFS_L_TC 0x07
68 | #define MPU6050_RA_YA_OFFS_H 0x08 //[15:0] YA_OFFS
69 | #define MPU6050_RA_YA_OFFS_L_TC 0x09
70 | #define MPU6050_RA_ZA_OFFS_H 0x0A //[15:0] ZA_OFFS
71 | #define MPU6050_RA_ZA_OFFS_L_TC 0x0B
72 | #define MPU6050_RA_SELF_TEST_X 0x0D //[7:5] XA_TEST[4-2], [4:0] XG_TEST[4-0]
73 | #define MPU6050_RA_SELF_TEST_Y 0x0E //[7:5] YA_TEST[4-2], [4:0] YG_TEST[4-0]
74 | #define MPU6050_RA_SELF_TEST_Z 0x0F //[7:5] ZA_TEST[4-2], [4:0] ZG_TEST[4-0]
75 | #define MPU6050_RA_SELF_TEST_A 0x10 //[5:4] XA_TEST[1-0], [3:2] YA_TEST[1-0], [1:0] ZA_TEST[1-0]
76 | #define MPU6050_RA_XG_OFFS_USRH 0x13 //[15:0] XG_OFFS_USR
77 | #define MPU6050_RA_XG_OFFS_USRL 0x14
78 | #define MPU6050_RA_YG_OFFS_USRH 0x15 //[15:0] YG_OFFS_USR
79 | #define MPU6050_RA_YG_OFFS_USRL 0x16
80 | #define MPU6050_RA_ZG_OFFS_USRH 0x17 //[15:0] ZG_OFFS_USR
81 | #define MPU6050_RA_ZG_OFFS_USRL 0x18
82 | #define MPU6050_RA_SMPLRT_DIV 0x19
83 | #define MPU6050_RA_CONFIG 0x1A
84 | #define MPU6050_RA_GYRO_CONFIG 0x1B
85 | #define MPU6050_RA_ACCEL_CONFIG 0x1C
86 | #define MPU6050_RA_FF_THR 0x1D
87 | #define MPU6050_RA_FF_DUR 0x1E
88 | #define MPU6050_RA_MOT_THR 0x1F
89 | #define MPU6050_RA_MOT_DUR 0x20
90 | #define MPU6050_RA_ZRMOT_THR 0x21
91 | #define MPU6050_RA_ZRMOT_DUR 0x22
92 | #define MPU6050_RA_FIFO_EN 0x23
93 | #define MPU6050_RA_I2C_MST_CTRL 0x24
94 | #define MPU6050_RA_I2C_SLV0_ADDR 0x25
95 | #define MPU6050_RA_I2C_SLV0_REG 0x26
96 | #define MPU6050_RA_I2C_SLV0_CTRL 0x27
97 | #define MPU6050_RA_I2C_SLV1_ADDR 0x28
98 | #define MPU6050_RA_I2C_SLV1_REG 0x29
99 | #define MPU6050_RA_I2C_SLV1_CTRL 0x2A
100 | #define MPU6050_RA_I2C_SLV2_ADDR 0x2B
101 | #define MPU6050_RA_I2C_SLV2_REG 0x2C
102 | #define MPU6050_RA_I2C_SLV2_CTRL 0x2D
103 | #define MPU6050_RA_I2C_SLV3_ADDR 0x2E
104 | #define MPU6050_RA_I2C_SLV3_REG 0x2F
105 | #define MPU6050_RA_I2C_SLV3_CTRL 0x30
106 | #define MPU6050_RA_I2C_SLV4_ADDR 0x31
107 | #define MPU6050_RA_I2C_SLV4_REG 0x32
108 | #define MPU6050_RA_I2C_SLV4_DO 0x33
109 | #define MPU6050_RA_I2C_SLV4_CTRL 0x34
110 | #define MPU6050_RA_I2C_SLV4_DI 0x35
111 | #define MPU6050_RA_I2C_MST_STATUS 0x36
112 | #define MPU6050_RA_INT_PIN_CFG 0x37
113 | #define MPU6050_RA_INT_ENABLE 0x38
114 | #define MPU6050_RA_DMP_INT_STATUS 0x39
115 | #define MPU6050_RA_INT_STATUS 0x3A
116 | #define MPU6050_RA_ACCEL_XOUT_H 0x3B
117 | #define MPU6050_RA_ACCEL_XOUT_L 0x3C
118 | #define MPU6050_RA_ACCEL_YOUT_H 0x3D
119 | #define MPU6050_RA_ACCEL_YOUT_L 0x3E
120 | #define MPU6050_RA_ACCEL_ZOUT_H 0x3F
121 | #define MPU6050_RA_ACCEL_ZOUT_L 0x40
122 | #define MPU6050_RA_TEMP_OUT_H 0x41
123 | #define MPU6050_RA_TEMP_OUT_L 0x42
124 | #define MPU6050_RA_GYRO_XOUT_H 0x43
125 | #define MPU6050_RA_GYRO_XOUT_L 0x44
126 | #define MPU6050_RA_GYRO_YOUT_H 0x45
127 | #define MPU6050_RA_GYRO_YOUT_L 0x46
128 | #define MPU6050_RA_GYRO_ZOUT_H 0x47
129 | #define MPU6050_RA_GYRO_ZOUT_L 0x48
130 | #define MPU6050_RA_EXT_SENS_DATA_00 0x49
131 | #define MPU6050_RA_EXT_SENS_DATA_01 0x4A
132 | #define MPU6050_RA_EXT_SENS_DATA_02 0x4B
133 | #define MPU6050_RA_EXT_SENS_DATA_03 0x4C
134 | #define MPU6050_RA_EXT_SENS_DATA_04 0x4D
135 | #define MPU6050_RA_EXT_SENS_DATA_05 0x4E
136 | #define MPU6050_RA_EXT_SENS_DATA_06 0x4F
137 | #define MPU6050_RA_EXT_SENS_DATA_07 0x50
138 | #define MPU6050_RA_EXT_SENS_DATA_08 0x51
139 | #define MPU6050_RA_EXT_SENS_DATA_09 0x52
140 | #define MPU6050_RA_EXT_SENS_DATA_10 0x53
141 | #define MPU6050_RA_EXT_SENS_DATA_11 0x54
142 | #define MPU6050_RA_EXT_SENS_DATA_12 0x55
143 | #define MPU6050_RA_EXT_SENS_DATA_13 0x56
144 | #define MPU6050_RA_EXT_SENS_DATA_14 0x57
145 | #define MPU6050_RA_EXT_SENS_DATA_15 0x58
146 | #define MPU6050_RA_EXT_SENS_DATA_16 0x59
147 | #define MPU6050_RA_EXT_SENS_DATA_17 0x5A
148 | #define MPU6050_RA_EXT_SENS_DATA_18 0x5B
149 | #define MPU6050_RA_EXT_SENS_DATA_19 0x5C
150 | #define MPU6050_RA_EXT_SENS_DATA_20 0x5D
151 | #define MPU6050_RA_EXT_SENS_DATA_21 0x5E
152 | #define MPU6050_RA_EXT_SENS_DATA_22 0x5F
153 | #define MPU6050_RA_EXT_SENS_DATA_23 0x60
154 | #define MPU6050_RA_MOT_DETECT_STATUS 0x61
155 | #define MPU6050_RA_I2C_SLV0_DO 0x63
156 | #define MPU6050_RA_I2C_SLV1_DO 0x64
157 | #define MPU6050_RA_I2C_SLV2_DO 0x65
158 | #define MPU6050_RA_I2C_SLV3_DO 0x66
159 | #define MPU6050_RA_I2C_MST_DELAY_CTRL 0x67
160 | #define MPU6050_RA_SIGNAL_PATH_RESET 0x68
161 | #define MPU6050_RA_MOT_DETECT_CTRL 0x69
162 | #define MPU6050_RA_USER_CTRL 0x6A
163 | #define MPU6050_RA_PWR_MGMT_1 0x6B
164 | #define MPU6050_RA_PWR_MGMT_2 0x6C
165 | #define MPU6050_RA_BANK_SEL 0x6D
166 | #define MPU6050_RA_MEM_START_ADDR 0x6E
167 | #define MPU6050_RA_MEM_R_W 0x6F
168 | #define MPU6050_RA_DMP_CFG_1 0x70
169 | #define MPU6050_RA_DMP_CFG_2 0x71
170 | #define MPU6050_RA_FIFO_COUNTH 0x72
171 | #define MPU6050_RA_FIFO_COUNTL 0x73
172 | #define MPU6050_RA_FIFO_R_W 0x74
173 | #define MPU6050_RA_WHO_AM_I 0x75
174 |
175 | #define MPU6050_SELF_TEST_XA_1_BIT 0x07
176 | #define MPU6050_SELF_TEST_XA_1_LENGTH 0x03
177 | #define MPU6050_SELF_TEST_XA_2_BIT 0x05
178 | #define MPU6050_SELF_TEST_XA_2_LENGTH 0x02
179 | #define MPU6050_SELF_TEST_YA_1_BIT 0x07
180 | #define MPU6050_SELF_TEST_YA_1_LENGTH 0x03
181 | #define MPU6050_SELF_TEST_YA_2_BIT 0x03
182 | #define MPU6050_SELF_TEST_YA_2_LENGTH 0x02
183 | #define MPU6050_SELF_TEST_ZA_1_BIT 0x07
184 | #define MPU6050_SELF_TEST_ZA_1_LENGTH 0x03
185 | #define MPU6050_SELF_TEST_ZA_2_BIT 0x01
186 | #define MPU6050_SELF_TEST_ZA_2_LENGTH 0x02
187 |
188 | #define MPU6050_SELF_TEST_XG_1_BIT 0x04
189 | #define MPU6050_SELF_TEST_XG_1_LENGTH 0x05
190 | #define MPU6050_SELF_TEST_YG_1_BIT 0x04
191 | #define MPU6050_SELF_TEST_YG_1_LENGTH 0x05
192 | #define MPU6050_SELF_TEST_ZG_1_BIT 0x04
193 | #define MPU6050_SELF_TEST_ZG_1_LENGTH 0x05
194 |
195 | #define MPU6050_TC_PWR_MODE_BIT 7
196 | #define MPU6050_TC_OFFSET_BIT 6
197 | #define MPU6050_TC_OFFSET_LENGTH 6
198 | #define MPU6050_TC_OTP_BNK_VLD_BIT 0
199 |
200 | #define MPU6050_VDDIO_LEVEL_VLOGIC 0
201 | #define MPU6050_VDDIO_LEVEL_VDD 1
202 |
203 | #define MPU6050_CFG_EXT_SYNC_SET_BIT 5
204 | #define MPU6050_CFG_EXT_SYNC_SET_LENGTH 3
205 | #define MPU6050_CFG_DLPF_CFG_BIT 2
206 | #define MPU6050_CFG_DLPF_CFG_LENGTH 3
207 |
208 | #define MPU6050_EXT_SYNC_DISABLED 0x0
209 | #define MPU6050_EXT_SYNC_TEMP_OUT_L 0x1
210 | #define MPU6050_EXT_SYNC_GYRO_XOUT_L 0x2
211 | #define MPU6050_EXT_SYNC_GYRO_YOUT_L 0x3
212 | #define MPU6050_EXT_SYNC_GYRO_ZOUT_L 0x4
213 | #define MPU6050_EXT_SYNC_ACCEL_XOUT_L 0x5
214 | #define MPU6050_EXT_SYNC_ACCEL_YOUT_L 0x6
215 | #define MPU6050_EXT_SYNC_ACCEL_ZOUT_L 0x7
216 |
217 | #define MPU6050_DLPF_BW_256 0x00
218 | #define MPU6050_DLPF_BW_188 0x01
219 | #define MPU6050_DLPF_BW_98 0x02
220 | #define MPU6050_DLPF_BW_42 0x03
221 | #define MPU6050_DLPF_BW_20 0x04
222 | #define MPU6050_DLPF_BW_10 0x05
223 | #define MPU6050_DLPF_BW_5 0x06
224 |
225 | #define MPU6050_GCONFIG_FS_SEL_BIT 4
226 | #define MPU6050_GCONFIG_FS_SEL_LENGTH 2
227 |
228 | #define MPU6050_GYRO_FS_250 0x00
229 | #define MPU6050_GYRO_FS_500 0x01
230 | #define MPU6050_GYRO_FS_1000 0x02
231 | #define MPU6050_GYRO_FS_2000 0x03
232 |
233 | #define MPU6050_ACONFIG_XA_ST_BIT 7
234 | #define MPU6050_ACONFIG_YA_ST_BIT 6
235 | #define MPU6050_ACONFIG_ZA_ST_BIT 5
236 | #define MPU6050_ACONFIG_AFS_SEL_BIT 4
237 | #define MPU6050_ACONFIG_AFS_SEL_LENGTH 2
238 | #define MPU6050_ACONFIG_ACCEL_HPF_BIT 2
239 | #define MPU6050_ACONFIG_ACCEL_HPF_LENGTH 3
240 |
241 | #define MPU6050_ACCEL_FS_2 0x00
242 | #define MPU6050_ACCEL_FS_4 0x01
243 | #define MPU6050_ACCEL_FS_8 0x02
244 | #define MPU6050_ACCEL_FS_16 0x03
245 |
246 | #define MPU6050_DHPF_RESET 0x00
247 | #define MPU6050_DHPF_5 0x01
248 | #define MPU6050_DHPF_2P5 0x02
249 | #define MPU6050_DHPF_1P25 0x03
250 | #define MPU6050_DHPF_0P63 0x04
251 | #define MPU6050_DHPF_HOLD 0x07
252 |
253 | #define MPU6050_TEMP_FIFO_EN_BIT 7
254 | #define MPU6050_XG_FIFO_EN_BIT 6
255 | #define MPU6050_YG_FIFO_EN_BIT 5
256 | #define MPU6050_ZG_FIFO_EN_BIT 4
257 | #define MPU6050_ACCEL_FIFO_EN_BIT 3
258 | #define MPU6050_SLV2_FIFO_EN_BIT 2
259 | #define MPU6050_SLV1_FIFO_EN_BIT 1
260 | #define MPU6050_SLV0_FIFO_EN_BIT 0
261 |
262 | #define MPU6050_MULT_MST_EN_BIT 7
263 | #define MPU6050_WAIT_FOR_ES_BIT 6
264 | #define MPU6050_SLV_3_FIFO_EN_BIT 5
265 | #define MPU6050_I2C_MST_P_NSR_BIT 4
266 | #define MPU6050_I2C_MST_CLK_BIT 3
267 | #define MPU6050_I2C_MST_CLK_LENGTH 4
268 |
269 | #define MPU6050_CLOCK_DIV_348 0x0
270 | #define MPU6050_CLOCK_DIV_333 0x1
271 | #define MPU6050_CLOCK_DIV_320 0x2
272 | #define MPU6050_CLOCK_DIV_308 0x3
273 | #define MPU6050_CLOCK_DIV_296 0x4
274 | #define MPU6050_CLOCK_DIV_286 0x5
275 | #define MPU6050_CLOCK_DIV_276 0x6
276 | #define MPU6050_CLOCK_DIV_267 0x7
277 | #define MPU6050_CLOCK_DIV_258 0x8
278 | #define MPU6050_CLOCK_DIV_500 0x9
279 | #define MPU6050_CLOCK_DIV_471 0xA
280 | #define MPU6050_CLOCK_DIV_444 0xB
281 | #define MPU6050_CLOCK_DIV_421 0xC
282 | #define MPU6050_CLOCK_DIV_400 0xD
283 | #define MPU6050_CLOCK_DIV_381 0xE
284 | #define MPU6050_CLOCK_DIV_364 0xF
285 |
286 | #define MPU6050_I2C_SLV_RW_BIT 7
287 | #define MPU6050_I2C_SLV_ADDR_BIT 6
288 | #define MPU6050_I2C_SLV_ADDR_LENGTH 7
289 | #define MPU6050_I2C_SLV_EN_BIT 7
290 | #define MPU6050_I2C_SLV_BYTE_SW_BIT 6
291 | #define MPU6050_I2C_SLV_REG_DIS_BIT 5
292 | #define MPU6050_I2C_SLV_GRP_BIT 4
293 | #define MPU6050_I2C_SLV_LEN_BIT 3
294 | #define MPU6050_I2C_SLV_LEN_LENGTH 4
295 |
296 | #define MPU6050_I2C_SLV4_RW_BIT 7
297 | #define MPU6050_I2C_SLV4_ADDR_BIT 6
298 | #define MPU6050_I2C_SLV4_ADDR_LENGTH 7
299 | #define MPU6050_I2C_SLV4_EN_BIT 7
300 | #define MPU6050_I2C_SLV4_INT_EN_BIT 6
301 | #define MPU6050_I2C_SLV4_REG_DIS_BIT 5
302 | #define MPU6050_I2C_SLV4_MST_DLY_BIT 4
303 | #define MPU6050_I2C_SLV4_MST_DLY_LENGTH 5
304 |
305 | #define MPU6050_MST_PASS_THROUGH_BIT 7
306 | #define MPU6050_MST_I2C_SLV4_DONE_BIT 6
307 | #define MPU6050_MST_I2C_LOST_ARB_BIT 5
308 | #define MPU6050_MST_I2C_SLV4_NACK_BIT 4
309 | #define MPU6050_MST_I2C_SLV3_NACK_BIT 3
310 | #define MPU6050_MST_I2C_SLV2_NACK_BIT 2
311 | #define MPU6050_MST_I2C_SLV1_NACK_BIT 1
312 | #define MPU6050_MST_I2C_SLV0_NACK_BIT 0
313 |
314 | #define MPU6050_INTCFG_INT_LEVEL_BIT 7
315 | #define MPU6050_INTCFG_INT_OPEN_BIT 6
316 | #define MPU6050_INTCFG_LATCH_INT_EN_BIT 5
317 | #define MPU6050_INTCFG_INT_RD_CLEAR_BIT 4
318 | #define MPU6050_INTCFG_FSYNC_INT_LEVEL_BIT 3
319 | #define MPU6050_INTCFG_FSYNC_INT_EN_BIT 2
320 | #define MPU6050_INTCFG_I2C_BYPASS_EN_BIT 1
321 | #define MPU6050_INTCFG_CLKOUT_EN_BIT 0
322 |
323 | #define MPU6050_INTMODE_ACTIVEHIGH 0x00
324 | #define MPU6050_INTMODE_ACTIVELOW 0x01
325 |
326 | #define MPU6050_INTDRV_PUSHPULL 0x00
327 | #define MPU6050_INTDRV_OPENDRAIN 0x01
328 |
329 | #define MPU6050_INTLATCH_50USPULSE 0x00
330 | #define MPU6050_INTLATCH_WAITCLEAR 0x01
331 |
332 | #define MPU6050_INTCLEAR_STATUSREAD 0x00
333 | #define MPU6050_INTCLEAR_ANYREAD 0x01
334 |
335 | #define MPU6050_INTERRUPT_FF_BIT 7
336 | #define MPU6050_INTERRUPT_MOT_BIT 6
337 | #define MPU6050_INTERRUPT_ZMOT_BIT 5
338 | #define MPU6050_INTERRUPT_FIFO_OFLOW_BIT 4
339 | #define MPU6050_INTERRUPT_I2C_MST_INT_BIT 3
340 | #define MPU6050_INTERRUPT_PLL_RDY_INT_BIT 2
341 | #define MPU6050_INTERRUPT_DMP_INT_BIT 1
342 | #define MPU6050_INTERRUPT_DATA_RDY_BIT 0
343 |
344 | // TODO: figure out what these actually do
345 | // UMPL source code is not very obivous
346 | #define MPU6050_DMPINT_5_BIT 5
347 | #define MPU6050_DMPINT_4_BIT 4
348 | #define MPU6050_DMPINT_3_BIT 3
349 | #define MPU6050_DMPINT_2_BIT 2
350 | #define MPU6050_DMPINT_1_BIT 1
351 | #define MPU6050_DMPINT_0_BIT 0
352 |
353 | #define MPU6050_MOTION_MOT_XNEG_BIT 7
354 | #define MPU6050_MOTION_MOT_XPOS_BIT 6
355 | #define MPU6050_MOTION_MOT_YNEG_BIT 5
356 | #define MPU6050_MOTION_MOT_YPOS_BIT 4
357 | #define MPU6050_MOTION_MOT_ZNEG_BIT 3
358 | #define MPU6050_MOTION_MOT_ZPOS_BIT 2
359 | #define MPU6050_MOTION_MOT_ZRMOT_BIT 0
360 |
361 | #define MPU6050_DELAYCTRL_DELAY_ES_SHADOW_BIT 7
362 | #define MPU6050_DELAYCTRL_I2C_SLV4_DLY_EN_BIT 4
363 | #define MPU6050_DELAYCTRL_I2C_SLV3_DLY_EN_BIT 3
364 | #define MPU6050_DELAYCTRL_I2C_SLV2_DLY_EN_BIT 2
365 | #define MPU6050_DELAYCTRL_I2C_SLV1_DLY_EN_BIT 1
366 | #define MPU6050_DELAYCTRL_I2C_SLV0_DLY_EN_BIT 0
367 |
368 | #define MPU6050_PATHRESET_GYRO_RESET_BIT 2
369 | #define MPU6050_PATHRESET_ACCEL_RESET_BIT 1
370 | #define MPU6050_PATHRESET_TEMP_RESET_BIT 0
371 |
372 | #define MPU6050_DETECT_ACCEL_ON_DELAY_BIT 5
373 | #define MPU6050_DETECT_ACCEL_ON_DELAY_LENGTH 2
374 | #define MPU6050_DETECT_FF_COUNT_BIT 3
375 | #define MPU6050_DETECT_FF_COUNT_LENGTH 2
376 | #define MPU6050_DETECT_MOT_COUNT_BIT 1
377 | #define MPU6050_DETECT_MOT_COUNT_LENGTH 2
378 |
379 | #define MPU6050_DETECT_DECREMENT_RESET 0x0
380 | #define MPU6050_DETECT_DECREMENT_1 0x1
381 | #define MPU6050_DETECT_DECREMENT_2 0x2
382 | #define MPU6050_DETECT_DECREMENT_4 0x3
383 |
384 | #define MPU6050_USERCTRL_DMP_EN_BIT 7
385 | #define MPU6050_USERCTRL_FIFO_EN_BIT 6
386 | #define MPU6050_USERCTRL_I2C_MST_EN_BIT 5
387 | #define MPU6050_USERCTRL_I2C_IF_DIS_BIT 4
388 | #define MPU6050_USERCTRL_DMP_RESET_BIT 3
389 | #define MPU6050_USERCTRL_FIFO_RESET_BIT 2
390 | #define MPU6050_USERCTRL_I2C_MST_RESET_BIT 1
391 | #define MPU6050_USERCTRL_SIG_COND_RESET_BIT 0
392 |
393 | #define MPU6050_PWR1_DEVICE_RESET_BIT 7
394 | #define MPU6050_PWR1_SLEEP_BIT 6
395 | #define MPU6050_PWR1_CYCLE_BIT 5
396 | #define MPU6050_PWR1_TEMP_DIS_BIT 3
397 | #define MPU6050_PWR1_CLKSEL_BIT 2
398 | #define MPU6050_PWR1_CLKSEL_LENGTH 3
399 |
400 | #define MPU6050_CLOCK_INTERNAL 0x00
401 | #define MPU6050_CLOCK_PLL_XGYRO 0x01
402 | #define MPU6050_CLOCK_PLL_YGYRO 0x02
403 | #define MPU6050_CLOCK_PLL_ZGYRO 0x03
404 | #define MPU6050_CLOCK_PLL_EXT32K 0x04
405 | #define MPU6050_CLOCK_PLL_EXT19M 0x05
406 | #define MPU6050_CLOCK_KEEP_RESET 0x07
407 |
408 | #define MPU6050_PWR2_LP_WAKE_CTRL_BIT 7
409 | #define MPU6050_PWR2_LP_WAKE_CTRL_LENGTH 2
410 | #define MPU6050_PWR2_STBY_XA_BIT 5
411 | #define MPU6050_PWR2_STBY_YA_BIT 4
412 | #define MPU6050_PWR2_STBY_ZA_BIT 3
413 | #define MPU6050_PWR2_STBY_XG_BIT 2
414 | #define MPU6050_PWR2_STBY_YG_BIT 1
415 | #define MPU6050_PWR2_STBY_ZG_BIT 0
416 |
417 | #define MPU6050_WAKE_FREQ_1P25 0x0
418 | #define MPU6050_WAKE_FREQ_2P5 0x1
419 | #define MPU6050_WAKE_FREQ_5 0x2
420 | #define MPU6050_WAKE_FREQ_10 0x3
421 |
422 | #define MPU6050_BANKSEL_PRFTCH_EN_BIT 6
423 | #define MPU6050_BANKSEL_CFG_USER_BANK_BIT 5
424 | #define MPU6050_BANKSEL_MEM_SEL_BIT 4
425 | #define MPU6050_BANKSEL_MEM_SEL_LENGTH 5
426 |
427 | #define MPU6050_WHO_AM_I_BIT 6
428 | #define MPU6050_WHO_AM_I_LENGTH 6
429 |
430 | #define MPU6050_DMP_MEMORY_BANKS 8
431 | #define MPU6050_DMP_MEMORY_BANK_SIZE 256
432 | #define MPU6050_DMP_MEMORY_CHUNK_SIZE 16
433 |
434 | // note: DMP code memory blocks defined at end of header file
435 |
436 | class MPU6050 {
437 | public:
438 | MPU6050(uint8_t address=MPU6050_DEFAULT_ADDRESS);
439 |
440 | void initialize();
441 | bool testConnection();
442 |
443 | // AUX_VDDIO register
444 | uint8_t getAuxVDDIOLevel();
445 | void setAuxVDDIOLevel(uint8_t level);
446 |
447 | // SMPLRT_DIV register
448 | uint8_t getRate();
449 | void setRate(uint8_t rate);
450 |
451 | // CONFIG register
452 | uint8_t getExternalFrameSync();
453 | void setExternalFrameSync(uint8_t sync);
454 | uint8_t getDLPFMode();
455 | void setDLPFMode(uint8_t bandwidth);
456 |
457 | // GYRO_CONFIG register
458 | uint8_t getFullScaleGyroRange();
459 | void setFullScaleGyroRange(uint8_t range);
460 |
461 | // SELF_TEST registers
462 | uint8_t getAccelXSelfTestFactoryTrim();
463 | uint8_t getAccelYSelfTestFactoryTrim();
464 | uint8_t getAccelZSelfTestFactoryTrim();
465 |
466 | uint8_t getGyroXSelfTestFactoryTrim();
467 | uint8_t getGyroYSelfTestFactoryTrim();
468 | uint8_t getGyroZSelfTestFactoryTrim();
469 |
470 | // ACCEL_CONFIG register
471 | bool getAccelXSelfTest();
472 | void setAccelXSelfTest(bool enabled);
473 | bool getAccelYSelfTest();
474 | void setAccelYSelfTest(bool enabled);
475 | bool getAccelZSelfTest();
476 | void setAccelZSelfTest(bool enabled);
477 | uint8_t getFullScaleAccelRange();
478 | void setFullScaleAccelRange(uint8_t range);
479 | uint8_t getDHPFMode();
480 | void setDHPFMode(uint8_t mode);
481 |
482 | // FF_THR register
483 | uint8_t getFreefallDetectionThreshold();
484 | void setFreefallDetectionThreshold(uint8_t threshold);
485 |
486 | // FF_DUR register
487 | uint8_t getFreefallDetectionDuration();
488 | void setFreefallDetectionDuration(uint8_t duration);
489 |
490 | // MOT_THR register
491 | uint8_t getMotionDetectionThreshold();
492 | void setMotionDetectionThreshold(uint8_t threshold);
493 |
494 | // MOT_DUR register
495 | uint8_t getMotionDetectionDuration();
496 | void setMotionDetectionDuration(uint8_t duration);
497 |
498 | // ZRMOT_THR register
499 | uint8_t getZeroMotionDetectionThreshold();
500 | void setZeroMotionDetectionThreshold(uint8_t threshold);
501 |
502 | // ZRMOT_DUR register
503 | uint8_t getZeroMotionDetectionDuration();
504 | void setZeroMotionDetectionDuration(uint8_t duration);
505 |
506 | // FIFO_EN register
507 | bool getTempFIFOEnabled();
508 | void setTempFIFOEnabled(bool enabled);
509 | bool getXGyroFIFOEnabled();
510 | void setXGyroFIFOEnabled(bool enabled);
511 | bool getYGyroFIFOEnabled();
512 | void setYGyroFIFOEnabled(bool enabled);
513 | bool getZGyroFIFOEnabled();
514 | void setZGyroFIFOEnabled(bool enabled);
515 | bool getAccelFIFOEnabled();
516 | void setAccelFIFOEnabled(bool enabled);
517 | bool getSlave2FIFOEnabled();
518 | void setSlave2FIFOEnabled(bool enabled);
519 | bool getSlave1FIFOEnabled();
520 | void setSlave1FIFOEnabled(bool enabled);
521 | bool getSlave0FIFOEnabled();
522 | void setSlave0FIFOEnabled(bool enabled);
523 |
524 | // I2C_MST_CTRL register
525 | bool getMultiMasterEnabled();
526 | void setMultiMasterEnabled(bool enabled);
527 | bool getWaitForExternalSensorEnabled();
528 | void setWaitForExternalSensorEnabled(bool enabled);
529 | bool getSlave3FIFOEnabled();
530 | void setSlave3FIFOEnabled(bool enabled);
531 | bool getSlaveReadWriteTransitionEnabled();
532 | void setSlaveReadWriteTransitionEnabled(bool enabled);
533 | uint8_t getMasterClockSpeed();
534 | void setMasterClockSpeed(uint8_t speed);
535 |
536 | // I2C_SLV* registers (Slave 0-3)
537 | uint8_t getSlaveAddress(uint8_t num);
538 | void setSlaveAddress(uint8_t num, uint8_t address);
539 | uint8_t getSlaveRegister(uint8_t num);
540 | void setSlaveRegister(uint8_t num, uint8_t reg);
541 | bool getSlaveEnabled(uint8_t num);
542 | void setSlaveEnabled(uint8_t num, bool enabled);
543 | bool getSlaveWordByteSwap(uint8_t num);
544 | void setSlaveWordByteSwap(uint8_t num, bool enabled);
545 | bool getSlaveWriteMode(uint8_t num);
546 | void setSlaveWriteMode(uint8_t num, bool mode);
547 | bool getSlaveWordGroupOffset(uint8_t num);
548 | void setSlaveWordGroupOffset(uint8_t num, bool enabled);
549 | uint8_t getSlaveDataLength(uint8_t num);
550 | void setSlaveDataLength(uint8_t num, uint8_t length);
551 |
552 | // I2C_SLV* registers (Slave 4)
553 | uint8_t getSlave4Address();
554 | void setSlave4Address(uint8_t address);
555 | uint8_t getSlave4Register();
556 | void setSlave4Register(uint8_t reg);
557 | void setSlave4OutputByte(uint8_t data);
558 | bool getSlave4Enabled();
559 | void setSlave4Enabled(bool enabled);
560 | bool getSlave4InterruptEnabled();
561 | void setSlave4InterruptEnabled(bool enabled);
562 | bool getSlave4WriteMode();
563 | void setSlave4WriteMode(bool mode);
564 | uint8_t getSlave4MasterDelay();
565 | void setSlave4MasterDelay(uint8_t delay);
566 | uint8_t getSlate4InputByte();
567 |
568 | // I2C_MST_STATUS register
569 | bool getPassthroughStatus();
570 | bool getSlave4IsDone();
571 | bool getLostArbitration();
572 | bool getSlave4Nack();
573 | bool getSlave3Nack();
574 | bool getSlave2Nack();
575 | bool getSlave1Nack();
576 | bool getSlave0Nack();
577 |
578 | // INT_PIN_CFG register
579 | bool getInterruptMode();
580 | void setInterruptMode(bool mode);
581 | bool getInterruptDrive();
582 | void setInterruptDrive(bool drive);
583 | bool getInterruptLatch();
584 | void setInterruptLatch(bool latch);
585 | bool getInterruptLatchClear();
586 | void setInterruptLatchClear(bool clear);
587 | bool getFSyncInterruptLevel();
588 | void setFSyncInterruptLevel(bool level);
589 | bool getFSyncInterruptEnabled();
590 | void setFSyncInterruptEnabled(bool enabled);
591 | bool getI2CBypassEnabled();
592 | void setI2CBypassEnabled(bool enabled);
593 | bool getClockOutputEnabled();
594 | void setClockOutputEnabled(bool enabled);
595 |
596 | // INT_ENABLE register
597 | uint8_t getIntEnabled();
598 | void setIntEnabled(uint8_t enabled);
599 | bool getIntFreefallEnabled();
600 | void setIntFreefallEnabled(bool enabled);
601 | bool getIntMotionEnabled();
602 | void setIntMotionEnabled(bool enabled);
603 | bool getIntZeroMotionEnabled();
604 | void setIntZeroMotionEnabled(bool enabled);
605 | bool getIntFIFOBufferOverflowEnabled();
606 | void setIntFIFOBufferOverflowEnabled(bool enabled);
607 | bool getIntI2CMasterEnabled();
608 | void setIntI2CMasterEnabled(bool enabled);
609 | bool getIntDataReadyEnabled();
610 | void setIntDataReadyEnabled(bool enabled);
611 |
612 | // INT_STATUS register
613 | uint8_t getIntStatus();
614 | bool getIntFreefallStatus();
615 | bool getIntMotionStatus();
616 | bool getIntZeroMotionStatus();
617 | bool getIntFIFOBufferOverflowStatus();
618 | bool getIntI2CMasterStatus();
619 | bool getIntDataReadyStatus();
620 |
621 | // ACCEL_*OUT_* registers
622 | void getMotion9(int16_t* ax, int16_t* ay, int16_t* az, int16_t* gx, int16_t* gy, int16_t* gz, int16_t* mx, int16_t* my, int16_t* mz);
623 | void getMotion6(int16_t* ax, int16_t* ay, int16_t* az, int16_t* gx, int16_t* gy, int16_t* gz);
624 | void getAcceleration(int16_t* x, int16_t* y, int16_t* z);
625 | int16_t getAccelerationX();
626 | int16_t getAccelerationY();
627 | int16_t getAccelerationZ();
628 |
629 | // TEMP_OUT_* registers
630 | int16_t getTemperature();
631 |
632 | // GYRO_*OUT_* registers
633 | void getRotation(int16_t* x, int16_t* y, int16_t* z);
634 | int16_t getRotationX();
635 | int16_t getRotationY();
636 | int16_t getRotationZ();
637 |
638 | // EXT_SENS_DATA_* registers
639 | uint8_t getExternalSensorByte(int position);
640 | uint16_t getExternalSensorWord(int position);
641 | uint32_t getExternalSensorDWord(int position);
642 |
643 | // MOT_DETECT_STATUS register
644 | uint8_t getMotionStatus();
645 | bool getXNegMotionDetected();
646 | bool getXPosMotionDetected();
647 | bool getYNegMotionDetected();
648 | bool getYPosMotionDetected();
649 | bool getZNegMotionDetected();
650 | bool getZPosMotionDetected();
651 | bool getZeroMotionDetected();
652 |
653 | // I2C_SLV*_DO register
654 | void setSlaveOutputByte(uint8_t num, uint8_t data);
655 |
656 | // I2C_MST_DELAY_CTRL register
657 | bool getExternalShadowDelayEnabled();
658 | void setExternalShadowDelayEnabled(bool enabled);
659 | bool getSlaveDelayEnabled(uint8_t num);
660 | void setSlaveDelayEnabled(uint8_t num, bool enabled);
661 |
662 | // SIGNAL_PATH_RESET register
663 | void resetGyroscopePath();
664 | void resetAccelerometerPath();
665 | void resetTemperaturePath();
666 |
667 | // MOT_DETECT_CTRL register
668 | uint8_t getAccelerometerPowerOnDelay();
669 | void setAccelerometerPowerOnDelay(uint8_t delay);
670 | uint8_t getFreefallDetectionCounterDecrement();
671 | void setFreefallDetectionCounterDecrement(uint8_t decrement);
672 | uint8_t getMotionDetectionCounterDecrement();
673 | void setMotionDetectionCounterDecrement(uint8_t decrement);
674 |
675 | // USER_CTRL register
676 | bool getFIFOEnabled();
677 | void setFIFOEnabled(bool enabled);
678 | bool getI2CMasterModeEnabled();
679 | void setI2CMasterModeEnabled(bool enabled);
680 | void switchSPIEnabled(bool enabled);
681 | void resetFIFO();
682 | void resetI2CMaster();
683 | void resetSensors();
684 |
685 | // PWR_MGMT_1 register
686 | void reset();
687 | bool getSleepEnabled();
688 | void setSleepEnabled(bool enabled);
689 | bool getWakeCycleEnabled();
690 | void setWakeCycleEnabled(bool enabled);
691 | bool getTempSensorEnabled();
692 | void setTempSensorEnabled(bool enabled);
693 | uint8_t getClockSource();
694 | void setClockSource(uint8_t source);
695 |
696 | // PWR_MGMT_2 register
697 | uint8_t getWakeFrequency();
698 | void setWakeFrequency(uint8_t frequency);
699 | bool getStandbyXAccelEnabled();
700 | void setStandbyXAccelEnabled(bool enabled);
701 | bool getStandbyYAccelEnabled();
702 | void setStandbyYAccelEnabled(bool enabled);
703 | bool getStandbyZAccelEnabled();
704 | void setStandbyZAccelEnabled(bool enabled);
705 | bool getStandbyXGyroEnabled();
706 | void setStandbyXGyroEnabled(bool enabled);
707 | bool getStandbyYGyroEnabled();
708 | void setStandbyYGyroEnabled(bool enabled);
709 | bool getStandbyZGyroEnabled();
710 | void setStandbyZGyroEnabled(bool enabled);
711 |
712 | // FIFO_COUNT_* registers
713 | uint16_t getFIFOCount();
714 |
715 | // FIFO_R_W register
716 | uint8_t getFIFOByte();
717 | int8_t GetCurrentFIFOPacket(uint8_t *data, uint8_t length);
718 | void setFIFOByte(uint8_t data);
719 | void getFIFOBytes(uint8_t *data, uint8_t length);
720 |
721 | // WHO_AM_I register
722 | uint8_t getDeviceID();
723 | void setDeviceID(uint8_t id);
724 |
725 | // ======== UNDOCUMENTED/DMP REGISTERS/METHODS ========
726 |
727 | // XG_OFFS_TC register
728 | uint8_t getOTPBankValid();
729 | void setOTPBankValid(bool enabled);
730 | int8_t getXGyroOffsetTC();
731 | void setXGyroOffsetTC(int8_t offset);
732 |
733 | // YG_OFFS_TC register
734 | int8_t getYGyroOffsetTC();
735 | void setYGyroOffsetTC(int8_t offset);
736 |
737 | // ZG_OFFS_TC register
738 | int8_t getZGyroOffsetTC();
739 | void setZGyroOffsetTC(int8_t offset);
740 |
741 | // X_FINE_GAIN register
742 | int8_t getXFineGain();
743 | void setXFineGain(int8_t gain);
744 |
745 | // Y_FINE_GAIN register
746 | int8_t getYFineGain();
747 | void setYFineGain(int8_t gain);
748 |
749 | // Z_FINE_GAIN register
750 | int8_t getZFineGain();
751 | void setZFineGain(int8_t gain);
752 |
753 | // XA_OFFS_* registers
754 | int16_t getXAccelOffset();
755 | void setXAccelOffset(int16_t offset);
756 |
757 | // YA_OFFS_* register
758 | int16_t getYAccelOffset();
759 | void setYAccelOffset(int16_t offset);
760 |
761 | // ZA_OFFS_* register
762 | int16_t getZAccelOffset();
763 | void setZAccelOffset(int16_t offset);
764 |
765 | // XG_OFFS_USR* registers
766 | int16_t getXGyroOffset();
767 | void setXGyroOffset(int16_t offset);
768 |
769 | // YG_OFFS_USR* register
770 | int16_t getYGyroOffset();
771 | void setYGyroOffset(int16_t offset);
772 |
773 | // ZG_OFFS_USR* register
774 | int16_t getZGyroOffset();
775 | void setZGyroOffset(int16_t offset);
776 |
777 | // INT_ENABLE register (DMP functions)
778 | bool getIntPLLReadyEnabled();
779 | void setIntPLLReadyEnabled(bool enabled);
780 | bool getIntDMPEnabled();
781 | void setIntDMPEnabled(bool enabled);
782 |
783 | // DMP_INT_STATUS
784 | bool getDMPInt5Status();
785 | bool getDMPInt4Status();
786 | bool getDMPInt3Status();
787 | bool getDMPInt2Status();
788 | bool getDMPInt1Status();
789 | bool getDMPInt0Status();
790 |
791 | // INT_STATUS register (DMP functions)
792 | bool getIntPLLReadyStatus();
793 | bool getIntDMPStatus();
794 |
795 | // USER_CTRL register (DMP functions)
796 | bool getDMPEnabled();
797 | void setDMPEnabled(bool enabled);
798 | void resetDMP();
799 |
800 | // BANK_SEL register
801 | void setMemoryBank(uint8_t bank, bool prefetchEnabled=false, bool userBank=false);
802 |
803 | // MEM_START_ADDR register
804 | void setMemoryStartAddress(uint8_t address);
805 |
806 | // MEM_R_W register
807 | uint8_t readMemoryByte();
808 | void writeMemoryByte(uint8_t data);
809 | void readMemoryBlock(uint8_t *data, uint16_t dataSize, uint8_t bank=0, uint8_t address=0);
810 | bool writeMemoryBlock(const uint8_t *data, uint16_t dataSize, uint8_t bank=0, uint8_t address=0, bool verify=true, bool useProgMem=false);
811 | bool writeProgMemoryBlock(const uint8_t *data, uint16_t dataSize, uint8_t bank=0, uint8_t address=0, bool verify=true);
812 |
813 | bool writeDMPConfigurationSet(const uint8_t *data, uint16_t dataSize, bool useProgMem=false);
814 | bool writeProgDMPConfigurationSet(const uint8_t *data, uint16_t dataSize);
815 |
816 | // DMP_CFG_1 register
817 | uint8_t getDMPConfig1();
818 | void setDMPConfig1(uint8_t config);
819 |
820 | // DMP_CFG_2 register
821 | uint8_t getDMPConfig2();
822 | void setDMPConfig2(uint8_t config);
823 |
824 | // Calibration Routines
825 | void CalibrateGyro(uint8_t Loops = 15); // Fine tune after setting offsets with less Loops.
826 | void CalibrateAccel(uint8_t Loops = 15);// Fine tune after setting offsets with less Loops.
827 | void PID(uint8_t ReadAddress, float kP,float kI, uint8_t Loops); // Does the math
828 | void PrintActiveOffsets(); // See the results of the Calibration
829 |
830 |
831 |
832 | // special methods for MotionApps 2.0 implementation
833 | #ifdef MPU6050_INCLUDE_DMP_MOTIONAPPS20
834 |
835 | uint8_t dmpInitialize();
836 | bool dmpPacketAvailable();
837 |
838 | uint8_t dmpSetFIFORate(uint8_t fifoRate);
839 | uint8_t dmpGetFIFORate();
840 | uint8_t dmpGetSampleStepSizeMS();
841 | uint8_t dmpGetSampleFrequency();
842 | int32_t dmpDecodeTemperature(int8_t tempReg);
843 |
844 | // Register callbacks after a packet of FIFO data is processed
845 | //uint8_t dmpRegisterFIFORateProcess(inv_obj_func func, int16_t priority);
846 | //uint8_t dmpUnregisterFIFORateProcess(inv_obj_func func);
847 | uint8_t dmpRunFIFORateProcesses();
848 |
849 | // Setup FIFO for various output
850 | uint8_t dmpSendQuaternion(uint_fast16_t accuracy);
851 | uint8_t dmpSendGyro(uint_fast16_t elements, uint_fast16_t accuracy);
852 | uint8_t dmpSendAccel(uint_fast16_t elements, uint_fast16_t accuracy);
853 | uint8_t dmpSendLinearAccel(uint_fast16_t elements, uint_fast16_t accuracy);
854 | uint8_t dmpSendLinearAccelInWorld(uint_fast16_t elements, uint_fast16_t accuracy);
855 | uint8_t dmpSendControlData(uint_fast16_t elements, uint_fast16_t accuracy);
856 | uint8_t dmpSendSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
857 | uint8_t dmpSendExternalSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
858 | uint8_t dmpSendGravity(uint_fast16_t elements, uint_fast16_t accuracy);
859 | uint8_t dmpSendPacketNumber(uint_fast16_t accuracy);
860 | uint8_t dmpSendQuantizedAccel(uint_fast16_t elements, uint_fast16_t accuracy);
861 | uint8_t dmpSendEIS(uint_fast16_t elements, uint_fast16_t accuracy);
862 |
863 | // Get Fixed Point data from FIFO
864 | uint8_t dmpGetAccel(int32_t *data, const uint8_t* packet=0);
865 | uint8_t dmpGetAccel(int16_t *data, const uint8_t* packet=0);
866 | uint8_t dmpGetAccel(VectorInt16 *v, const uint8_t* packet=0);
867 | uint8_t dmpGetQuaternion(int32_t *data, const uint8_t* packet=0);
868 | uint8_t dmpGetQuaternion(int16_t *data, const uint8_t* packet=0);
869 | uint8_t dmpGetQuaternion(Quaternion *q, const uint8_t* packet=0);
870 | uint8_t dmpGet6AxisQuaternion(int32_t *data, const uint8_t* packet=0);
871 | uint8_t dmpGet6AxisQuaternion(int16_t *data, const uint8_t* packet=0);
872 | uint8_t dmpGet6AxisQuaternion(Quaternion *q, const uint8_t* packet=0);
873 | uint8_t dmpGetRelativeQuaternion(int32_t *data, const uint8_t* packet=0);
874 | uint8_t dmpGetRelativeQuaternion(int16_t *data, const uint8_t* packet=0);
875 | uint8_t dmpGetRelativeQuaternion(Quaternion *data, const uint8_t* packet=0);
876 | uint8_t dmpGetGyro(int32_t *data, const uint8_t* packet=0);
877 | uint8_t dmpGetGyro(int16_t *data, const uint8_t* packet=0);
878 | uint8_t dmpGetGyro(VectorInt16 *v, const uint8_t* packet=0);
879 | uint8_t dmpSetLinearAccelFilterCoefficient(float coef);
880 | uint8_t dmpGetLinearAccel(int32_t *data, const uint8_t* packet=0);
881 | uint8_t dmpGetLinearAccel(int16_t *data, const uint8_t* packet=0);
882 | uint8_t dmpGetLinearAccel(VectorInt16 *v, const uint8_t* packet=0);
883 | uint8_t dmpGetLinearAccel(VectorInt16 *v, VectorInt16 *vRaw, VectorFloat *gravity);
884 | uint8_t dmpGetLinearAccelInWorld(int32_t *data, const uint8_t* packet=0);
885 | uint8_t dmpGetLinearAccelInWorld(int16_t *data, const uint8_t* packet=0);
886 | uint8_t dmpGetLinearAccelInWorld(VectorInt16 *v, const uint8_t* packet=0);
887 | uint8_t dmpGetLinearAccelInWorld(VectorInt16 *v, VectorInt16 *vReal, Quaternion *q);
888 | uint8_t dmpGetGyroAndAccelSensor(int32_t *data, const uint8_t* packet=0);
889 | uint8_t dmpGetGyroAndAccelSensor(int16_t *data, const uint8_t* packet=0);
890 | uint8_t dmpGetGyroAndAccelSensor(VectorInt16 *g, VectorInt16 *a, const uint8_t* packet=0);
891 | uint8_t dmpGetGyroSensor(int32_t *data, const uint8_t* packet=0);
892 | uint8_t dmpGetGyroSensor(int16_t *data, const uint8_t* packet=0);
893 | uint8_t dmpGetGyroSensor(VectorInt16 *v, const uint8_t* packet=0);
894 | uint8_t dmpGetControlData(int32_t *data, const uint8_t* packet=0);
895 | uint8_t dmpGetTemperature(int32_t *data, const uint8_t* packet=0);
896 | uint8_t dmpGetGravity(int32_t *data, const uint8_t* packet=0);
897 | uint8_t dmpGetGravity(int16_t *data, const uint8_t* packet=0);
898 | uint8_t dmpGetGravity(VectorInt16 *v, const uint8_t* packet=0);
899 | uint8_t dmpGetGravity(VectorFloat *v, Quaternion *q);
900 | uint8_t dmpGetUnquantizedAccel(int32_t *data, const uint8_t* packet=0);
901 | uint8_t dmpGetUnquantizedAccel(int16_t *data, const uint8_t* packet=0);
902 | uint8_t dmpGetUnquantizedAccel(VectorInt16 *v, const uint8_t* packet=0);
903 | uint8_t dmpGetQuantizedAccel(int32_t *data, const uint8_t* packet=0);
904 | uint8_t dmpGetQuantizedAccel(int16_t *data, const uint8_t* packet=0);
905 | uint8_t dmpGetQuantizedAccel(VectorInt16 *v, const uint8_t* packet=0);
906 | uint8_t dmpGetExternalSensorData(int32_t *data, uint16_t size, const uint8_t* packet=0);
907 | uint8_t dmpGetEIS(int32_t *data, const uint8_t* packet=0);
908 |
909 | uint8_t dmpGetEuler(float *data, Quaternion *q);
910 | uint8_t dmpGetYawPitchRoll(float *data, Quaternion *q, VectorFloat *gravity);
911 |
912 | // Get Floating Point data from FIFO
913 | uint8_t dmpGetAccelFloat(float *data, const uint8_t* packet=0);
914 | uint8_t dmpGetQuaternionFloat(float *data, const uint8_t* packet=0);
915 |
916 | uint8_t dmpProcessFIFOPacket(const unsigned char *dmpData);
917 | uint8_t dmpReadAndProcessFIFOPacket(uint8_t numPackets, uint8_t *processed=NULL);
918 |
919 | uint8_t dmpSetFIFOProcessedCallback(void (*func) (void));
920 |
921 | uint8_t dmpInitFIFOParam();
922 | uint8_t dmpCloseFIFO();
923 | uint8_t dmpSetGyroDataSource(uint8_t source);
924 | uint8_t dmpDecodeQuantizedAccel();
925 | uint32_t dmpGetGyroSumOfSquare();
926 | uint32_t dmpGetAccelSumOfSquare();
927 | void dmpOverrideQuaternion(long *q);
928 | uint16_t dmpGetFIFOPacketSize();
929 | uint8_t dmpGetCurrentFIFOPacket(uint8_t *data); // overflow proof
930 | #endif
931 |
932 | // special methods for MotionApps 4.1 implementation
933 | #ifdef MPU6050_INCLUDE_DMP_MOTIONAPPS41
934 |
935 | uint8_t dmpInitialize();
936 | bool dmpPacketAvailable();
937 |
938 | uint8_t dmpSetFIFORate(uint8_t fifoRate);
939 | uint8_t dmpGetFIFORate();
940 | uint8_t dmpGetSampleStepSizeMS();
941 | uint8_t dmpGetSampleFrequency();
942 | int32_t dmpDecodeTemperature(int8_t tempReg);
943 |
944 | // Register callbacks after a packet of FIFO data is processed
945 | //uint8_t dmpRegisterFIFORateProcess(inv_obj_func func, int16_t priority);
946 | //uint8_t dmpUnregisterFIFORateProcess(inv_obj_func func);
947 | uint8_t dmpRunFIFORateProcesses();
948 |
949 | // Setup FIFO for various output
950 | uint8_t dmpSendQuaternion(uint_fast16_t accuracy);
951 | uint8_t dmpSendGyro(uint_fast16_t elements, uint_fast16_t accuracy);
952 | uint8_t dmpSendAccel(uint_fast16_t elements, uint_fast16_t accuracy);
953 | uint8_t dmpSendLinearAccel(uint_fast16_t elements, uint_fast16_t accuracy);
954 | uint8_t dmpSendLinearAccelInWorld(uint_fast16_t elements, uint_fast16_t accuracy);
955 | uint8_t dmpSendControlData(uint_fast16_t elements, uint_fast16_t accuracy);
956 | uint8_t dmpSendSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
957 | uint8_t dmpSendExternalSensorData(uint_fast16_t elements, uint_fast16_t accuracy);
958 | uint8_t dmpSendGravity(uint_fast16_t elements, uint_fast16_t accuracy);
959 | uint8_t dmpSendPacketNumber(uint_fast16_t accuracy);
960 | uint8_t dmpSendQuantizedAccel(uint_fast16_t elements, uint_fast16_t accuracy);
961 | uint8_t dmpSendEIS(uint_fast16_t elements, uint_fast16_t accuracy);
962 |
963 | // Get Fixed Point data from FIFO
964 | uint8_t dmpGetAccel(int32_t *data, const uint8_t* packet=0);
965 | uint8_t dmpGetAccel(int16_t *data, const uint8_t* packet=0);
966 | uint8_t dmpGetAccel(VectorInt16 *v, const uint8_t* packet=0);
967 | uint8_t dmpGetQuaternion(int32_t *data, const uint8_t* packet=0);
968 | uint8_t dmpGetQuaternion(int16_t *data, const uint8_t* packet=0);
969 | uint8_t dmpGetQuaternion(Quaternion *q, const uint8_t* packet=0);
970 | uint8_t dmpGet6AxisQuaternion(int32_t *data, const uint8_t* packet=0);
971 | uint8_t dmpGet6AxisQuaternion(int16_t *data, const uint8_t* packet=0);
972 | uint8_t dmpGet6AxisQuaternion(Quaternion *q, const uint8_t* packet=0);
973 | uint8_t dmpGetRelativeQuaternion(int32_t *data, const uint8_t* packet=0);
974 | uint8_t dmpGetRelativeQuaternion(int16_t *data, const uint8_t* packet=0);
975 | uint8_t dmpGetRelativeQuaternion(Quaternion *data, const uint8_t* packet=0);
976 | uint8_t dmpGetGyro(int32_t *data, const uint8_t* packet=0);
977 | uint8_t dmpGetGyro(int16_t *data, const uint8_t* packet=0);
978 | uint8_t dmpGetGyro(VectorInt16 *v, const uint8_t* packet=0);
979 | uint8_t dmpGetMag(int16_t *data, const uint8_t* packet=0);
980 | uint8_t dmpSetLinearAccelFilterCoefficient(float coef);
981 | uint8_t dmpGetLinearAccel(int32_t *data, const uint8_t* packet=0);
982 | uint8_t dmpGetLinearAccel(int16_t *data, const uint8_t* packet=0);
983 | uint8_t dmpGetLinearAccel(VectorInt16 *v, const uint8_t* packet=0);
984 | uint8_t dmpGetLinearAccel(VectorInt16 *v, VectorInt16 *vRaw, VectorFloat *gravity);
985 | uint8_t dmpGetLinearAccelInWorld(int32_t *data, const uint8_t* packet=0);
986 | uint8_t dmpGetLinearAccelInWorld(int16_t *data, const uint8_t* packet=0);
987 | uint8_t dmpGetLinearAccelInWorld(VectorInt16 *v, const uint8_t* packet=0);
988 | uint8_t dmpGetLinearAccelInWorld(VectorInt16 *v, VectorInt16 *vReal, Quaternion *q);
989 | uint8_t dmpGetGyroAndAccelSensor(int32_t *data, const uint8_t* packet=0);
990 | uint8_t dmpGetGyroAndAccelSensor(int16_t *data, const uint8_t* packet=0);
991 | uint8_t dmpGetGyroAndAccelSensor(VectorInt16 *g, VectorInt16 *a, const uint8_t* packet=0);
992 | uint8_t dmpGetGyroSensor(int32_t *data, const uint8_t* packet=0);
993 | uint8_t dmpGetGyroSensor(int16_t *data, const uint8_t* packet=0);
994 | uint8_t dmpGetGyroSensor(VectorInt16 *v, const uint8_t* packet=0);
995 | uint8_t dmpGetControlData(int32_t *data, const uint8_t* packet=0);
996 | uint8_t dmpGetTemperature(int32_t *data, const uint8_t* packet=0);
997 | uint8_t dmpGetGravity(int32_t *data, const uint8_t* packet=0);
998 | uint8_t dmpGetGravity(int16_t *data, const uint8_t* packet=0);
999 | uint8_t dmpGetGravity(VectorInt16 *v, const uint8_t* packet=0);
1000 | uint8_t dmpGetGravity(VectorFloat *v, Quaternion *q);
1001 | uint8_t dmpGetUnquantizedAccel(int32_t *data, const uint8_t* packet=0);
1002 | uint8_t dmpGetUnquantizedAccel(int16_t *data, const uint8_t* packet=0);
1003 | uint8_t dmpGetUnquantizedAccel(VectorInt16 *v, const uint8_t* packet=0);
1004 | uint8_t dmpGetQuantizedAccel(int32_t *data, const uint8_t* packet=0);
1005 | uint8_t dmpGetQuantizedAccel(int16_t *data, const uint8_t* packet=0);
1006 | uint8_t dmpGetQuantizedAccel(VectorInt16 *v, const uint8_t* packet=0);
1007 | uint8_t dmpGetExternalSensorData(int32_t *data, uint16_t size, const uint8_t* packet=0);
1008 | uint8_t dmpGetEIS(int32_t *data, const uint8_t* packet=0);
1009 |
1010 | uint8_t dmpGetEuler(float *data, Quaternion *q);
1011 | uint8_t dmpGetYawPitchRoll(float *data, Quaternion *q, VectorFloat *gravity);
1012 |
1013 | // Get Floating Point data from FIFO
1014 | uint8_t dmpGetAccelFloat(float *data, const uint8_t* packet=0);
1015 | uint8_t dmpGetQuaternionFloat(float *data, const uint8_t* packet=0);
1016 |
1017 | uint8_t dmpProcessFIFOPacket(const unsigned char *dmpData);
1018 | uint8_t dmpReadAndProcessFIFOPacket(uint8_t numPackets, uint8_t *processed=NULL);
1019 |
1020 | uint8_t dmpSetFIFOProcessedCallback(void (*func) (void));
1021 |
1022 | uint8_t dmpInitFIFOParam();
1023 | uint8_t dmpCloseFIFO();
1024 | uint8_t dmpSetGyroDataSource(uint8_t source);
1025 | uint8_t dmpDecodeQuantizedAccel();
1026 | uint32_t dmpGetGyroSumOfSquare();
1027 | uint32_t dmpGetAccelSumOfSquare();
1028 | void dmpOverrideQuaternion(long *q);
1029 | uint16_t dmpGetFIFOPacketSize();
1030 | #endif
1031 |
1032 | private:
1033 | uint8_t devAddr;
1034 | uint8_t buffer[14];
1035 | #if defined(MPU6050_INCLUDE_DMP_MOTIONAPPS20) or defined(MPU6050_INCLUDE_DMP_MOTIONAPPS41)
1036 | uint8_t *dmpPacketBuffer;
1037 | uint16_t dmpPacketSize;
1038 | #endif
1039 | };
1040 |
1041 | #endif /* _MPU6050_H_ */
1042 |
--------------------------------------------------------------------------------
/lib/MPU6050/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "I2Cdevlib-MPU6050",
3 | "keywords": "gyroscope, accelerometer, sensor, i2cdevlib, i2c",
4 | "description": "The MPU6050 combines a 3-axis gyroscope and a 3-axis accelerometer on the same silicon die together with an onboard Digital Motion Processor(DMP) which processes complex 6-axis MotionFusion algorithms",
5 | "include": "Arduino/MPU6050",
6 | "repository":
7 | {
8 | "type": "git",
9 | "url": "https://github.com/jrowberg/i2cdevlib.git"
10 | },
11 | "dependencies":
12 | {
13 | "name": "I2Cdevlib-Core",
14 | "frameworks": "arduino"
15 | },
16 | "frameworks": "arduino",
17 | "platforms": "atmelavr"
18 | }
19 |
--------------------------------------------------------------------------------
/lib/MpuHelper/MpuHelper.cpp:
--------------------------------------------------------------------------------
1 | #include "MpuHelper.h"
2 |
3 | void MpuHelperClass::read() {
4 | preferences.begin("mpu", true);
5 | host = preferences.getString("host");
6 | port = preferences.getInt("port", 3333);
7 | duration = preferences.getInt("duration", 1);
8 | threshold = preferences.getInt("threshold", 20);
9 | preferences.end();
10 | }
11 |
12 | void MpuHelperClass::write() {
13 | preferences.begin("mpu", false);
14 | preferences.putString("host", host);
15 | preferences.putInt("port", port);
16 | preferences.putInt("duration", duration);
17 | preferences.putInt("threshold", threshold);
18 | preferences.end();
19 | }
20 |
21 | void MpuHelperClass::setup() {
22 | unsigned long setupStartTime = millis();
23 | Serial.println("Setup MPU helper");
24 |
25 | read();
26 |
27 | Wire.begin(SDA, SCL);
28 |
29 | // Reset the MPU (to try different settings)
30 | // mpu6050.reset();
31 | // delay(100);
32 |
33 | mpu6050.initialize();
34 |
35 | Serial.println("Testing device connections...");
36 | if (!mpu6050.testConnection()) {
37 | Serial.println("MPU6050 connection failed");
38 | return;
39 | }
40 |
41 | Serial.println("MPU6050 connection successful");
42 |
43 | // make sure accel is running
44 | mpu6050.setSleepEnabled(false);
45 | mpu6050.setWakeCycleEnabled(false);
46 |
47 | // enable accel
48 | mpu6050.setStandbyXAccelEnabled(false);
49 | mpu6050.setStandbyYAccelEnabled(false);
50 | mpu6050.setStandbyZAccelEnabled(false);
51 |
52 | // standby gyro
53 | mpu6050.setStandbyXGyroEnabled(true);
54 | mpu6050.setStandbyYGyroEnabled(true);
55 | mpu6050.setStandbyZGyroEnabled(true);
56 |
57 | // disable temperature sensor
58 | mpu6050.setTempSensorEnabled(false);
59 |
60 | // set accel HPF to reset settings
61 | mpu6050.setDHPFMode(0);
62 |
63 | // set accel LPF setting to 256hz bandwidth
64 | mpu6050.setDLPFMode(0);
65 |
66 | // enable motion interrupt
67 | mpu6050.setIntMotionEnabled(true);
68 | mpu6050.setMotionDetectionDuration(duration); // 1
69 | mpu6050.setMotionDetectionThreshold(threshold); // 20
70 |
71 | // logSettings();
72 |
73 | setupDuration = millis() - setupStartTime;
74 | Serial.print("Setup MPU helper took ");
75 | Serial.println(setupDuration);
76 | }
77 |
78 | void MpuHelperClass::loop() {
79 | readValues();
80 | sendValues();
81 | }
82 |
83 | void MpuHelperClass::sleep() {
84 | if (!mpu6050.testConnection()) {
85 | return;
86 | }
87 |
88 | // set accel HPF to hold
89 | mpu6050.setDHPFMode(7);
90 |
91 | // set the frequency to wakeup
92 | mpu6050.setWakeFrequency(0);
93 |
94 | mpu6050.setStandbyXGyroEnabled(true); // should be already set
95 | mpu6050.setStandbyYGyroEnabled(true); // should be already set
96 | mpu6050.setStandbyZGyroEnabled(true); // should be already set
97 |
98 | mpu6050.setTempSensorEnabled(false);
99 | mpu6050.setWakeCycleEnabled(true);
100 |
101 | // Write low to MPU pins to fallback to 6.5uA
102 | digitalWrite(SDA, LOW);
103 | digitalWrite(SCL, LOW);
104 | }
105 |
106 | void MpuHelperClass::readValues() {
107 | mpu6050.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
108 |
109 | Serial.print(ax);
110 | Serial.print("\t");
111 | Serial.print(ay);
112 | Serial.print("\t");
113 | Serial.println(az);
114 |
115 | calculateSide();
116 | }
117 |
118 | int MpuHelperClass::calculateAxis(int16_t &value) {
119 | return value > 8000 ? 1 : value < -8000 ? -1 : 0;
120 | }
121 |
122 | void MpuHelperClass::calculateSide() {
123 | int sideX = calculateAxis(ax);
124 | int sideY = calculateAxis(ay);
125 | int sideZ = calculateAxis(az);
126 |
127 | prevSide = side;
128 |
129 | if (sideX == 0 && sideY == 0 && sideZ == 1) {
130 | side = 0;
131 | } else if (sideX == 0 && sideY == 0 && sideZ == -1) {
132 | side = 1;
133 | } else if (sideX == 0 && sideY == -1 && sideZ == 0) {
134 | side = 2;
135 | } else if (sideX == 0 && sideY == 1 && sideZ == 0) {
136 | side = 3;
137 | } else if (sideX == 1 && sideY == 0 && sideZ == 0) {
138 | side = 4;
139 | } else if (sideX == -1 && sideY == 0 && sideZ == 0) {
140 | side = 5;
141 | }
142 |
143 | // Serial.println(side);
144 | }
145 |
146 | void MpuHelperClass::sendValues() {
147 | if (prevSide == side) {
148 | return;
149 | }
150 | if (host.length() == 0) return;
151 | if (!WiFiHelper.connect()) return;
152 | unsigned long requestStartTime = millis();
153 |
154 | StaticJsonDocument<32> doc;
155 |
156 | udp.beginPacket(host.c_str(), port);
157 |
158 | doc["side"] = side;
159 | serializeJson(doc, udp);
160 |
161 | udp.println();
162 | udp.endPacket();
163 |
164 | requestDuration = millis() - requestStartTime;
165 | Serial.print("Send UDP request ");
166 | Serial.println(requestDuration);
167 | }
168 |
169 | void MpuHelperClass::logSettings() {
170 | Serial.print("WakeCycle ");
171 | Serial.println(String(mpu6050.getWakeCycleEnabled()));
172 |
173 | Serial.print("DHPFMode ");
174 | Serial.println(String(mpu6050.getDHPFMode()));
175 | Serial.print("DLPFMode ");
176 | Serial.println(String(mpu6050.getDLPFMode()));
177 |
178 | Serial.println("AccelStandby ");
179 | Serial.println(String(mpu6050.getStandbyXAccelEnabled()));
180 |
181 | Serial.print("GyroStandby ");
182 | Serial.println(String(mpu6050.getStandbyXGyroEnabled()));
183 | Serial.print("TempSensor ");
184 | Serial.println(String(mpu6050.getTempSensorEnabled()));
185 | Serial.println();
186 |
187 | Serial.print("FIFO Enabled ");
188 | Serial.println(String(mpu6050.getFIFOEnabled()));
189 | Serial.print("XGyroFifo Enabled ");
190 | Serial.println(String(mpu6050.getXGyroFIFOEnabled()));
191 | Serial.print("IntFIFOBufferOverflow Enabled ");
192 | Serial.println(String(mpu6050.getIntFIFOBufferOverflowEnabled()));
193 | Serial.print("Clock Source ");
194 | Serial.println(String(mpu6050.getClockSource()));
195 | Serial.print("FullScalAccelRange ");
196 | Serial.println(String(mpu6050.getFullScaleAccelRange()));
197 | Serial.print("FullScalGyroRange ");
198 | Serial.println(String(mpu6050.getFullScaleGyroRange()));
199 |
200 | Serial.println();
201 | }
202 |
203 | void MpuHelperClass::server() {
204 | Serial.println("Setup MPU server");
205 |
206 | WebServerHelper.server.on("/api/mpu", HTTP_GET, [this](AsyncWebServerRequest *request) {
207 | int args = request->args();
208 |
209 | if (args > 0) {
210 | request->send(200, "text/plain", "message received");
211 | Serial.println("Update mpu settings");
212 |
213 | if (request->hasArg("host")) host = request->arg("host");
214 | if (request->hasArg("port")) port = request->arg("port").toInt();
215 | if (request->hasArg("duration")) duration = request->arg("duration").toInt();
216 | if (request->hasArg("threshold")) threshold = request->arg("threshold").toInt();
217 |
218 | write();
219 |
220 | } else {
221 | AsyncJsonResponse *response = new AsyncJsonResponse();
222 | response->addHeader("Server", "ESP Async Web Server");
223 | JsonVariant &root = response->getRoot();
224 |
225 | root["side"] = side;
226 | root["setupDuration"] = setupDuration;
227 | root["requestDuration"] = requestDuration;
228 |
229 | root["host"] = host;
230 | root["port"] = port;
231 |
232 | root["duration"] = duration;
233 | root["threshold"] = threshold;
234 |
235 | response->setLength();
236 | request->send(response);
237 | }
238 | });
239 | }
240 |
241 | MpuHelperClass MpuHelper;
242 |
--------------------------------------------------------------------------------
/lib/MpuHelper/MpuHelper.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef MpuHelper_h
3 | #define MpuHelper_h
4 |
5 | #include "Arduino.h"
6 | #include "ArduinoJson.h"
7 | #include "AsyncJson.h"
8 | #include "I2Cdev.h"
9 | #include "MPU6050.h"
10 | #include "Preferences.h"
11 | #include "WebServerHelper.h"
12 | #include "WiFiHelper.h"
13 | #include "WiFiUdp.h"
14 | #include "Wire.h"
15 |
16 | class MpuHelperClass {
17 | private:
18 | WiFiUDP udp;
19 | MPU6050 mpu6050;
20 | Preferences preferences;
21 |
22 | int16_t ax, ay, az;
23 | int16_t gx, gy, gz;
24 |
25 | String host;
26 | int32_t port;
27 |
28 | void read();
29 | void write();
30 |
31 | int calculateAxis(int16_t &value);
32 | void calculateSide();
33 | void logSettings();
34 | void readValues();
35 | void sendValues();
36 |
37 | unsigned long requestDuration;
38 | unsigned long setupDuration;
39 |
40 | int duration;
41 | int threshold;
42 |
43 | public:
44 | int prevSide;
45 | int side;
46 |
47 | void setup();
48 | void server();
49 | void loop();
50 | void sleep();
51 | };
52 |
53 | extern MpuHelperClass MpuHelper;
54 |
55 | #endif
--------------------------------------------------------------------------------
/lib/MpuHelper/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "MpuHelper",
3 | "version": "1.0.0"
4 | }
--------------------------------------------------------------------------------
/lib/WaveshareHelper/WaveshareHelper.cpp:
--------------------------------------------------------------------------------
1 | #include "WaveshareHelper.h"
2 |
3 | static const uint8_t EPD_BUSY = 4; // to EPD BUSY
4 | static const uint8_t EPD_CS = 5; // to EPD CS
5 | static const uint8_t EPD_RST = 16; // to EPD RST
6 | static const uint8_t EPD_DC = 17; // to EPD DC
7 | static const uint8_t EPD_SCK = 18; // to EPD CLK
8 | static const uint8_t EPD_MISO = 19; // Master-In Slave-Out not used, as no data from display
9 | static const uint8_t EPD_MOSI = 23; // to EPD DIN
10 |
11 | GxEPD2_BW display(GxEPD2_750_T7(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY));
12 | U8G2_FOR_ADAFRUIT_GFX u8g2Fonts; // https://github.com/olikraus/u8g2/wiki/fntlistall
13 |
14 | void WaveshareHelperClass::read() {
15 | preferences.begin("waveshare", true);
16 | host = preferences.getString("host");
17 | user = preferences.getString("user", "display");
18 | password = preferences.getString("password", "display");
19 | updateInterval = preferences.getInt("updateInterval", 30);
20 | preferences.end();
21 | }
22 |
23 | void WaveshareHelperClass::write() {
24 | preferences.begin("waveshare", false);
25 | preferences.putString("host", host);
26 | preferences.putString("user", user);
27 | preferences.putString("password", password);
28 | preferences.putInt("updateInterval", updateInterval);
29 | preferences.end();
30 | }
31 |
32 | void WaveshareHelperClass::setup() {
33 | unsigned long setupStartTime = millis();
34 | Serial.println("Setup Waveshare helper");
35 |
36 | read();
37 | initDisplay();
38 |
39 | setupDuration = millis() - setupStartTime;
40 | Serial.print("Setup Waveshare helper took ");
41 | Serial.println(setupDuration);
42 | }
43 |
44 | void WaveshareHelperClass::initDisplay() {
45 | display.init(115200, true, 2);
46 |
47 | SPI.end();
48 | SPI.begin(EPD_SCK, EPD_MISO, EPD_MOSI, EPD_CS);
49 | u8g2Fonts.begin(display); // connect u8g2 procedures to Adafruit GFX
50 | u8g2Fonts.setFontMode(1); // use u8g2 transparent mode (this is default)
51 | u8g2Fonts.setFontDirection(0); // left to right (this is default)
52 | u8g2Fonts.setForegroundColor(GxEPD_BLACK);
53 | u8g2Fonts.setBackgroundColor(GxEPD_WHITE);
54 | u8g2Fonts.setFont(u8g2_font_helvB10_tf); // select u8g2 font from here: https://github.com/olikraus/u8g2/wiki/fntlistall
55 | display.fillScreen(GxEPD_WHITE);
56 | display.setFullWindow();
57 | }
58 |
59 | void WaveshareHelperClass::update(bool disconnect) {
60 | if (host.length() == 0) return;
61 |
62 | u8g2Fonts.setBackgroundColor(GxEPD_BLACK);
63 | u8g2Fonts.setForegroundColor(GxEPD_WHITE);
64 | display.fillRect(0, 0, 320, 480, GxEPD_BLACK);
65 |
66 | drawStatus("CO2", "/jdev/sps/io/CO2Status", 40, 80);
67 | drawStatus("Qualität", "/jdev/sps/io/IAQStatus", 40, 200);
68 | drawStatus("Feuchtigkeit", "/jdev/sps/io/HumidityStatus", 40, 320);
69 |
70 | u8g2Fonts.setBackgroundColor(GxEPD_WHITE);
71 | u8g2Fonts.setForegroundColor(GxEPD_BLACK);
72 |
73 | drawUsage("Allgemein", "/jdev/sps/io/AVerbrauch/all", 360, 30);
74 | drawUsage("Heizung", "/jdev/sps/io/HVerbrauch/all", 360, 270);
75 |
76 | if (disconnect) {
77 | WiFi.disconnect();
78 | WiFi.mode(WIFI_OFF);
79 | }
80 |
81 | display.display(false); // Full screen update mode
82 | }
83 |
84 | void WaveshareHelperClass::drawStatus(String title, String urlPart, int offsetX, int offsetY) {
85 | DynamicJsonDocument doc(2048);
86 | if (!getAndParse(doc, urlPart)) return;
87 |
88 | // Read values
89 | String statusText = doc["LL"]["value"];
90 |
91 | u8g2Fonts.setFont(u8g2_font_helvB10_tf);
92 | drawString(offsetX, offsetY, title, LEFT);
93 |
94 | u8g2Fonts.setFont(u8g2_font_helvB24_tf);
95 | drawString(offsetX, offsetY + 40, statusText, LEFT);
96 | }
97 |
98 | void WaveshareHelperClass::drawUsage(String title, String urlPart, int offsetX, int offsetY) {
99 | DynamicJsonDocument doc(2048);
100 | if (!getAndParse(doc, urlPart)) return;
101 |
102 | u8g2Fonts.setFont(u8g2_font_helvB14_tf);
103 | drawString(offsetX, offsetY, title, LEFT);
104 |
105 | // Read values
106 | float usageC = doc["LL"]["output1"]["value"].as() * 1000;
107 | float usage0 = doc["LL"]["output3"]["value"].as();
108 | float usage1 = doc["LL"]["output4"]["value"].as();
109 | float usage2 = doc["LL"]["output5"]["value"].as();
110 |
111 | u8g2Fonts.setFont(u8g2_font_helvR24_tf);
112 | drawString(290 + offsetX, 120 + offsetY, String(usageC, 0) + " W", LEFT);
113 |
114 | u8g2Fonts.setFont(u8g2_font_helvB08_tf);
115 | drawString(290 + offsetX, 85 + offsetY, "Aktuell", LEFT);
116 |
117 | drawString(45 + offsetX, 50 + offsetY, "Vorgestern", CENTER);
118 | drawString(135 + offsetX, 50 + offsetY, "Gestern", CENTER);
119 | drawString(225 + offsetX, 50 + offsetY, "Heute", CENTER);
120 |
121 | display.drawLine(10 + offsetX, 150 + offsetY, 260 + offsetX, 150 + offsetY, GxEPD_BLACK);
122 |
123 | u8g2Fonts.setFont(u8g2_font_helvR14_tf);
124 | drawString(40 + offsetX, 170 + offsetY, String(usage2), CENTER);
125 | drawString(130 + offsetX, 170 + offsetY, String(usage1), CENTER);
126 | drawString(225 + offsetX, 170 + offsetY, String(usage0), CENTER);
127 |
128 | float maxUsage = max(usage2, usage1);
129 | maxUsage = max(maxUsage, usage0) / 100;
130 |
131 | float pUsage0 = usage0 / maxUsage * 0.7;
132 | float pUsage1 = usage1 / maxUsage * 0.7;
133 | float pUsage2 = usage2 / maxUsage * 0.7;
134 |
135 | display.fillRect(35 + offsetX, 151 + offsetY - pUsage2, 20, pUsage2, GxEPD_BLACK);
136 | display.fillRect(125 + offsetX, 151 + offsetY - pUsage1, 20, pUsage1, GxEPD_BLACK);
137 | display.fillRect(215 + offsetX, 151 + offsetY - pUsage0, 20, pUsage0, GxEPD_BLACK);
138 | }
139 |
140 | bool WaveshareHelperClass::getAndParse(JsonDocument &doc, String urlPart) {
141 | http.useHTTP10(true);
142 | http.begin(host + urlPart);
143 | http.setAuthorization(user.c_str(), password.c_str());
144 | int httpCode = http.GET();
145 |
146 | if (httpCode != HTTP_CODE_OK) {
147 | Serial.print("http error code: ");
148 | Serial.println(httpCode);
149 | return false;
150 | }
151 |
152 | DeserializationError error = deserializeJson(doc, http.getStream());
153 |
154 | http.end();
155 |
156 | // Test if parsing succeeds.
157 | if (error) {
158 | Serial.print(F("deserializeJson failed: "));
159 | Serial.println(error.c_str());
160 | return false;
161 | }
162 |
163 | return true;
164 | }
165 |
166 | void WaveshareHelperClass::drawString(int x, int y, String text, alignment align) {
167 | int16_t x1, y1;
168 | uint16_t w, h;
169 |
170 | display.setTextWrap(false);
171 | display.getTextBounds(text, x, y, &x1, &y1, &w, &h);
172 |
173 | if (align == RIGHT) x = x - w;
174 | if (align == CENTER) x = x - w / 2;
175 |
176 | u8g2Fonts.setCursor(x, y + h);
177 | u8g2Fonts.print(text);
178 | }
179 |
180 | void WaveshareHelperClass::sleep() {
181 | display.powerOff();
182 |
183 | // Write low to reset
184 | digitalWrite(SDA, LOW);
185 | digitalWrite(SCL, LOW);
186 |
187 | pinMode(BUILTIN_LED, INPUT); // If it's On, turn it off and some boards use GPIO-5 for SPI-SS, which remains low after screen use
188 | digitalWrite(BUILTIN_LED, HIGH);
189 |
190 | long wakeupTime = uS_TO_S_FACTOR * 60UL * long(updateInterval);
191 | esp_sleep_enable_timer_wakeup(wakeupTime);
192 | esp_deep_sleep_start();
193 | }
194 |
195 | void WaveshareHelperClass::server() {
196 | Serial.println("Setup Waveshare server");
197 |
198 | WebServerHelper.server.on("/api/waveshare", HTTP_GET, [this](AsyncWebServerRequest *request) {
199 | int args = request->args();
200 |
201 | if (args > 0) {
202 | request->send(200, "text/plain", "message received");
203 | Serial.println("Update Waveshare settings");
204 |
205 | if (request->hasArg("host")) host = request->arg("host");
206 | if (request->hasArg("user")) user = request->arg("user");
207 | if (request->hasArg("password")) password = request->arg("password").toInt();
208 | if (request->hasArg("updateInterval")) updateInterval = request->arg("updateInterval").toInt();
209 |
210 | write();
211 | ESP.restart();
212 |
213 | } else {
214 | AsyncJsonResponse *response = new AsyncJsonResponse();
215 | response->addHeader("Server", "ESP Async Web Server");
216 | JsonVariant &root = response->getRoot();
217 |
218 | root["setupDuration"] = setupDuration;
219 | root["host"] = host;
220 | root["user"] = user;
221 | root["updateInterval"] = updateInterval;
222 |
223 | response->setLength();
224 | request->send(response);
225 | }
226 | });
227 | }
228 |
229 | WaveshareHelperClass WaveshareHelper;
230 |
--------------------------------------------------------------------------------
/lib/WaveshareHelper/WaveshareHelper.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef WaveshareHelper_h
3 | #define WaveshareHelper_h
4 | #define ENABLE_GxEPD2_display 1
5 |
6 | #include "ArduinoJson.h"
7 | #include "AsyncJson.h"
8 | #include "GxEPD2_BW.h"
9 | // #include "I2Cdev.h"
10 | #include "HTTPClient.h"
11 | #include "SPI.h"
12 | #include "U8g2_for_Adafruit_GFX.h"
13 | #include "WebServerHelper.h"
14 | #include "WiFi.h"
15 | #include "Wire.h"
16 |
17 | #define SCREEN_WIDTH 800
18 | #define SCREEN_HEIGHT 480
19 | #define uS_TO_S_FACTOR 1000000
20 |
21 | enum alignment { LEFT,
22 | RIGHT,
23 | CENTER };
24 |
25 | class WaveshareHelperClass {
26 | private:
27 | Preferences preferences;
28 | HTTPClient http;
29 | String host;
30 | String user;
31 | String password;
32 | int32_t updateInterval;
33 |
34 | void read();
35 | void write();
36 |
37 | void readValues();
38 | void sendValues();
39 |
40 | unsigned long setupDuration;
41 |
42 | void initDisplay();
43 |
44 | bool getAndParse(JsonDocument &doc, String urlPart);
45 | void drawStatus(String title, String urlPart, int offsetX, int offsetY);
46 | void drawUsage(String title, String urlPart, int offsetX, int offsetY);
47 | void drawString(int x, int y, String text, alignment align);
48 |
49 | public:
50 | void setup();
51 | void server();
52 | void update(bool disconnect);
53 | void sleep();
54 | };
55 |
56 | extern WaveshareHelperClass WaveshareHelper;
57 |
58 | #endif
--------------------------------------------------------------------------------
/lib/WaveshareHelper/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "WaveshareHelper",
3 | "version": "1.0.0"
4 | }
--------------------------------------------------------------------------------
/lib/WebServerHelper/WebServerHelper.cpp:
--------------------------------------------------------------------------------
1 | #include "WebServerHelper.h"
2 |
3 | WebServerHelperClass::WebServerHelperClass() : server(80){};
4 |
5 | void WebServerHelperClass::start(String application) {
6 | Serial.println("WebServer start");
7 |
8 | app = application;
9 |
10 | if (!SPIFFS.begin()) {
11 | Serial.println("An Error has occurred while mounting SPIFFS");
12 | return;
13 | }
14 |
15 | server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
16 | request->send(SPIFFS, "/index.html", "text/html");
17 | });
18 |
19 | server.on("/bundle.js", HTTP_GET, [](AsyncWebServerRequest *request) {
20 | request->send(SPIFFS, "/bundle.js");
21 | });
22 |
23 | server.on("/api/restart", HTTP_GET, [](AsyncWebServerRequest *request) {
24 | request->send(200, "text/plain", "message received");
25 | ESP.restart();
26 | });
27 |
28 | server.on("/api/sleep", HTTP_GET, [this](AsyncWebServerRequest *request) {
29 | request->send(200, "text/plain", "message received");
30 |
31 | if (sleep) {
32 | sleep();
33 | }
34 | });
35 |
36 | WebServerHelper.server.on("/api/application", HTTP_GET, [this](AsyncWebServerRequest *request) {
37 | AsyncJsonResponse *response = new AsyncJsonResponse();
38 | response->addHeader("Server", "ESP Async Web Server");
39 |
40 | JsonVariant &root = response->getRoot();
41 | root["application"] = app;
42 |
43 | response->setLength();
44 | request->send(response);
45 | });
46 |
47 | server.on("/api/esp", HTTP_GET, [this](AsyncWebServerRequest *request) {
48 | AsyncJsonResponse *response = new AsyncJsonResponse();
49 | response->addHeader("Server", "ESP Async Web Server");
50 |
51 | JsonVariant &root = response->getRoot();
52 | root["heap"] = ESP.getFreeHeap();
53 | root["cupFreq"] = ESP.getCpuFreqMHz();
54 | root["sketchSize"] = ESP.getSketchSize();
55 | root["sketchSizeFree"] = ESP.getFreeSketchSpace();
56 |
57 | response->setLength();
58 | request->send(response);
59 | });
60 |
61 | server.on(
62 | "/api/update", HTTP_POST, [this](AsyncWebServerRequest *request) {
63 | request->send_P(200, "text/plain", "message received");
64 | ESP.restart(); },
65 | [this](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
66 | uploadFile(U_FLASH, request, filename, index, data, len, final);
67 | });
68 |
69 | server.on(
70 | "/api/updateFS", HTTP_POST, [this](AsyncWebServerRequest *request) {
71 | request->send_P(200, "text/plain", "message received");
72 | ESP.restart(); },
73 | [this](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
74 | uploadFile(U_SPIFFS, request, filename, index, data, len, final);
75 | });
76 |
77 | server.begin();
78 | Serial.println("WebServer running");
79 | }
80 |
81 | void WebServerHelperClass::uploadFile(int command, AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
82 | if (!index) {
83 | Serial.printf("UploadStart: %s\n", filename.c_str());
84 | if (!Update.begin(UPDATE_SIZE_UNKNOWN, command)) {
85 | Update.printError(Serial);
86 | }
87 | }
88 |
89 | if (!Update.hasError()) {
90 | if (Update.write(data, len) != len) {
91 | Update.printError(Serial);
92 | }
93 | }
94 |
95 | if (final) {
96 | if (Update.end(true)) {
97 | Serial.printf("Update Success: %uB\n", index + len);
98 | } else {
99 | Update.printError(Serial);
100 | }
101 | }
102 | }
103 |
104 | void WebServerHelperClass::onSleep(SleepFunc sleepFn) {
105 | sleep = sleepFn;
106 | }
107 |
108 | WebServerHelperClass WebServerHelper;
109 |
--------------------------------------------------------------------------------
/lib/WebServerHelper/WebServerHelper.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef WebServerHelper_h
3 | #define WebServerHelper_h
4 |
5 | #include "ArduinoJson.h"
6 | #include "AsyncJson.h"
7 | #include "ESPAsyncWebServer.h"
8 | #include "SPIFFS.h"
9 | #include "Update.h"
10 |
11 | class WebServerHelperClass {
12 | private:
13 | void uploadFile(int command, AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
14 |
15 | public:
16 | String app;
17 | AsyncWebServer server;
18 | WebServerHelperClass();
19 | void start(String application);
20 |
21 | using SleepFunc = void (*)();
22 | SleepFunc sleep;
23 | void onSleep(SleepFunc sleep = nullptr);
24 | };
25 |
26 | extern WebServerHelperClass WebServerHelper;
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/lib/WebServerHelper/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "WebServerHelper",
3 | "version": "1.0.0"
4 | }
--------------------------------------------------------------------------------
/lib/WiFiHelper/WiFiHelper.cpp:
--------------------------------------------------------------------------------
1 | #include "WiFiHelper.h"
2 |
3 | void WiFiHelperClass::read() {
4 | preferences.begin("esp", true); // create folder
5 |
6 | ssid = preferences.getString("ssid", DEFAULT_SSID);
7 | password = preferences.getString("password", DEFAULT_PSK);
8 | host = preferences.getString("host", DEFAULT_HOST);
9 |
10 | mode = preferences.getString("mode", "dhcp");
11 | ipv4 = preferences.getString("ipv4");
12 | dns = preferences.getString("dns");
13 | subnet = preferences.getString("subnet");
14 | gateway = preferences.getString("gateway");
15 |
16 | preferences.end();
17 | }
18 |
19 | void WiFiHelperClass::write() {
20 | preferences.begin("esp", false); // create folder
21 |
22 | preferences.putString("ssid", ssid);
23 | preferences.putString("password", password);
24 | preferences.putString("host", host);
25 |
26 | preferences.putString("mode", mode);
27 | preferences.putString("ipv4", ipv4);
28 | preferences.putString("dns", dns);
29 | preferences.putString("subnet", subnet);
30 | preferences.putString("gateway", gateway);
31 |
32 | preferences.end();
33 | }
34 |
35 | void WiFiHelperClass::setup() {
36 | read();
37 | }
38 |
39 | bool WiFiHelperClass::connect(bool firstConnect) {
40 | if (WiFi.status() == WL_CONNECTED) return true;
41 |
42 | unsigned long wifiStartTime = millis();
43 |
44 | if (mode == "static") {
45 | IPAddress ipv4IP;
46 | IPAddress dnsIP;
47 | IPAddress subnetIP;
48 | IPAddress gatewayIP;
49 |
50 | ipv4IP.fromString(ipv4);
51 | dnsIP.fromString(dns);
52 | subnetIP.fromString(subnet);
53 | gatewayIP.fromString(gateway);
54 |
55 | Serial.print("WIFI use static IP: ");
56 | Serial.println(ipv4);
57 |
58 | WiFi.config(ipv4IP, gatewayIP, subnetIP, dnsIP);
59 | }
60 |
61 | Serial.print("WIFI connect to ");
62 | Serial.println(ssid);
63 |
64 | WiFi.mode(WIFI_STA);
65 |
66 | WiFi.setSleep(true);
67 | WiFi.begin(ssid.c_str(), password.c_str());
68 |
69 | // The first connect can take a while
70 | // use the built in function to wait (up to 10sec)
71 | if (firstConnect) {
72 | WiFi.waitForConnectResult();
73 | } else {
74 | int retry = 0;
75 | while (WiFi.status() != WL_CONNECTED && retry++ < 100) {
76 | delay(10);
77 | }
78 | }
79 |
80 | wifiTime = millis() - wifiStartTime;
81 | Serial.print("WIFI connection took ");
82 | Serial.println(String(wifiTime));
83 |
84 | return WiFi.status() == WL_CONNECTED;
85 | }
86 |
87 | void WiFiHelperClass::setupAP() {
88 | // configure WiFi AP
89 | Serial.println("WIFI Setup AP");
90 |
91 | WiFi.disconnect();
92 | WiFi.softAP("espbs", "password");
93 |
94 | IPAddress myIP = WiFi.softAPIP();
95 | Serial.print("AP IP address: ");
96 | Serial.println(myIP.toString());
97 | }
98 |
99 | void WiFiHelperClass::setupMDNS() {
100 | // use mdns for host name resolution
101 | if (!MDNS.begin(host.c_str())) {
102 | Serial.println("Error setting up MDNS responder!");
103 | }
104 | Serial.print("mDNS responder started connect to http://");
105 | Serial.print(host);
106 | Serial.println(".local");
107 | }
108 |
109 | void WiFiHelperClass::sleep() {
110 | WiFi.disconnect(true);
111 | WiFi.mode(WIFI_OFF);
112 |
113 | btStop();
114 |
115 | adc_power_off();
116 | esp_wifi_stop();
117 | }
118 |
119 | void WiFiHelperClass::server() {
120 | Serial.println("Setup WiFi helper");
121 |
122 | if (WiFiHelper.connect(true)) {
123 | WiFiHelper.setupMDNS();
124 | } else {
125 | WiFiHelper.setupAP();
126 | }
127 |
128 | WebServerHelper.server.on("/api/wifi", HTTP_GET, [this](AsyncWebServerRequest *request) {
129 | int args = request->args();
130 |
131 | if (args > 0) {
132 | request->send(200, "text/plain", "message received");
133 |
134 | Serial.println("Update wifi settings");
135 | if (request->hasArg("host")) host = request->arg("host");
136 | if (request->hasArg("ssid")) ssid = request->arg("ssid");
137 | if (request->hasArg("password")) password = request->arg("password");
138 |
139 | write();
140 | WiFi.disconnect();
141 | ESP.restart();
142 |
143 | } else {
144 | AsyncJsonResponse *response = new AsyncJsonResponse();
145 | response->addHeader("Server", "ESP Async Web Server");
146 |
147 | JsonVariant &root = response->getRoot();
148 | root["host"] = host;
149 | root["ssid"] = ssid;
150 |
151 | root["rssi"] = String(WiFi.RSSI());
152 | root["time"] = String(wifiTime);
153 |
154 | response->setLength();
155 | request->send(response);
156 | }
157 | });
158 |
159 | WebServerHelper.server.on("/api/network", HTTP_GET, [this](AsyncWebServerRequest *request) {
160 | int args = request->args();
161 |
162 | if (args > 0) {
163 | request->send(200, "text/plain", "message received");
164 |
165 | Serial.println("Update network settings");
166 | if (request->hasArg("mode")) mode = request->arg("mode");
167 | if (request->hasArg("ipv4")) ipv4 = request->arg("ipv4");
168 | if (request->hasArg("dns")) dns = request->arg("dns");
169 | if (request->hasArg("subnet")) subnet = request->arg("subnet");
170 | if (request->hasArg("gateway")) gateway = request->arg("gateway");
171 |
172 | write();
173 | WiFi.disconnect();
174 | ESP.restart();
175 | } else {
176 | AsyncJsonResponse *response = new AsyncJsonResponse();
177 | response->addHeader("Server", "ESP Async Web Server");
178 |
179 | JsonVariant &root = response->getRoot();
180 | root["mode"] = mode;
181 | root["ipv4"] = WiFi.localIP().toString();
182 | root["dns"] = WiFi.dnsIP().toString();
183 | root["subnet"] = WiFi.subnetMask().toString();
184 | root["gateway"] = WiFi.gatewayIP().toString();
185 |
186 | response->setLength();
187 | request->send(response);
188 | }
189 | });
190 | }
191 |
192 | WiFiHelperClass WiFiHelper;
--------------------------------------------------------------------------------
/lib/WiFiHelper/WiFiHelper.h:
--------------------------------------------------------------------------------
1 | #ifndef WiFiHelper_h
2 | #define WiFiHelper_h
3 |
4 | #include "AsyncJson.h"
5 | #include "ESPmDNS.h"
6 | #include "Preferences.h"
7 | #include "WebServerHelper.h"
8 | #include "WiFi.h"
9 | #include "WiFiAP.h"
10 | #include "WiFiClient.h"
11 | #include "driver/adc.h"
12 | #include "esp_wifi.h"
13 |
14 | #define DEFAULT_HOST "esp32"
15 | #define DEFAULT_SSID "ESP32"
16 | #define DEFAULT_PSK "password"
17 |
18 | class WiFiHelperClass {
19 | private:
20 | unsigned long wifiTime;
21 | Preferences preferences;
22 |
23 | String ssid;
24 | String password;
25 | String host;
26 |
27 | String mode;
28 | String ipv4;
29 | String dns;
30 | String subnet;
31 | String gateway;
32 |
33 | void read();
34 | void write();
35 |
36 | void setupAP();
37 | void setupMDNS();
38 |
39 | public:
40 | void setup();
41 | void server();
42 | bool connect(bool firstConnect = false);
43 | void sleep();
44 | };
45 |
46 | extern WiFiHelperClass WiFiHelper;
47 |
48 | #endif
--------------------------------------------------------------------------------
/lib/WiFiHelper/library.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "WiFiHelper",
3 | "version": "1.0.0"
4 | }
--------------------------------------------------------------------------------
/partitions_custom.csv:
--------------------------------------------------------------------------------
1 | # Name, Type, SubType, Offset, Size, Flags
2 | nvs, data, nvs, 0x9000, 0x5000,
3 | otadata, data, ota, 0xe000, 0x2000,
4 | app0, app, ota_0, 0x10000, 0x160000,
5 | app1, app, ota_1, 0x170000,0x160000,
6 | spiffs, data, spiffs, 0x2D0000,0x130000,
7 |
8 |
9 | # default partition table
10 | # Name, Type, SubType, Offset, Size, Flags
11 | # nvs, data, nvs, 0x9000, 0x5000,
12 | # otadata, data, ota, 0xe000, 0x2000,
13 | # app0, app, ota_0, 0x10000, 0x140000,
14 | # app1, app, ota_1, 0x150000,0x140000,
15 | # spiffs, data, spiffs, 0x290000,0x170000,
--------------------------------------------------------------------------------
/platformio.ini:
--------------------------------------------------------------------------------
1 | ; PlatformIO Project Configuration File
2 | ;
3 | ; Build options: build flags, source filter
4 | ; Upload options: custom upload port, speed and extra flags
5 | ; Library options: dependencies, extra library storages
6 | ; Advanced options: extra scripting
7 | ;
8 | ; Please visit documentation for the other options and examples
9 | ; https://docs.platformio.org/page/projectconf.html
10 |
11 | [platformio]
12 | description = ESPBS Base system
13 |
14 | [env:lolin_d32]
15 | platform = espressif32
16 | board = lolin_d32
17 | framework = arduino
18 | monitor_speed = 115200
19 | board_build.partitions = partitions_custom.csv
20 | ; build_flags = -D CONFIG_FREERTOS_UNICORE
21 | board_build.f_cpu = 240000000L
22 |
23 | ; ---- CUBE ----
24 | ;src_filter = +
25 | ;lib_deps = FS, ESP Async WebServer, ArduinoJson, ESPAsyncTCP, Update
26 |
27 | ; ---- CO2 ----
28 | src_filter = +
29 | lib_deps = FS, ESP Async WebServer, ArduinoJson, ESPAsyncTCP, Update, MH-Z19@1.5.3, BSEC Software Library
30 | build_flags =
31 | -I .pio/libdeps/BSECSoftwareLibrary/src/bme680
32 | -L .pio/libdeps/BSECSoftwareLibrary/src/esp32
33 | -lalgobsec
34 |
35 | ; ---- AqiLed ----
36 | ; src_filter = +
37 | ; lib_deps = FS, ESP Async WebServer, ArduinoJson, ESPAsyncTCP, Update, BSEC Software Library, fastled/FastLED @ ^3.3.3
38 | ; build_flags =
39 | ; -I .pio/libdeps/BSECSoftwareLibrary/src/bme680
40 | ; -L .pio/libdeps/BSECSoftwareLibrary/src/esp32
41 | ; -lalgobsec
42 |
43 | ; ---- Waveshare display ----
44 | ; src_filter = +
45 | ; lib_deps = FS, ESP Async WebServer, ArduinoJson, ESPAsyncTCP, Update, GxEPD2, U8g2_for_Adafruit_GFX
46 |
47 | ; ---- Knob ----
48 | ; src_filter = +
49 | ; lib_deps = FS, ESP Async WebServer, ArduinoJson, ESPAsyncTCP, Update, igorantolic/Ai Esp32 Rotary Encoder @ ^1.0
50 |
--------------------------------------------------------------------------------
/screenshots/aqiLed_wiring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/aqiLed_wiring.png
--------------------------------------------------------------------------------
/screenshots/aqiled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/aqiled.png
--------------------------------------------------------------------------------
/screenshots/co2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/co2.png
--------------------------------------------------------------------------------
/screenshots/co2_wiring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/co2_wiring.png
--------------------------------------------------------------------------------
/screenshots/cube.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/cube.png
--------------------------------------------------------------------------------
/screenshots/cube_wiring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/cube_wiring.png
--------------------------------------------------------------------------------
/screenshots/display.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/display.png
--------------------------------------------------------------------------------
/screenshots/display_wiring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/display_wiring.png
--------------------------------------------------------------------------------
/screenshots/firmware.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/firmware.png
--------------------------------------------------------------------------------
/screenshots/knob.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/knob.png
--------------------------------------------------------------------------------
/screenshots/knob_wiring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/knob_wiring.png
--------------------------------------------------------------------------------
/screenshots/mpu6050.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/mpu6050.png
--------------------------------------------------------------------------------
/screenshots/sleep.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/sleep.png
--------------------------------------------------------------------------------
/screenshots/updateWebsite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/updateWebsite.png
--------------------------------------------------------------------------------
/screenshots/upload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/upload.png
--------------------------------------------------------------------------------
/screenshots/website.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/website.png
--------------------------------------------------------------------------------
/screenshots/wifi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Lillifee/espbs/15b17905f2afefe52391940dabd8823d520f9098/screenshots/wifi.png
--------------------------------------------------------------------------------
/src/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # This file was automatically generated for projects
2 | # without default 'CMakeLists.txt' file.
3 |
4 | FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*)
5 |
6 | idf_component_register(SRCS ${app_sources})
7 |
--------------------------------------------------------------------------------
/src/aqiLed.cpp:
--------------------------------------------------------------------------------
1 | #include "Arduino.h"
2 | #include "BsecHelper.h"
3 | #include "LedHelper.h"
4 | #include "WebServerHelper.h"
5 | #include "WifiHelper.h"
6 |
7 | void setup() {
8 | Serial.begin(115200);
9 |
10 | WiFiHelper.setup();
11 | WiFiHelper.server();
12 |
13 | LedHelper.setup();
14 | LedHelper.server();
15 |
16 | BsecHelper.setup(BME680_I2C_ADDR_SECONDARY);
17 | BsecHelper.server();
18 |
19 | WebServerHelper.start("aqiLed");
20 | }
21 |
22 | void loop() {
23 | // Stop bsec readings during animation or test
24 | if (LedHelper.animation == 0 && LedHelper.test == 0) {
25 | BsecHelper.loop();
26 | }
27 |
28 | LedHelper.value = BsecHelper.iaqSensor.iaq + 0.5;
29 | LedHelper.loop();
30 | }
31 |
--------------------------------------------------------------------------------
/src/co2.cpp:
--------------------------------------------------------------------------------
1 | #include "Arduino.h"
2 | #include "BsecHelper.h"
3 | #include "Co2Helper.h"
4 | #include "WebServerHelper.h"
5 | #include "WifiHelper.h"
6 |
7 | void setup() {
8 | Serial.begin(115200);
9 |
10 | WiFiHelper.setup();
11 | WiFiHelper.server();
12 |
13 | Co2Helper.setup();
14 | Co2Helper.server();
15 |
16 | BsecHelper.setup(BME680_I2C_ADDR_PRIMARY);
17 | BsecHelper.server();
18 |
19 | WebServerHelper.start("co2");
20 | }
21 |
22 | void loop() {
23 | Co2Helper.loop();
24 | BsecHelper.loop();
25 | }
26 |
--------------------------------------------------------------------------------
/src/cube.cpp:
--------------------------------------------------------------------------------
1 | #include "MpuHelper.h"
2 | #include "WebServerHelper.h"
3 | #include "WifiHelper.h"
4 | #include "rom/rtc.h"
5 |
6 | #define LED_BUILTIN 5
7 | unsigned long sleepTime;
8 | RESET_REASON resetReason;
9 |
10 | void deepSleep() {
11 | WiFiHelper.sleep();
12 | MpuHelper.sleep();
13 |
14 | esp_sleep_enable_ext0_wakeup(GPIO_NUM_33, 1);
15 | esp_deep_sleep_start();
16 | }
17 |
18 | void setup() {
19 | Serial.begin(115200);
20 |
21 | WiFiHelper.setup();
22 | MpuHelper.setup();
23 |
24 | resetReason = rtc_get_reset_reason(0);
25 |
26 | if (resetReason == POWERON_RESET) {
27 | pinMode(LED_BUILTIN, OUTPUT);
28 |
29 | WiFiHelper.server();
30 | MpuHelper.server();
31 |
32 | WebServerHelper.onSleep(deepSleep);
33 | WebServerHelper.start("cube");
34 | } else if (!WiFiHelper.connect()) {
35 | deepSleep();
36 | }
37 |
38 | sleepTime = millis() + 1000;
39 | }
40 |
41 | void loop() {
42 | MpuHelper.loop();
43 |
44 | if (resetReason == POWERON_RESET) {
45 | digitalWrite(LED_BUILTIN, HIGH);
46 | delay(500);
47 |
48 | digitalWrite(LED_BUILTIN, LOW);
49 | delay(500);
50 | } else {
51 | if (MpuHelper.prevSide != MpuHelper.side)
52 | sleepTime = millis() + 1000;
53 |
54 | if (millis() >= sleepTime)
55 | deepSleep();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/display.cpp:
--------------------------------------------------------------------------------
1 | #include "WaveshareHelper.h"
2 | #include "WebServerHelper.h"
3 | #include "WifiHelper.h"
4 | #include "rom/rtc.h"
5 |
6 | RESET_REASON resetReason;
7 |
8 | void deepSleep() {
9 | WiFiHelper.sleep();
10 | WaveshareHelper.sleep();
11 | }
12 |
13 | void setup() {
14 | Serial.begin(115200);
15 |
16 | WiFiHelper.setup();
17 | WaveshareHelper.setup();
18 |
19 | resetReason = rtc_get_reset_reason(0);
20 |
21 | // Enter configuration mode on reset
22 | if (resetReason == POWERON_RESET) {
23 | pinMode(LED_BUILTIN, OUTPUT);
24 |
25 | WiFiHelper.server();
26 | WaveshareHelper.server();
27 |
28 | WebServerHelper.onSleep(deepSleep);
29 | WebServerHelper.start("display");
30 |
31 | WaveshareHelper.update(false);
32 | return;
33 | }
34 |
35 | if (WiFiHelper.connect()) {
36 | WaveshareHelper.update(true);
37 | }
38 |
39 | deepSleep();
40 | }
41 |
42 | void loop() {
43 | // Loop is only executed in configuration mode.
44 | digitalWrite(LED_BUILTIN, HIGH);
45 | delay(500);
46 |
47 | digitalWrite(LED_BUILTIN, LOW);
48 | delay(500);
49 | }
50 |
--------------------------------------------------------------------------------
/src/knob.cpp:
--------------------------------------------------------------------------------
1 | #include "KnobHelper.h"
2 | #include "WebServerHelper.h"
3 | #include "WifiHelper.h"
4 | #include "rom/rtc.h"
5 |
6 | unsigned long sleepTime;
7 | RESET_REASON resetReason;
8 |
9 | void deepSleep() {
10 | WiFiHelper.sleep();
11 | KnobHelper.sleep();
12 |
13 | Serial.println("sleep");
14 | esp_sleep_enable_ext0_wakeup(GPIO_NUM_13, 0);
15 | esp_deep_sleep_start();
16 | }
17 |
18 | void setup() {
19 | Serial.begin(115200);
20 |
21 | WiFiHelper.setup();
22 | KnobHelper.setup();
23 |
24 | resetReason = rtc_get_reset_reason(0);
25 |
26 | if (resetReason == POWERON_RESET) {
27 | WiFiHelper.server();
28 | KnobHelper.server();
29 |
30 | WebServerHelper.onSleep(deepSleep);
31 | WebServerHelper.start("knob");
32 | } else if (!WiFiHelper.connect()) {
33 | deepSleep();
34 | }
35 |
36 | sleepTime = millis() + 2000;
37 | }
38 |
39 | void loop() {
40 | KnobHelper.loop();
41 | delay(50);
42 |
43 | if (resetReason == POWERON_RESET) {
44 | digitalWrite(LED_BUILTIN, HIGH);
45 | delay(500);
46 |
47 | digitalWrite(LED_BUILTIN, LOW);
48 | delay(500);
49 | } else {
50 | if (KnobHelper.value != KnobHelper.prevValue)
51 | sleepTime = millis() + 2000;
52 |
53 | if (millis() >= sleepTime)
54 | deepSleep();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/test/README:
--------------------------------------------------------------------------------
1 |
2 | This directory is intended for PIO Unit Testing and project tests.
3 |
4 | Unit Testing is a software testing method by which individual units of
5 | source code, sets of one or more MCU program modules together with associated
6 | control data, usage procedures, and operating procedures, are tested to
7 | determine whether they are fit for use. Unit testing finds problems early
8 | in the development cycle.
9 |
10 | More information about PIO Unit Testing:
11 | - https://docs.platformio.org/page/plus/unit-testing.html
12 |
--------------------------------------------------------------------------------