├── Firmware-Src ├── README.md ├── Libraries │ ├── BMP085 │ │ ├── BMP085.jpg │ │ ├── BMP085.h │ │ ├── BMP085.cpp │ │ └── README.txt │ ├── TSL2561 │ │ ├── keywords.txt │ │ ├── examples │ │ │ └── SFE_TSL2561_example │ │ │ │ └── SFE_TSL2561_example.ino │ │ ├── TSL2561.h │ │ └── TSL2561.cpp │ ├── Wire │ │ ├── examples │ │ │ ├── master_writer │ │ │ │ └── master_writer.ino │ │ │ ├── slave_sender │ │ │ │ └── slave_sender.ino │ │ │ ├── master_reader │ │ │ │ └── master_reader.ino │ │ │ ├── slave_receiver │ │ │ │ └── slave_receiver.ino │ │ │ ├── digital_potentiometer │ │ │ │ └── digital_potentiometer.ino │ │ │ └── SFRRanger_reader │ │ │ │ └── SFRRanger_reader.ino │ │ ├── keywords.txt │ │ ├── utility │ │ │ ├── twi.h │ │ │ └── twi.c │ │ ├── Wire.h │ │ └── Wire.cpp │ └── Sensirion │ │ ├── examples │ │ ├── SimpleSensirion │ │ │ └── SimpleSensirion.pde │ │ └── NonBlocking │ │ │ └── NonBlocking.pde │ │ ├── keywords.txt │ │ ├── README.txt │ │ ├── Sensirion.h │ │ └── Sensirion.cpp ├── ccu-changelog.txt ├── WetterSensor.h ├── Register.h └── WetterSensor.ino ├── .gitignore ├── Contrib ├── control-fhem.txt ├── flash-ota.sh ├── CCU │ ├── HB-UW-Sen-THPL_CCU-addon.tgz │ ├── build.sh │ └── HB-UW-Sen-THPL_CCU-addon-src │ │ ├── firmware │ │ └── rftypes │ │ │ ├── hb_uw_sen_thpl.xml │ │ │ └── hb_uw_sen_thpl_le_v0_11.xml │ │ ├── www │ │ └── config │ │ │ └── img │ │ │ └── devices │ │ │ ├── 50 │ │ │ ├── hb-uw-sen-thpl-i_thumb.png │ │ │ └── hb-uw-sen-thpl-o_thumb.png │ │ │ └── 250 │ │ │ ├── hb-uw-sen-thpl-i.png │ │ │ └── hb-uw-sen-thpl-o.png │ │ └── update_script ├── build-tool.sh ├── FHEM │ └── HMConfig_SenTHPL.pm └── hex2eq3.php ├── Images ├── HB-UW-Sen-THPL-O.jpg ├── CC1101-Sensor-Außen Platine_1.jpg ├── HB-UW-Sen-THPL-O_filter_foil.JPG ├── HB-UW-Sen-THPL-drill_dimension.jpg ├── HB-UW-Sen-THPL-O_Overview_Rev_1.0.jpg └── CC1101-Sensor Firmwareupdate mit dem Raspberry Pi.jpg ├── Schematic ├── Schematic-RF.pdf └── SHT10-Adapter.brd ├── .gitmodules ├── Firmware-Release ├── HB-UW-Sen-THPL_update_V0_14_001_150301-I.tgz ├── HB-UW-Sen-THPL_update_V0_14_001_150301-O.tgz ├── HB-UW-Sen-THPL_update_V0_15_000_150303-I.tgz └── HB-UW-Sen-THPL_update_V0_15_000_150303-O.tgz └── README.md /Firmware-Src/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .settings 2 | .project 3 | .cproject 4 | arduino 5 | Release 6 | -------------------------------------------------------------------------------- /Contrib/control-fhem.txt: -------------------------------------------------------------------------------- 1 | UPD 2015-04-27_20:35:00 3409 FHEM/HMConfig_SenTHPL.pm -------------------------------------------------------------------------------- /Contrib/flash-ota.sh: -------------------------------------------------------------------------------- 1 | sudo ../../../../../FHEM/FHEM.dev/hmcfgusb/flash-ota -c /dev/ttyACM0 -f $1 -s $2 -------------------------------------------------------------------------------- /Images/HB-UW-Sen-THPL-O.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Images/HB-UW-Sen-THPL-O.jpg -------------------------------------------------------------------------------- /Schematic/Schematic-RF.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Schematic/Schematic-RF.pdf -------------------------------------------------------------------------------- /Contrib/CCU/HB-UW-Sen-THPL_CCU-addon.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Contrib/CCU/HB-UW-Sen-THPL_CCU-addon.tgz -------------------------------------------------------------------------------- /Firmware-Src/Libraries/BMP085/BMP085.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Firmware-Src/Libraries/BMP085/BMP085.jpg -------------------------------------------------------------------------------- /Images/CC1101-Sensor-Außen Platine_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Images/CC1101-Sensor-Außen Platine_1.jpg -------------------------------------------------------------------------------- /Images/HB-UW-Sen-THPL-O_filter_foil.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Images/HB-UW-Sen-THPL-O_filter_foil.JPG -------------------------------------------------------------------------------- /Images/HB-UW-Sen-THPL-drill_dimension.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Images/HB-UW-Sen-THPL-drill_dimension.jpg -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Firmware-Src/Libraries/AskSin"] 2 | path = Firmware-Src/Libraries/AskSin 3 | url = git@github.com:kc-GitHub/AskSin.git 4 | -------------------------------------------------------------------------------- /Images/HB-UW-Sen-THPL-O_Overview_Rev_1.0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Images/HB-UW-Sen-THPL-O_Overview_Rev_1.0.jpg -------------------------------------------------------------------------------- /Images/CC1101-Sensor Firmwareupdate mit dem Raspberry Pi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Images/CC1101-Sensor Firmwareupdate mit dem Raspberry Pi.jpg -------------------------------------------------------------------------------- /Firmware-Release/HB-UW-Sen-THPL_update_V0_14_001_150301-I.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Firmware-Release/HB-UW-Sen-THPL_update_V0_14_001_150301-I.tgz -------------------------------------------------------------------------------- /Firmware-Release/HB-UW-Sen-THPL_update_V0_14_001_150301-O.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Firmware-Release/HB-UW-Sen-THPL_update_V0_14_001_150301-O.tgz -------------------------------------------------------------------------------- /Firmware-Release/HB-UW-Sen-THPL_update_V0_15_000_150303-I.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Firmware-Release/HB-UW-Sen-THPL_update_V0_15_000_150303-I.tgz -------------------------------------------------------------------------------- /Firmware-Release/HB-UW-Sen-THPL_update_V0_15_000_150303-O.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Firmware-Release/HB-UW-Sen-THPL_update_V0_15_000_150303-O.tgz -------------------------------------------------------------------------------- /Contrib/CCU/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd HB-UW-Sen-THPL_CCU-addon-src 4 | chmod +x update_script 5 | tar -H gnu -zcvf HB-UW-Sen-THPL_CCU-addon.tgz * 6 | mv HB-UW-Sen-THPL_CCU-addon.tgz .. 7 | cd .. -------------------------------------------------------------------------------- /Contrib/CCU/HB-UW-Sen-THPL_CCU-addon-src/firmware/rftypes/hb_uw_sen_thpl.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Contrib/CCU/HB-UW-Sen-THPL_CCU-addon-src/firmware/rftypes/hb_uw_sen_thpl.xml -------------------------------------------------------------------------------- /Contrib/CCU/HB-UW-Sen-THPL_CCU-addon-src/firmware/rftypes/hb_uw_sen_thpl_le_v0_11.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Contrib/CCU/HB-UW-Sen-THPL_CCU-addon-src/firmware/rftypes/hb_uw_sen_thpl_le_v0_11.xml -------------------------------------------------------------------------------- /Contrib/CCU/HB-UW-Sen-THPL_CCU-addon-src/www/config/img/devices/250/hb-uw-sen-thpl-i.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Contrib/CCU/HB-UW-Sen-THPL_CCU-addon-src/www/config/img/devices/250/hb-uw-sen-thpl-i.png -------------------------------------------------------------------------------- /Contrib/CCU/HB-UW-Sen-THPL_CCU-addon-src/www/config/img/devices/250/hb-uw-sen-thpl-o.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Contrib/CCU/HB-UW-Sen-THPL_CCU-addon-src/www/config/img/devices/250/hb-uw-sen-thpl-o.png -------------------------------------------------------------------------------- /Contrib/CCU/HB-UW-Sen-THPL_CCU-addon-src/www/config/img/devices/50/hb-uw-sen-thpl-i_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Contrib/CCU/HB-UW-Sen-THPL_CCU-addon-src/www/config/img/devices/50/hb-uw-sen-thpl-i_thumb.png -------------------------------------------------------------------------------- /Contrib/CCU/HB-UW-Sen-THPL_CCU-addon-src/www/config/img/devices/50/hb-uw-sen-thpl-o_thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kc-GitHub/Wettersensor/HEAD/Contrib/CCU/HB-UW-Sen-THPL_CCU-addon-src/www/config/img/devices/50/hb-uw-sen-thpl-o_thumb.png -------------------------------------------------------------------------------- /Firmware-Src/Libraries/TSL2561/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map for SFE_TSL2561 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | SFE_TSL2561 KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | begin KEYWORD2 16 | 17 | ####################################### 18 | # Constants (LITERAL1) 19 | ####################################### 20 | 21 | TSL2561_ADDR LITERAL1 22 | TSL2561_ADDR_0 LITERAL1 23 | TSL2561_ADDR_1 LITERAL1 -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Wire/examples/master_writer/master_writer.ino: -------------------------------------------------------------------------------- 1 | // Wire Master Writer 2 | // by Nicholas Zambetti 3 | 4 | // Demonstrates use of the Wire library 5 | // Writes data to an I2C/TWI slave device 6 | // Refer to the "Wire Slave Receiver" example for use with this 7 | 8 | // Created 29 March 2006 9 | 10 | // This example code is in the public domain. 11 | 12 | 13 | #include 14 | 15 | void setup() 16 | { 17 | Wire.begin(); // join i2c bus (address optional for master) 18 | } 19 | 20 | byte x = 0; 21 | 22 | void loop() 23 | { 24 | Wire.beginTransmission(4); // transmit to device #4 25 | Wire.write("x is "); // sends five bytes 26 | Wire.write(x); // sends one byte 27 | Wire.endTransmission(); // stop transmitting 28 | 29 | x++; 30 | delay(500); 31 | } 32 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Wire/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Wire 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | ####################################### 10 | # Methods and Functions (KEYWORD2) 11 | ####################################### 12 | 13 | begin KEYWORD2 14 | beginTransmission KEYWORD2 15 | endTransmission KEYWORD2 16 | requestFrom KEYWORD2 17 | send KEYWORD2 18 | receive KEYWORD2 19 | onReceive KEYWORD2 20 | onRequest KEYWORD2 21 | 22 | ####################################### 23 | # Instances (KEYWORD2) 24 | ####################################### 25 | 26 | Wire KEYWORD2 27 | 28 | ####################################### 29 | # Constants (LITERAL1) 30 | ####################################### 31 | 32 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Wire/examples/slave_sender/slave_sender.ino: -------------------------------------------------------------------------------- 1 | // Wire Slave Sender 2 | // by Nicholas Zambetti 3 | 4 | // Demonstrates use of the Wire library 5 | // Sends data as an I2C/TWI slave device 6 | // Refer to the "Wire Master Reader" example for use with this 7 | 8 | // Created 29 March 2006 9 | 10 | // This example code is in the public domain. 11 | 12 | 13 | #include 14 | 15 | void setup() 16 | { 17 | Wire.begin(2); // join i2c bus with address #2 18 | Wire.onRequest(requestEvent); // register event 19 | } 20 | 21 | void loop() 22 | { 23 | delay(100); 24 | } 25 | 26 | // function that executes whenever data is requested by master 27 | // this function is registered as an event, see setup() 28 | void requestEvent() 29 | { 30 | Wire.write("hello "); // respond with message of 6 bytes 31 | // as expected by master 32 | } 33 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Wire/examples/master_reader/master_reader.ino: -------------------------------------------------------------------------------- 1 | // Wire Master Reader 2 | // by Nicholas Zambetti 3 | 4 | // Demonstrates use of the Wire library 5 | // Reads data from an I2C/TWI slave device 6 | // Refer to the "Wire Slave Sender" example for use with this 7 | 8 | // Created 29 March 2006 9 | 10 | // This example code is in the public domain. 11 | 12 | 13 | #include 14 | 15 | void setup() 16 | { 17 | Wire.begin(); // join i2c bus (address optional for master) 18 | Serial.begin(9600); // start serial for output 19 | } 20 | 21 | void loop() 22 | { 23 | Wire.requestFrom(2, 6); // request 6 bytes from slave device #2 24 | 25 | while(Wire.available()) // slave may send less than requested 26 | { 27 | char c = Wire.read(); // receive a byte as character 28 | Serial.print(c); // print the character 29 | } 30 | 31 | delay(500); 32 | } 33 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Sensirion/examples/SimpleSensirion/SimpleSensirion.pde: -------------------------------------------------------------------------------- 1 | /* 2 | * Query a SHT10 temperature and humidity sensor 3 | * 4 | * A simple example that queries the sensor every 5 seconds 5 | * and communicates the result over a serial connection. 6 | * Error handling is omitted in this example. 7 | */ 8 | 9 | #include 10 | 11 | const uint8_t dataPin = 2; 12 | const uint8_t clockPin = 3; 13 | 14 | float temperature; 15 | float humidity; 16 | float dewpoint; 17 | 18 | Sensirion tempSensor = Sensirion(dataPin, clockPin); 19 | 20 | void setup() 21 | { 22 | Serial.begin(9600); 23 | } 24 | 25 | void loop() 26 | { 27 | tempSensor.measure(&temperature, &humidity, &dewpoint); 28 | 29 | Serial.print("Temperature: "); 30 | Serial.print(temperature); 31 | Serial.print(" C, Humidity: "); 32 | Serial.print(humidity); 33 | Serial.print(" %, Dewpoint: "); 34 | Serial.print(dewpoint); 35 | Serial.println(" C"); 36 | 37 | delay(5000); 38 | } 39 | -------------------------------------------------------------------------------- /Firmware-Src/ccu-changelog.txt: -------------------------------------------------------------------------------- 1 | For the firmware update, the Sensor must switched off and switched on again. 2 | 3 | 1. Take at least one battery out of the sensor. 4 | 2. Press the config button and insert the battery in the sensor. 5 | 3. Still holding the config button a few seconds after inserting the batteries. 6 | 4. Bootloader should starts. 7 | 8 | Changelog: 9 | 10 | Version Beta 0.14 11 | ------------- 12 | 13 | ** Improvement 14 | * Add new register: 15 | - Fix millis() overflow bug. Now, the sensor stays in sleep mode after 49 days, so battery should not drained anymore 16 | - Battery voltage now measured with 1 digit only. 17 | 18 | Version Beta 0.13 19 | ------------- 20 | 21 | ** Improvement 22 | * Add new register: 23 | - transmitTryMax: How often should the sensor try to send data without ack. 24 | - lowBatLimit: Defined the battery voltage used for low battery detection. 25 | - ledMode: Switch the device LED on or off while sent out data. 26 | - altitude: Define the sensor-altitude for calculating the air pressure at sea level. 27 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Sensirion/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Sensirion 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | Sensirion KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | measure KEYWORD2 16 | meas KEYWORD2 17 | measTemp KEYWORD2 18 | measHumi KEYWORD2 19 | measRdy KEYWORD2 20 | writeSR KEYWORD2 21 | readSR KEYWORD2 22 | reset KEYWORD2 23 | calcTemp KEYWORD2 24 | calcHumi KEYWORD2 25 | calcDewpoint KEYWORD2 26 | 27 | ####################################### 28 | # Constants (LITERAL1) 29 | ####################################### 30 | 31 | TEMP LITERAL1 32 | HUMI LITERAL1 33 | BLOCK LITERAL1 34 | NONBLOCK LITERAL1 35 | LOW_RES LITERAL1 36 | NORELOAD LITERAL1 37 | HEAT_ON LITERAL1 38 | BATT_LOW LITERAL1 39 | S_Err_NoACK LITERAL1 40 | S_Err_CRC LITERAL1 41 | S_Err_TO LITERAL1 42 | S_Meas_Rdy LITERAL1 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Firmware for Univarsal Wettersensor 2 | =================================== 3 | 4 | * http://www.fhemwiki.de/wiki/Universalsensor 5 | * http://forum.fhem.de/index.php/topic,20620.0.html 6 | 7 | #Changelog# 8 | 9 | ##Version 0.15 (Development)## 10 | * Improve / Fix debugging. 11 | * Fix [#16](/../../issues/16) so peering with HM-CC-RT-DN should stable now. 12 | * Add hysteresis for battery voltage measurement. 13 | * Experimental support for US-100 ultrasonic distance sensor (Do not use this experimental feature if you need the peering with HM-CC-RT-DN at this time) 14 | 15 | ##Version 0.14## 16 | * Fix millis() overflow bug. Now, the sensor stays in sleep mode after 49 days, so battery should not drained anymore 17 | * Battery voltage now measured with 1 digit only. 18 | 19 | ##Version 0.13 (Beta)## 20 | * Add new register: 21 | - transmitTryMax: How often should the sensor try to send data without ack. 22 | - lowBatLimit: Defined the battery voltage used for low battery detection. 23 | - ledMode: Switch the device LED on or off while sent out data. 24 | - altitude: Define the sensor-altitude for calculating the air pressure at sea level. 25 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Wire/examples/slave_receiver/slave_receiver.ino: -------------------------------------------------------------------------------- 1 | // Wire Slave Receiver 2 | // by Nicholas Zambetti 3 | 4 | // Demonstrates use of the Wire library 5 | // Receives data as an I2C/TWI slave device 6 | // Refer to the "Wire Master Writer" example for use with this 7 | 8 | // Created 29 March 2006 9 | 10 | // This example code is in the public domain. 11 | 12 | 13 | #include 14 | 15 | void setup() 16 | { 17 | Wire.begin(4); // join i2c bus with address #4 18 | Wire.onReceive(receiveEvent); // register event 19 | Serial.begin(9600); // start serial for output 20 | } 21 | 22 | void loop() 23 | { 24 | delay(100); 25 | } 26 | 27 | // function that executes whenever data is received from master 28 | // this function is registered as an event, see setup() 29 | void receiveEvent(int howMany) 30 | { 31 | while(1 < Wire.available()) // loop through all but the last 32 | { 33 | char c = Wire.read(); // receive byte as a character 34 | Serial.print(c); // print the character 35 | } 36 | int x = Wire.read(); // receive byte as an integer 37 | Serial.println(x); // print the integer 38 | } 39 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Wire/examples/digital_potentiometer/digital_potentiometer.ino: -------------------------------------------------------------------------------- 1 | // I2C Digital Potentiometer 2 | // by Nicholas Zambetti 3 | // and Shawn Bonkowski 4 | 5 | // Demonstrates use of the Wire library 6 | // Controls AD5171 digital potentiometer via I2C/TWI 7 | 8 | // Created 31 March 2006 9 | 10 | // This example code is in the public domain. 11 | 12 | // This example code is in the public domain. 13 | 14 | 15 | #include 16 | 17 | void setup() 18 | { 19 | Wire.begin(); // join i2c bus (address optional for master) 20 | } 21 | 22 | byte val = 0; 23 | 24 | void loop() 25 | { 26 | Wire.beginTransmission(44); // transmit to device #44 (0x2c) 27 | // device address is specified in datasheet 28 | Wire.write(byte(0x00)); // sends instruction byte 29 | Wire.write(val); // sends potentiometer value byte 30 | Wire.endTransmission(); // stop transmitting 31 | 32 | val++; // increment value 33 | if(val == 64) // if reached 64th position (max) 34 | { 35 | val = 0; // start over from lowest value 36 | } 37 | delay(500); 38 | } 39 | 40 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Wire/utility/twi.h: -------------------------------------------------------------------------------- 1 | /* 2 | twi.h - TWI/I2C library for Wiring & Arduino 3 | Copyright (c) 2006 Nicholas Zambetti. All right reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef twi_h 21 | #define twi_h 22 | 23 | #include 24 | 25 | //#define ATMEGA8 26 | 27 | #ifndef TWI_FREQ 28 | #define TWI_FREQ 100000L 29 | #endif 30 | 31 | #ifndef TWI_BUFFER_LENGTH 32 | #define TWI_BUFFER_LENGTH 32 33 | #endif 34 | 35 | #define TWI_READY 0 36 | #define TWI_MRX 1 37 | #define TWI_MTX 2 38 | #define TWI_SRX 3 39 | #define TWI_STX 4 40 | 41 | void twi_init(void); 42 | void twi_setAddress(uint8_t); 43 | uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t, uint8_t); 44 | uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t); 45 | uint8_t twi_transmit(const uint8_t*, uint8_t); 46 | void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) ); 47 | void twi_attachSlaveTxEvent( void (*)(void) ); 48 | void twi_reply(uint8_t); 49 | void twi_stop(void); 50 | void twi_releaseBus(void); 51 | 52 | #endif 53 | 54 | -------------------------------------------------------------------------------- /Firmware-Src/WetterSensor.h: -------------------------------------------------------------------------------- 1 | #if defined(ARDUINO) && ARDUINO >= 100 2 | #include "Arduino.h" 3 | #else 4 | #include "WProgram.h" 5 | #endif 6 | 7 | /** 8 | * Must set in AskSinMain.h to !!! 9 | * 10 | * Set to 1 to read address data from end of bootloader section 11 | * Set to 0 to read address data from program space 12 | */ 13 | #define USE_ADRESS_SECTION 1 14 | 15 | #define ADDRESS_SECTION_START 0x7FF0 // Start address of data in adress section at and of bootloader 16 | 17 | /** 18 | * Activate for serial debug infos 19 | */ 20 | #define SER_DBG 21 | 22 | #define FIRMWARE_VERSION 0x0F // 0.15 23 | 24 | /* 25 | * Address data if we don't read them from bootloader section 26 | */ 27 | #if USE_ADRESS_SECTION == 0 28 | //#define DEVICE_TYPE 0xF1, 0x02 // The model-ID 0xF1 0x01 = DIY (HB-UW-Sen-THPL-O) 29 | #define DEVICE_TYPE 0xF1, 0x01 // The model-ID 0xF1 0x01 = DIY (HB-UW-Sen-THPL-I) 30 | #define DEVICE_SERIAL 'H','B','0','D','e','f','a','u','l','t' // The serial 10 bytes, needed for pairing (Default for serial flash tool) 31 | #define DEVICE_ADDRESS 0xAB, 0xCD, 0xEF // The HM-ID 3 bytes, needed for pairing (Default for flash tool) 32 | #endif 33 | 34 | #define BATTERY_MEASSUREMENT_FACTOR 17 // Faktor Spannungsteiler externe Batteriemessung 35 | #define BATTERY_MIN_VOLTAGE 10 // minimal configuable low battery voltage level 36 | #define BATTERY_MAX_VOLTAGE 50 // maximal configuable low battery voltage level 37 | 38 | void getPgmSpaceData(uint8_t *buffer, uint16_t address, uint8_t len); 39 | void getDataFromAddressSection(uint8_t *buffer, uint8_t bufferStartAddress, uint16_t sectionAddress, uint8_t dataLen); 40 | 41 | void cmdConfigChanged(uint8_t *data, uint8_t len); 42 | void cmdReset(uint8_t *data, uint8_t len); 43 | void cmdStatusRequest(uint8_t *data, uint8_t len); 44 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/BMP085/BMP085.h: -------------------------------------------------------------------------------- 1 | // BMP085 Pressure/Temperature (Altimeter) sensor 2 | 3 | // MIT license 4 | #ifndef BMP085_H 5 | #define BMP085_H 6 | 7 | 8 | #if (ARDUINO >= 100) 9 | #include "Arduino.h" 10 | #else 11 | #include "WProgram.h" 12 | #endif 13 | #include 14 | 15 | #define BMP085_DEBUG 0 16 | 17 | #define BMP085_I2CADDR 0x77 18 | 19 | #define BMP085_ULTRALOWPOWER 0 20 | #define BMP085_STANDARD 1 21 | #define BMP085_HIGHRES 2 22 | #define BMP085_ULTRAHIGHRES 3 23 | #define BMP085_CAL_AC1 0xAA // R Calibration data (16 bits) 24 | #define BMP085_CAL_AC2 0xAC // R Calibration data (16 bits) 25 | #define BMP085_CAL_AC3 0xAE // R Calibration data (16 bits) 26 | #define BMP085_CAL_AC4 0xB0 // R Calibration data (16 bits) 27 | #define BMP085_CAL_AC5 0xB2 // R Calibration data (16 bits) 28 | #define BMP085_CAL_AC6 0xB4 // R Calibration data (16 bits) 29 | #define BMP085_CAL_B1 0xB6 // R Calibration data (16 bits) 30 | #define BMP085_CAL_B2 0xB8 // R Calibration data (16 bits) 31 | #define BMP085_CAL_MB 0xBA // R Calibration data (16 bits) 32 | #define BMP085_CAL_MC 0xBC // R Calibration data (16 bits) 33 | #define BMP085_CAL_MD 0xBE // R Calibration data (16 bits) 34 | 35 | #define BMP085_CONTROL 0xF4 36 | #define BMP085_TEMPDATA 0xF6 37 | #define BMP085_PRESSUREDATA 0xF6 38 | #define BMP085_READTEMPCMD 0x2E 39 | #define BMP085_READPRESSURECMD 0x34 40 | 41 | 42 | class BMP085 { 43 | public: 44 | void begin(uint8_t mode = BMP085_ULTRAHIGHRES); // by default go highres 45 | float readTemperature(void); 46 | int32_t readPressure(void); 47 | float readAltitude(float sealevelPressure = 101325); // std atmosphere 48 | uint16_t readRawTemperature(void); 49 | uint32_t readRawPressure(void); 50 | 51 | private: 52 | uint8_t read8(uint8_t addr); 53 | uint16_t read16(uint8_t addr); 54 | void write8(uint8_t addr, uint8_t data); 55 | 56 | uint8_t oversampling; 57 | 58 | int16_t ac1, ac2, ac3, b1, b2, mb, mc, md; 59 | uint16_t ac4, ac5, ac6; 60 | }; 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /Contrib/build-tool.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -lt 2 ] 4 | then 5 | echo "build-tool.sh [type I|O]" 6 | echo "Sample: ./build-tool.sh 13 000 I" 7 | exit 1 8 | fi 9 | 10 | if [ $# -eq 3 ] 11 | then 12 | type=-$3 13 | else 14 | typ3= 15 | fi 16 | 17 | curPath=`pwd` 18 | date=`date +%y%m%d` 19 | versionMajor=0 20 | versionMinor=$1 21 | update=_update_V$versionMajor\_$versionMinor\_$2\_$date 22 | 23 | outFile=HB-UW-Sen-THPL$type$update 24 | outPath=../Firmware-Release 25 | fullFile=$outPath/$outFile 26 | 27 | if [ $# -lt 3 ] 28 | then 29 | ./hex2eq3.php --inFile ../Firmware-Src/Release/WetterSensor.hex --spmPageSize 128 --outFormat eq3 --outFile $fullFile.eq3 --withCrcCheck 30 | ./hex2eq3.php --inFile ../Firmware-Src/Release/WetterSensor.hex --spmPageSize 128 --outFormat hex --outFile $fullFile.hex --withCrcCheck 31 | cp $fullFile.eq3 ./ 32 | 33 | rm -rf ../Firmware-Release/tmp 34 | mkdir ../Firmware-Release/tmp 35 | cp $fullFile.eq3 ../Firmware-Release/tmp 36 | cp ../Firmware-Src/ccu-changelog.txt ../Firmware-Release/tmp/changelog.txt 37 | 38 | echo "TypeCode=61698" > ../Firmware-Release/tmp/info 39 | echo "Name=HB-UW-Sen-THPL-O" >> ../Firmware-Release/tmp/info 40 | echo "CCUFirmwareVersionMin=2.9.0" >> ../Firmware-Release/tmp/info 41 | echo "FirmwareVersion=$versionMajor.$versionMinor" >> ../Firmware-Release/tmp/info 42 | cd $outPath/tmp 43 | tar -H gnu -zcvf $outFile-O.tgz ./* 44 | cd $curPath 45 | mv $outPath/tmp/$outFile-O.tgz $outPath 46 | 47 | rm $outPath/tmp/info 48 | echo "TypeCode=61697" > ../Firmware-Release/tmp/info 49 | echo "Name=HB-UW-Sen-THPL-I" >> ../Firmware-Release/tmp/info 50 | echo "CCUFirmwareVersionMin=2.9.0" >> ../Firmware-Release/tmp/info 51 | echo "FirmwareVersion=$versionMajor.$versionMinor" >> ../Firmware-Release/tmp/info 52 | cd $outPath/tmp 53 | tar -H gnu -zcvf $outFile-I.tgz ./* 54 | cd $curPath 55 | mv $outPath/tmp/$outFile-I.tgz $outPath 56 | 57 | rm -rf ../Firmware-Release/tmp 58 | 59 | else 60 | cp ../Firmware-Src/Release/WetterSensor.hex $outFile.hex 61 | fi 62 | 63 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Wire/Wire.h: -------------------------------------------------------------------------------- 1 | /* 2 | TwoWire.h - TWI/I2C library for Arduino & Wiring 3 | Copyright (c) 2006 Nicholas Zambetti. All right reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts 20 | */ 21 | 22 | #ifndef TwoWire_h 23 | #define TwoWire_h 24 | 25 | #include 26 | #include "Stream.h" 27 | 28 | #define BUFFER_LENGTH 32 29 | 30 | class TwoWire : public Stream 31 | { 32 | private: 33 | static uint8_t rxBuffer[]; 34 | static uint8_t rxBufferIndex; 35 | static uint8_t rxBufferLength; 36 | 37 | static uint8_t txAddress; 38 | static uint8_t txBuffer[]; 39 | static uint8_t txBufferIndex; 40 | static uint8_t txBufferLength; 41 | 42 | static uint8_t transmitting; 43 | static void (*user_onRequest)(void); 44 | static void (*user_onReceive)(int); 45 | static void onRequestService(void); 46 | static void onReceiveService(uint8_t*, int); 47 | public: 48 | TwoWire(); 49 | void begin(); 50 | void begin(uint8_t); 51 | void begin(int); 52 | void beginTransmission(uint8_t); 53 | void beginTransmission(int); 54 | uint8_t endTransmission(void); 55 | uint8_t endTransmission(uint8_t); 56 | uint8_t requestFrom(uint8_t, uint8_t); 57 | uint8_t requestFrom(uint8_t, uint8_t, uint8_t); 58 | uint8_t requestFrom(int, int); 59 | uint8_t requestFrom(int, int, int); 60 | virtual size_t write(uint8_t); 61 | virtual size_t write(const uint8_t *, size_t); 62 | virtual int available(void); 63 | virtual int read(void); 64 | virtual int peek(void); 65 | virtual void flush(void); 66 | void onReceive( void (*)(int) ); 67 | void onRequest( void (*)(void) ); 68 | 69 | inline size_t write(unsigned long n) { return write((uint8_t)n); } 70 | inline size_t write(long n) { return write((uint8_t)n); } 71 | inline size_t write(unsigned int n) { return write((uint8_t)n); } 72 | inline size_t write(int n) { return write((uint8_t)n); } 73 | using Print::write; 74 | }; 75 | 76 | extern TwoWire Wire; 77 | 78 | #endif 79 | 80 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.ino: -------------------------------------------------------------------------------- 1 | // I2C SRF10 or SRF08 Devantech Ultrasonic Ranger Finder 2 | // by Nicholas Zambetti 3 | // and James Tichenor 4 | 5 | // Demonstrates use of the Wire library reading data from the 6 | // Devantech Utrasonic Rangers SFR08 and SFR10 7 | 8 | // Created 29 April 2006 9 | 10 | // This example code is in the public domain. 11 | 12 | 13 | #include 14 | 15 | void setup() 16 | { 17 | Wire.begin(); // join i2c bus (address optional for master) 18 | Serial.begin(9600); // start serial communication at 9600bps 19 | } 20 | 21 | int reading = 0; 22 | 23 | void loop() 24 | { 25 | // step 1: instruct sensor to read echoes 26 | Wire.beginTransmission(112); // transmit to device #112 (0x70) 27 | // the address specified in the datasheet is 224 (0xE0) 28 | // but i2c adressing uses the high 7 bits so it's 112 29 | Wire.write(byte(0x00)); // sets register pointer to the command register (0x00) 30 | Wire.write(byte(0x50)); // command sensor to measure in "inches" (0x50) 31 | // use 0x51 for centimeters 32 | // use 0x52 for ping microseconds 33 | Wire.endTransmission(); // stop transmitting 34 | 35 | // step 2: wait for readings to happen 36 | delay(70); // datasheet suggests at least 65 milliseconds 37 | 38 | // step 3: instruct sensor to return a particular echo reading 39 | Wire.beginTransmission(112); // transmit to device #112 40 | Wire.write(byte(0x02)); // sets register pointer to echo #1 register (0x02) 41 | Wire.endTransmission(); // stop transmitting 42 | 43 | // step 4: request reading from sensor 44 | Wire.requestFrom(112, 2); // request 2 bytes from slave device #112 45 | 46 | // step 5: receive reading from sensor 47 | if(2 <= Wire.available()) // if two bytes were received 48 | { 49 | reading = Wire.read(); // receive high byte (overwrites previous reading) 50 | reading = reading << 8; // shift high byte to be high 8 bits 51 | reading |= Wire.read(); // receive low byte as lower 8 bits 52 | Serial.println(reading); // print the reading 53 | } 54 | 55 | delay(250); // wait a bit since people have to read the output :) 56 | } 57 | 58 | 59 | /* 60 | 61 | // The following code changes the address of a Devantech Ultrasonic Range Finder (SRF10 or SRF08) 62 | // usage: changeAddress(0x70, 0xE6); 63 | 64 | void changeAddress(byte oldAddress, byte newAddress) 65 | { 66 | Wire.beginTransmission(oldAddress); 67 | Wire.write(byte(0x00)); 68 | Wire.write(byte(0xA0)); 69 | Wire.endTransmission(); 70 | 71 | Wire.beginTransmission(oldAddress); 72 | Wire.write(byte(0x00)); 73 | Wire.write(byte(0xAA)); 74 | Wire.endTransmission(); 75 | 76 | Wire.beginTransmission(oldAddress); 77 | Wire.write(byte(0x00)); 78 | Wire.write(byte(0xA5)); 79 | Wire.endTransmission(); 80 | 81 | Wire.beginTransmission(oldAddress); 82 | Wire.write(byte(0x00)); 83 | Wire.write(newAddress); 84 | Wire.endTransmission(); 85 | } 86 | 87 | */ 88 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Sensirion/README.txt: -------------------------------------------------------------------------------- 1 | Sensirion: An Arduino Library for the Sensirion SHT1x and SHT7x family of 2 | temperature and humidity sensors. 3 | 4 | Created by Markus Schatzl, November 28, 2008 5 | Revised (v1.1) by Carl Jackson, August 4, 2010 6 | Rewritten (v2.0) by Carl Jackson, December 8, 2010 7 | 8 | Revision History 9 | 10 | 1.0 - Original code provides a constructor, two public functions, plus 11 | several private functions. The primary public function, "measure", 12 | commands the sensor to perform both a temperature and a humidity 13 | measurement and then calculates the dewpoint. Total execution time 14 | is approximately 400 milliseconds. 15 | 16 | 1.1 - Added several new functions while touching as little as possible of 17 | the original code. The primary new feature is the ability to perform 18 | non-blocking measurements, ie, to return control to the calling routine 19 | after sending a command to the sensor rather than to spin waiting for 20 | the measurement to complete. Also added the ability to set the sensor 21 | measurement precision (14-bit/12-bit Temp/RH vs. 12-bit/8-bit Temp/RH) 22 | for precision vs. speed trade-off. Updated equation coefficients for 23 | the V4 version of the sensors per Sensirion recommendations. 24 | 25 | 2.0 - Extensive changes for robustness, code size, and new features. Added 26 | CRC checking, consistent handling of the data pin internal pullup, and 27 | improved error reporting. Added sensor status register read function 28 | and expanded status register write function to cover all setable bits. 29 | 30 | 31 | Usage Information 32 | 33 | CRC error detection is enabled by default. It may be disabled by deleting 34 | the line "#define CRC_ENA" in the library header file (Sensrion.h). This 35 | reduces the code size by about 150 bytes. When enabled, CRC errors are 36 | indicated via the return code S_Err_CRC. In addition, the value 0xFFFF is 37 | substituted for the affected data. 38 | 39 | The library header file defines two macros (PULSE_SHORT and PULSE_LONG) 40 | that are used in generating the sensor interface signaling. By default, 41 | PULSE_SHORT delays 1 microsecond and PULSE_LONG delays 3 microseconds. 42 | These delays appear reliable for wire lengths of at least 1 foot (30 cm). 43 | Long connections may require adjustments to the delay macros and may also 44 | require serial termination, low pass filtering, or other approaches to 45 | improve the sensor interface signal integrity. 46 | 47 | To avoid self heating of the sensor, Sensirion recommends that the 48 | sensor not be active for more than 10% of the time. In its default high 49 | resolution mode, the sensor performs 14-bit temperature measurements and 50 | 12-bit humidity measurements which may take up to 320 msec and 80 msec 51 | respectively to complete. One set of temperature / humidity measurements 52 | thus takes up to 400 msec so at least 4 seconds should elapse between 53 | successive sets of measurements. In low resolution mode, the sensor 54 | performs 12-bit temperature measurements and 8-bit humidity measurements, 55 | reducing these times to 80 msec and 20 msec respectively for a total of 56 | 100 msec for a set. In this case, at least 1 second should elapse between 57 | successive sets of measurements. 58 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Sensirion/Sensirion.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================== */ 2 | /* Sensirion.h - Library for Sensirion SHT1x & SHT7x family temperature */ 3 | /* and humidity sensors */ 4 | /* Created by Markus Schatzl, November 28, 2008 */ 5 | /* Released into the public domain */ 6 | /* */ 7 | /* Revised (v1.1) by Carl Jackson, August 4, 2010 */ 8 | /* Rewritten (v2.0) by Carl Jackson, December 10, 2010 */ 9 | /* See README.txt file for details */ 10 | /* ========================================================================== */ 11 | 12 | 13 | #ifndef Sensirion_h 14 | #define Sensirion_h 15 | 16 | #if defined(ARDUINO) && ARDUINO >= 100 17 | #include "Arduino.h" 18 | #else 19 | #include "WProgram.h" 20 | #endif 21 | #include 22 | #include 23 | //#include 24 | 25 | 26 | // Enable CRC checking 27 | #define CRC_ENA 28 | 29 | // Enable ('1') or disable ('0') internal pullup on DATA line 30 | // Commenting out this #define saves code space but leaves internal pullup 31 | // state undefined (ie, depends on last bit transmitted) 32 | #define DATA_PU 1 33 | 34 | // Clock pulse timing macros 35 | // Lengthening these may assist communication over long wires 36 | //#define PULSE_LONG delayMicroseconds(3) 37 | //#define PULSE_SHORT delayMicroseconds(1) 38 | #define PULSE_LONG _delay_us(3) 39 | #define PULSE_SHORT _delay_us(1) 40 | 41 | // Useful macros 42 | #define measTemp(result) meas(TEMP, result, BLOCK) 43 | #define measHumi(result) meas(HUMI, result, BLOCK) 44 | 45 | // User constants 46 | const uint8_t TEMP = 0; 47 | const uint8_t HUMI = 1; 48 | const bool BLOCK = true; 49 | const bool NONBLOCK = false; 50 | 51 | // Status register bit definitions 52 | const uint8_t LOW_RES = 0x01; // 12-bit Temp / 8-bit RH (vs. 14 / 12) 53 | const uint8_t NORELOAD = 0x02; // No reload of calibrarion data 54 | const uint8_t HEAT_ON = 0x04; // Built-in heater on 55 | const uint8_t BATT_LOW = 0x40; // VDD < 2.47V 56 | 57 | // Function return code definitions 58 | const uint8_t S_Err_NoACK = 1; // ACK expected but not received 59 | const uint8_t S_Err_CRC = 2; // CRC failure 60 | const uint8_t S_Err_TO = 3; // Timeout 61 | const uint8_t S_Meas_Rdy = 4; // Measurement ready 62 | 63 | class Sensirion 64 | { 65 | private: 66 | uint8_t _pinData; 67 | uint8_t _pinClock; 68 | uint16_t *_presult; 69 | uint8_t _stat_reg; 70 | #ifdef CRC_ENA 71 | uint8_t _crc; 72 | #endif 73 | uint8_t getResult(uint16_t *result); 74 | uint8_t putByte(uint8_t value); 75 | uint8_t getByte(bool ack); 76 | void startTransmission(void); 77 | void resetConnection(void); 78 | #ifdef CRC_ENA 79 | void calcCRC(uint8_t value, uint8_t *crc); 80 | uint8_t bitrev(uint8_t value); 81 | #endif 82 | 83 | public: 84 | void config(uint8_t dataPin, uint8_t clockPin); 85 | uint8_t measure(float *temp, float *humi, float *dew); 86 | uint8_t meas(uint8_t cmd, uint16_t *result, bool block); 87 | uint8_t measRdy(void); 88 | uint8_t writeSR(uint8_t value); 89 | uint8_t readSR(uint8_t *result); 90 | uint8_t reset(void); 91 | float calcTemp(uint16_t rawData); 92 | float calcHumi(uint16_t rawData, float temp); 93 | float calcDewpoint(float humi, float temp); 94 | }; 95 | 96 | #endif // #ifndef Sensirion_h 97 | -------------------------------------------------------------------------------- /Contrib/CCU/HB-UW-Sen-THPL_CCU-addon-src/update_script: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ### Prepare filesystem 4 | mountPathRoot="/mnt-root" 5 | mountPathUser="/mnt-user" 6 | mkdir -p $mountPathRoot 7 | mkdir -p $mountPathUser 8 | 9 | if ["$1" == ""]; then 10 | echo "CCU1" 11 | mount -t yaffs /dev/mtdblock2 $mountPathRoot 12 | mount -t yaffs /dev/mtdblock3 $mountPathUser 13 | lcdtool "Installing new device" 14 | lcdtool -a 0x40 -t bin 00 15 | else 16 | echo "CCU2" 17 | mount -t ubifs ubi0:root $mountPathRoot 18 | mount -t ubifs ubi1:user $mountPathUser 19 | fi 20 | 21 | ########################### 22 | ### New device UWS-THPL ### 23 | ########################### 24 | device="HB-UW-Sen-THPL" 25 | 26 | ### Copy new devices Files ### 27 | cp -a ./firmware/rftypes/* $mountPathRoot/firmware/rftypes/ 28 | 29 | ### Copy new images ### 30 | cp -ar ./www/config/img/devices $mountPathRoot/www/config/img/ 31 | 32 | ### Edit DEVDB.tcl ### 33 | devdescrFile="$mountPathRoot/www/config/devdescr/DEVDB.tcl" 34 | devdescrSearch="array[[:space:]]*set[[:space:]]*DEV_PATHS[[:space:]]*{" 35 | 36 | devdescrInsert="" 37 | devdescrInsert="$devdescrInsert HB-UW-Sen-THPL-I {{50 \/config\/img\/devices\/50\/hb-uw-sen-thpl-i_thumb.png} {250 \/config\/img\/devices\/250\/hb-uw-sen-thpl-i.png}} " 38 | devdescrInsert="$devdescrInsert HB-UW-Sen-THPL-O {{50 \/config\/img\/devices\/50\/hb-uw-sen-thpl-o_thumb.png} {250 \/config\/img\/devices\/250\/hb-uw-sen-thpl-o.png}} " 39 | 40 | devdescrModifyed=`cat $devdescrFile | grep "$device"` 41 | if [ -z $devdescrModifyed ]; then 42 | cp -a $devdescrFile $devdescrFile.save 43 | sed -i "s/\($devdescrSearch\)/\1$devdescrInsert/g" $devdescrFile 44 | fi 45 | 46 | ### Edit webui.js ### 47 | webuiFile="$mountPathRoot/www/webui/webui.js" 48 | webuiSearch="DEV_HIGHLIGHT[[:space:]]*=[[:space:]]*new Array();" 49 | 50 | webuiInsert="\n" 51 | webuiInsert="$webuiInsert DEV_HIGHLIGHT['HB-UW-Sen-THPL-I'] = new Object();\n" 52 | webuiInsert="$webuiInsert DEV_LIST.push('HB-UW-Sen-THPL-I');\n" 53 | webuiInsert="$webuiInsert DEV_DESCRIPTION['HB-UW-Sen-THPL-I']='Univesal Funk- Temperatur-\/ Feuchte-\/ Luftdruck-\/ Helligkeitssensor (Innen)';\n" 54 | webuiInsert="$webuiInsert DEV_PATHS['HB-UW-Sen-THPL-I'] = new Object();\n" 55 | webuiInsert="$webuiInsert DEV_PATHS['HB-UW-Sen-THPL-I']['50'] = '\/config\/img\/devices\/50\/hb-uw-sen-thpl-i_thumb.png';\n" 56 | webuiInsert="$webuiInsert DEV_PATHS['HB-UW-Sen-THPL-I']['250'] = '\/config\/img\/devices\/250\/hb-uw-sen-thpl-i.png';\n" 57 | 58 | webuiInsert="$webuiInsert DEV_HIGHLIGHT['HB-UW-Sen-THPL-O'] = new Object();\n" 59 | webuiInsert="$webuiInsert DEV_LIST.push('HB-UW-Sen-THPL-O');\n" 60 | webuiInsert="$webuiInsert DEV_DESCRIPTION['HB-UW-Sen-THPL-O']='Univesal Funk- Temperatur-\/ Feuchte-\/ Luftdruck-\/ Helligkeitssensor (Außen)';\n" 61 | webuiInsert="$webuiInsert DEV_PATHS['HB-UW-Sen-THPL-O'] = new Object();\n" 62 | webuiInsert="$webuiInsert DEV_PATHS['HB-UW-Sen-THPL-O']['50'] = '\/config\/img\/devices\/50\/hb-uw-sen-thpl-o_thumb.png';\n" 63 | webuiInsert="$webuiInsert DEV_PATHS['HB-UW-Sen-THPL-O']['250'] = '\/config\/img\/devices\/250\/hb-uw-sen-thpl-o.png';\n" 64 | 65 | webuiModifyed=`cat $webuiFile | grep "$device"` 66 | if [ -z $webuiModifyed ]; then 67 | # Space on filesystem off CCU1 is short, so we copy the file to tempfs before editing 68 | cp $webuiFile $mountPathUser/webui.js 69 | sed -i "s/\($webuiSearch\)/\1$webuiInsert/g" $mountPathUser/webui.js 70 | mv $mountPathUser/webui.js $webuiFile 71 | fi 72 | 73 | umount $mountPathRoot 74 | umount $mountPathUser 75 | if ["$1" == ""]; then 76 | echo "CCU1" 77 | lcdtool "Reboot... " 78 | lcdtool -a 0x40 -t bin 00 79 | echo "x" > /dev/watchdog 80 | reboot 81 | while true ; do true ; done 82 | else 83 | echo "CCU2" 84 | # CCU2 always reboot after Addon/Firmware Update 85 | fi 86 | -------------------------------------------------------------------------------- /Contrib/FHEM/HMConfig_SenTHPL.pm: -------------------------------------------------------------------------------- 1 | package main; 2 | 3 | use strict; 4 | use warnings; 5 | 6 | # device definition 7 | $HMConfig::culHmModel{'F101'} = {name => 'HB-UW-Sen-THPL-I', st => 'THPLSensor', cyc => '00:10', rxt => 'l:w:c:f', lst => 'p', chn => '',}; 8 | $HMConfig::culHmModel{'F102'} = {name => 'HB-UW-Sen-THPL-O', st => 'THPLSensor', cyc => '00:10', rxt => 'l:w:c:f', lst => 'p', chn => '',}; 9 | 10 | $HMConfig::culHmRegDefine{'lowBatLimitTHPL'} = {a=>18.0,s=>1.0,l=>0,min=>1.0 ,max=>5 ,c=>'',f=>10,u=>'V', d=>0,t=>'Low batterie limit, step 0.1 V.'}; 11 | $HMConfig::culHmRegDefine{'altitude'} = {a=>36.0,s=>2.0,l=>0,min=>-500,max=>10000,c=>'',f=>'',u=>'m' ,d=>0,t=>'Altitude for calculate air pressure at see level in meter.'}; 12 | 13 | # Register model mapping 14 | $HMConfig::culHmRegModel{'HB-UW-Sen-THPL-I'} = { 15 | 'burstRx' => 1, 16 | 'lowBatLimitTHPL' => 1, 17 | 'ledMode' => 1, 18 | 'transmDevTryMax' => 1, 19 | 'altitude' => 1 20 | }; 21 | 22 | $HMConfig::culHmRegModel{'HB-UW-Sen-THPL-O'} = $HMConfig::culHmRegModel{'HB-UW-Sen-THPL-I'}; 23 | 24 | # subtype channel mapping 25 | $HMConfig::culHmSubTypeSets{'THPLSensor'} = { 26 | 'peerChan' => '0 ... single [set|unset] [actor|remote|both]', 27 | 'fwUpdate' => ' ...', 28 | 'getSerial' => '', 29 | 'getVersion' => '', 30 | 'statusRequest' => '', 31 | 'burstXmit' => '' 32 | }; 33 | 34 | # Subtype spezific funtions 35 | sub CUL_HM_ParseTHPLSensor(@){ 36 | 37 | my ($mFlg, $frameType, $src, $dst, $msgData, $targetDevIO) = @_; 38 | 39 | my $shash = CUL_HM_id2Hash($src); #sourcehash - will be modified to channel entity 40 | my @events = (); 41 | 42 | # WEATHER_EVENT 43 | if ($frameType eq '70'){ 44 | my $name = $shash->{NAME}; 45 | my $chn = '01'; 46 | 47 | my ($dTempBat, $humidity, $pressure, $luminosity, $batVoltage) = map{hex($_)} unpack ('A4A2A4A8A4', $msgData); 48 | 49 | # temperature 50 | my $temperature = $dTempBat & 0x7fff; 51 | $temperature = ($temperature &0x4000) ? $temperature - 0x8000 : $temperature; 52 | $temperature = sprintf('%0.1f', $temperature / 10); 53 | 54 | my $stateMsg = 'state:T: ' . $temperature; 55 | push (@events, [$shash, 1, 'temperature:' . $temperature]); 56 | 57 | # battery state 58 | push (@events, [$shash, 1, 'battery:' . ($dTempBat & 0x8000 ? 'low' : 'ok')]); 59 | 60 | # battery voltage 61 | $batVoltage = sprintf('%.2f', (($batVoltage + 0.00) / 1000)); 62 | push (@events, [$shash, 1, 'batVoltage:' . $batVoltage]); 63 | 64 | # humidity 65 | if ($humidity) { 66 | $stateMsg .= ' H: ' . $humidity; 67 | push (@events, [$shash, 1, 'humidity:' . $humidity]); 68 | } 69 | 70 | # luminosity 71 | if ($luminosity < 6553800) { 72 | $luminosity = ($luminosity + 0.0) / 100; 73 | $luminosity = ($luminosity < 100) ? $luminosity : sprintf('%.0f', $luminosity); 74 | $stateMsg .= ' L: ' . $luminosity; 75 | push (@events, [$shash, 1, 'luminosity:' . $luminosity]); 76 | } 77 | 78 | # air pressure 79 | if ($pressure) { 80 | $pressure = $pressure / 10; 81 | 82 | my $pressureTxt = sprintf('%.1f', $pressure); 83 | $stateMsg .= ' P: ' . $pressureTxt; 84 | push (@events, [$shash, 1, 'pressure:' . $pressureTxt]); 85 | 86 | my ($rAltitude) = split(' ', ReadingsVal($name, 'R-altitude', 0)); 87 | my $altitude = AttrVal('global', 'altitude', -9999); 88 | my $pressureNN = ($altitude > -9999 && $rAltitude == 0) ? sprintf('%.1f', ($pressure + ($altitude / 8.5))) : 0; 89 | if ($pressureNN) { 90 | $stateMsg .= ' P-NN: ' . $pressureNN; 91 | push (@events, [$shash, 1, 'pressure-nn:' . $pressureNN]); 92 | } 93 | } 94 | 95 | push (@events, [$shash, 1, $stateMsg]); 96 | } 97 | 98 | return @events; 99 | } 100 | 101 | 1; 102 | -------------------------------------------------------------------------------- /Firmware-Src/Register.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef _REGISTER_h 4 | #define _REGISTER_h 5 | 6 | #define FRAME_TYPE 0x70 // Frame type 0x70 = WEATHER_EVENT 7 | #define DEVICE_INFO 0x03, 0x01, 0x00 // Device Info, 3 byte, describes device, not completely clear yet. includes amount of channels 8 | 9 | #if USE_ADRESS_SECTION == 1 10 | uint8_t devParam[] = { 11 | FIRMWARE_VERSION, 12 | 0xFF, 0xFF, // space for device type, assigned later 13 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // space for device serial, assigned later 14 | FRAME_TYPE, 15 | DEVICE_INFO, 16 | 0xFF, 0xFF, 0xFF // space for device address, assigned later 17 | }; 18 | #else 19 | uint8_t devParam[] = { 20 | FIRMWARE_VERSION, 21 | DEVICE_TYPE, 22 | DEVICE_SERIAL, 23 | FRAME_TYPE, 24 | DEVICE_INFO, 25 | DEVICE_ADDRESS 26 | }; 27 | #endif 28 | 29 | HM::s_devParm dParm = { 30 | 3, // send retries, 1 byte, how often a string should be send out until we get an answer 31 | 700, // send timeout, 2 byte, time out for ACK handling 32 | devParam // pointer to devParam, see above 33 | }; 34 | 35 | //- channel device list table -------------------------------------------------------------------------------------------- 36 | HM::s_modtable modTbl[] = { 37 | { 0, 0, (s_mod_dlgt) NULL }, // ??? 38 | { 0, 0, (s_mod_dlgt) NULL }, // ??? 39 | }; // 16 byte 40 | 41 | /** 42 | * channel slice definition 43 | * Each value represents a register index defined in s_regDevL0 below 44 | */ 45 | uint8_t sliceStr[] = { 46 | 0x01, 0x05, 0x0A, 0x0B, 0x0C, 0x12, 0x14, 0x24, 0x25 47 | }; 48 | 49 | /** 50 | * Register definition for List 0 51 | */ 52 | struct s_regDevL0 { 53 | // 0x01, 0x05, 0x0A, 0x0B, 0x0C, 0x12, 0x14, 0x24, 0x25 54 | uint8_t burstRx; // 0x01, startBit:0, bits:8 55 | uint8_t :6; // 0x05 startBit:0, bits:6 56 | uint8_t ledMode :2; // 0x05, startBit:6, bits:2 57 | uint8_t pairCentral[3]; // 0x0A, 0x0B, 0x0C, startBit:0, bits:8 (3 mal) 58 | uint8_t lowBatLimit; // 0x12, startBit:0, bits:8 59 | uint8_t transmDevTryMax; // 0x14, startBit:0, bits:8 60 | uint8_t altitude[2]; // 0x24, 0x25 startBit:0, bits:8 61 | }; 62 | 63 | // todo 64 | struct s_regChanL4 { 65 | // 0x01, 66 | uint8_t peerNeedsBurst:1; // 0x01, s:0, e:1 67 | uint8_t :7; // 68 | }; 69 | 70 | struct s_regDev { 71 | s_regDevL0 l0; 72 | }; 73 | 74 | struct s_regChan { 75 | s_regChanL4 l4; 76 | }; 77 | 78 | struct s_regs { 79 | s_regDev ch0; 80 | s_regChan ch1; 81 | } regs; // 11 byte 82 | 83 | /** 84 | * channel device list table, 22 bytes 85 | */ 86 | const s_cnlDefType cnlDefType[] PROGMEM = { 87 | // cnl, lst, peersMax, sIdx, sLen, pAddr, pPeer, *pRegs (pointer to regs structure) 88 | { 0, 0, 0, 0x00, 9, 0x0000, 0x0000, (void*)®s.ch0.l0}, // List 0 89 | { 1, 4, 6, 0x05, 1, 0x0005, 0x0000, (void*)®s.ch1.l4}, // List 4 90 | }; 91 | 92 | // handover to AskSin lib, 6 bytes 93 | HM::s_devDef dDef = { 94 | 1, 2, sliceStr, cnlDefType, 95 | }; 96 | 97 | /** 98 | * EEprom definition, 16 bytes 99 | * Define start address and size in eeprom for magicNumber, peerDB, regsDB, userSpace 100 | */ 101 | HM::s_eeprom ee[] = { 102 | //magicNum, peerDB, regsDB, userSpace 103 | { 0x0000, 0x0002, 0x001a, 0x0025, }, // start address 104 | { 0x0002, 0x0030, 0x000b, 0x0000, }, // length 105 | }; 106 | 107 | /** 108 | * Definitions for EEprom defaults. 109 | * Must enter in same order as e.g. defined in s_regDevL0 110 | */ 111 | const uint8_t regs00[] PROGMEM = {0x00, 0x64, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00}; 112 | const uint8_t regs04[] PROGMEM = {0x1f, 0xa6, 0x5c, 0x05}; 113 | 114 | s_defaultRegsTbl defaultRegsTbl[] = { 115 | // peer(0) or regs(1), channel, list, peer index, len, pointer to payload 116 | { 1, 0, 0, 0, 9, regs00 }, 117 | }; 118 | 119 | HM::s_dtRegs dtRegs = { 120 | //amount of lines in defaultRegsTbl[], pointer to defaultRegsTbl[] 121 | 1, defaultRegsTbl 122 | }; 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /Contrib/hex2eq3.php: -------------------------------------------------------------------------------- 1 | #! /usr/bin/php -q 2 | thisScript = $argv[0]; 38 | $this->init(); 39 | } 40 | 41 | protected function init() { 42 | $pathParts = pathinfo(__file__); 43 | $this->thisScriptPathAbs = $pathParts['dirname']; 44 | 45 | $options = getopt('h', $this->options); 46 | 47 | if (array_key_exists('h', $options) || array_key_exists('help', $options) || 48 | !array_key_exists('inFile', $options) || (array_key_exists('inFile', $options) && !$options['inFile']) ) { 49 | 50 | $this->printHelpAndExit(); 51 | } else { 52 | $this->inFile = $options['inFile']; 53 | $this->outFormat = (array_key_exists('outFormat' , $options) && $options['outFormat']) ? $options['outFormat'] : 'eq3'; 54 | $this->spmPageSize = (array_key_exists('spmPageSize' , $options) && $options['spmPageSize']) ? $options['spmPageSize'] : 128; 55 | $this->pathToSrecCat = (array_key_exists('pathTo-srec_cat' , $options) && $options['pathTo-srec_cat']) ? $options['pathTo-srec_cat'] : $this->thisScriptPathAbs . '/bin/srecord/srec_cat'; 56 | $this->hexEndAddress = (array_key_exists('hexEndAddress' , $options) && $options['hexEndAddress']) ? $options['hexEndAddress'] : '0x6FFE'; 57 | $this->hexEndAddress = ((int)$this->hexEndAddress == $this->hexEndAddress) ? (int)$this->hexEndAddress : hexdec($this->hexEndAddress); 58 | 59 | $this->withCrcCheck = (array_key_exists('withCrcCheck' , $options)) ? true : false; 60 | $this->markAsBootloaderUpdate = (array_key_exists('markAsBootloaderUpdate' , $options)) ? true : false; 61 | } 62 | 63 | if ($this->spmPageSize != 64 && $this->spmPageSize != 128 && $this->spmPageSize != 256 && $this->spmPageSize != 512) { 64 | $this->printHelpAndExit(); 65 | } 66 | 67 | if ($this->outFormat != 'eq3' && $this->outFormat != 'hex' && $this->outFormat != 'bin') { 68 | $this->printHelpAndExit(); 69 | } 70 | 71 | // check access for inFile 72 | $fp = @fopen($this->inFile, 'r'); 73 | if (!$fp) { 74 | print ('Could not open ' . $this->inFile . LF); 75 | exit(); 76 | } 77 | fclose($fp); 78 | 79 | $pathParts = pathinfo($this->inFile); 80 | $defautlOutFileName = './' . $pathParts['filename'] . '.' . $this->outFormat; 81 | 82 | $this->outFile = (array_key_exists('outFile' , $options) && $options['outFile']) ? $options['outFile'] : $defautlOutFileName; 83 | 84 | if ($this->inFile == $this->outFile) { 85 | print ('inFile and outFile can not be the same' . LF); 86 | exit(); 87 | } 88 | } 89 | 90 | protected function printHelpAndExit() { 91 | print ('Commandline:' . LF); 92 | print ($this->thisScript . ' --inFile --outFile --spmPageSize <64|128|256|512> [--hexEndAddress ] [--outFormat ] [--markAsBootloaderUpdate] [--withCrcCheck --pathTo-srec_cat ]' . LF); 93 | print (LF); 94 | 95 | exit(); 96 | } 97 | 98 | protected function bin2eq3() { 99 | // check access for outFile 100 | $fp = @fopen($this->outFile, 'w'); 101 | if (!$fp) { 102 | print ('Could not write to ' . $this->outFile . LF); 103 | exit(); 104 | } else { 105 | fclose ($fp); 106 | } 107 | 108 | // check access for inFile 109 | $fp = @fopen($this->tmpFile, 'r'); 110 | if (!$fp) { 111 | print ('Could not open ' . $this->tmpFile . LF); 112 | exit(); 113 | } 114 | 115 | $out = ''; 116 | while(!feof($fp)) { 117 | $payload = fread($fp, $this->spmPageSize); 118 | if (strlen($payload) > 0) { 119 | $out.= sprintf('%04X', $this->spmPageSize); 120 | 121 | for($i = 0; $i < $this->spmPageSize; $i++) { 122 | if ($i >= strlen($payload)) { 123 | $out.= '00'; 124 | } else { 125 | $out.= sprintf('%02X', ord($payload[$i])); 126 | } 127 | } 128 | } 129 | } 130 | 131 | file_put_contents($this->outFile, $out); 132 | } 133 | 134 | public function convert() { 135 | if (!file_exists($this->pathToSrecCat)) { 136 | print ('Could not found srec_cat at: ' . $this->pathToSrecCat . LF); 137 | exit(); 138 | } 139 | 140 | switch ($this->outFormat) { 141 | case 'eq3': 142 | case 'bin': 143 | $outFormat = 'binary'; 144 | break; 145 | 146 | case 'hex': 147 | $outFormat = 'intel'; 148 | break; 149 | } 150 | 151 | $hexEndAddress = sprintf('0x%04x', $this->hexEndAddress); 152 | $crcCmd = ($this->withCrcCheck) ? ' -Cyclic_Redundancy_Check_16_Little_Endian ' . $hexEndAddress : ''; 153 | 154 | if ($this->markAsBootloaderUpdate) { 155 | $magigWordAdress = sprintf('0x%04x', $this->hexEndAddress + 2); 156 | $blEndAddress = sprintf('0x%04x', $this->hexEndAddress - 2); 157 | $srecCatCmdBootloaderFlag = $this->pathToSrecCat . ' ' . $this->inFile . 158 | ' -intel -offset -' . $magigWordAdress . ' -fill 0xff 0x0000 ' .$blEndAddress . 159 | ' -generate ' .$blEndAddress . ' ' . $hexEndAddress . 160 | ' -repeat-data ' . $this->magicWord . ' -o ' . $this->tmpFile . '.bin -binary'; 161 | 162 | exec($srecCatCmdBootloaderFlag); 163 | 164 | $srecCatCmd = $this->pathToSrecCat . ' ' . $this->tmpFile . '.bin -binary' . $crcCmd . ' -o ' . $this->tmpFile . ' -' . $outFormat; 165 | } else { 166 | $srecCatCmd = $this->pathToSrecCat . ' ' . $this->inFile . ' -intel -fill 0xFF 0x0000 ' . $hexEndAddress . $crcCmd . ' -o ' . $this->tmpFile . ' -' . $outFormat; 167 | } 168 | 169 | exec($srecCatCmd); 170 | 171 | if ($this->outFormat == 'eq3') { 172 | $this->bin2eq3(); 173 | @unlink($this->tmpFile.'.bin'); 174 | unlink($this->tmpFile); 175 | } else { 176 | rename($this->tmpFile, $this->outFile); 177 | } 178 | } 179 | } 180 | 181 | $converter = new converter($argv); 182 | $converter->convert(); 183 | 184 | exit(); 185 | -------------------------------------------------------------------------------- /Firmware-Src/WetterSensor.ino: -------------------------------------------------------------------------------- 1 | #include "WetterSensor.h" 2 | #include "Register.h" // configuration sheet 3 | 4 | //- load library's -------------------------------------------------------------------------------------------------------- 5 | #include // i2c library, needed for bmp085 or bmp180 6 | #include 7 | #include 8 | #include 9 | #include // remote buttons library 10 | #include 11 | 12 | // homematic communication 13 | HM::s_jumptable jTbl[] = { // jump table for HM communication 14 | // byte3, byte10, byte11, function to call // 0xff means - any byte 15 | { 0x11, 0x04, 0x00, cmdReset }, // Reset message 16 | { 0x01, 0xFF, 0x06, cmdConfigChanged }, // Config end message 17 | { 0x01, 0xFF, 0x0E, cmdStatusRequest }, 18 | { 0x00 } 19 | }; 20 | 21 | Buttons button[1]; // declare remote button object 22 | 23 | Sensirion sht10; 24 | BMP085 bmp085; 25 | TSL2561 tsl2561; 26 | 27 | Sensors_SHT10_BMP085_TSL2561 sensTHPL; 28 | 29 | // main functions 30 | void setup() { 31 | 32 | //millis overflow test 33 | //timer0_millis = 4294967295 - 666666; // overflow reached in about 11 minutes and 7 seconds 34 | 35 | // We disable the Watchdog first 36 | wdt_disable(); 37 | 38 | #ifdef SER_DBG 39 | Serial.begin(57600); // serial setup 40 | Serial << F("Starting sketch...\n"); // ...and some information 41 | Serial << F("freeMem: ") << freeMem() << F(" byte") << F("\n"); 42 | #endif 43 | 44 | #if USE_ADRESS_SECTION == 1 45 | getDataFromAddressSection(devParam, 1, ADDRESS_SECTION_START + 0, 12); // get device type (model-ID) and serial number from bootloader section at 0x7FF0 and 0x7FF2 46 | getDataFromAddressSection(devParam, 17, ADDRESS_SECTION_START + 12, 3); // get device address stored in bootloader section at 0x7FFC 47 | 48 | Serial << F("Device type from Bootloader: "); pHex(&devParam[1], 2, SERIAL_DBG_PHEX_MODE_LF); 49 | Serial << F("Serial from Bootloader: ") ; pHex(&devParam[3], 10, SERIAL_DBG_PHEX_MODE_LF); 50 | Serial << F("Addresse from Bootloader: ") ; pHex(&devParam[17], 3, SERIAL_DBG_PHEX_MODE_LF); 51 | #else 52 | Serial << F("Device type from PROGMEM: "); pHex(&devParam[1], 2, SERIAL_DBG_PHEX_MODE_LF); 53 | Serial << F("Serial from PROGMEM: ") ; pHex(&devParam[3], 10, SERIAL_DBG_PHEX_MODE_LF); 54 | Serial << F("Addresse from PROGMEM: ") ; pHex(&devParam[17], 3, SERIAL_DBG_PHEX_MODE_LF); 55 | #endif 56 | 57 | hm.cc.config(10,11,12,13,2,0); // CS, MOSI, MISO, SCK, GDO0, Interrupt 58 | 59 | // setup battery measurement 60 | hm.battery.config( 61 | BATTERY_MODE_EXTERNAL_MESSUREMENT, 7, 1, BATTERY_MEASSUREMENT_FACTOR, 900000 // battery measurement every 15 minutes 62 | ); 63 | 64 | hm.init(); // initialize the hm module 65 | 66 | button[0].regInHM(0, &hm); // register buttons in HM per channel, handover HM class pointer 67 | button[0].config(8, NULL); // configure button on specific pin and handover a function pointer to the main sketch 68 | 69 | sensTHPL.regInHM(1, &hm); // register sensor class in hm 70 | sensTHPL.config(A4, A5, 0, &sht10, &bmp085, &tsl2561); // data pin, clock pin and timing - 0 means HM calculated timing, every number above will taken in milliseconds 71 | 72 | byte rr = MCUSR; 73 | MCUSR =0; 74 | 75 | cmdConfigChanged(0, 0); 76 | 77 | // initialization done, we blink 3 times 78 | hm.statusLed.config(4, 4); // configure the status led pin 79 | hm.statusLed.set(STATUSLED_BOTH, STATUSLED_MODE_BLINKFAST, 3); 80 | 81 | #ifdef US_100 82 | // Initialize Pins for US-100 Ultrasonic distance sensor 83 | pinMode(US_100_PIN_VCC, OUTPUT); 84 | digitalWrite(US_100_PIN_VCC, LOW); // US-100 Power (off) 85 | 86 | pinMode(US_100_PIN_TRIGGER, OUTPUT); 87 | digitalWrite(US_100_PIN_TRIGGER, LOW); // US-100 Trigger (off) 88 | 89 | pinMode(US_100_PIN_ECHO, INPUT); // US-100 Echo as input pin 90 | 91 | pinMode(US_100_PIN_GND, OUTPUT); 92 | digitalWrite(US_100_PIN_GND, LOW); // US-100 Power-GND (must be off every time) 93 | #endif 94 | 95 | } 96 | 97 | void getDataFromAddressSection(uint8_t *buffer, uint8_t bufferStartAddress, uint16_t sectionAddress, uint8_t dataLen) { 98 | for (unsigned char i = 0; i < dataLen; i++) { 99 | buffer[(i + bufferStartAddress)] = pgm_read_byte(sectionAddress + i); 100 | } 101 | } 102 | 103 | void getPgmSpaceData(uint8_t *buffer, uint16_t address, uint8_t len) { 104 | for (unsigned char i = 0; i < len; i++) { 105 | buffer[i] = pgm_read_byte(address+i); 106 | } 107 | } 108 | 109 | void loop() { 110 | hm.poll(); // poll the HM communication 111 | } 112 | 113 | void cmdReset(uint8_t *data, uint8_t len) { 114 | #ifdef SER_DBG 115 | Serial << F("reset, data: "); pHex(data,len, SERIAL_DBG_PHEX_MODE_LF); 116 | #endif 117 | 118 | hm.send_ACK(); // send an ACK 119 | if (data[1] == 0) { 120 | hm.reset(); 121 | // hm.resetWdt(); 122 | } 123 | } 124 | 125 | void cmdConfigChanged(uint8_t *data, uint8_t len) { 126 | // low battery level 127 | uint8_t lowBatVoltage = regs.ch0.l0.lowBatLimit; 128 | lowBatVoltage = (lowBatVoltage < BATTERY_MIN_VOLTAGE) ? BATTERY_MIN_VOLTAGE : lowBatVoltage; 129 | lowBatVoltage = (lowBatVoltage > BATTERY_MAX_VOLTAGE) ? BATTERY_MAX_VOLTAGE : lowBatVoltage; 130 | hm.battery.setMinVoltage(lowBatVoltage); 131 | 132 | // led mode 133 | hm.setLedMode((regs.ch0.l0.ledMode) ? LED_MODE_EVERYTIME : LED_MODE_CONFIG); 134 | 135 | // power mode for HM device 136 | // hm.setPowerMode(POWER_MODE_SLEEP_WDT); 137 | hm.setPowerMode((regs.ch0.l0.burstRx) ? POWER_MODE_BURST : POWER_MODE_SLEEP_WDT); 138 | // hm.setPowerMode(POWER_MODE_ON); 139 | 140 | // set max transmit retry 141 | uint8_t transmDevTryMax = regs.ch0.l0.transmDevTryMax; 142 | transmDevTryMax = (transmDevTryMax < 1) ? 1 : transmDevTryMax; 143 | transmDevTryMax = (transmDevTryMax > 10) ? 10 : transmDevTryMax; 144 | dParm.maxRetr = transmDevTryMax; 145 | 146 | // set altitude 147 | int16_t altitude = regs.ch0.l0.altitude[1] | (regs.ch0.l0.altitude[0] << 8); 148 | altitude = (altitude < -500) ? -500 : altitude; 149 | altitude = (altitude > 10000) ? 10000 : altitude; 150 | sensTHPL.setAltitude(altitude); 151 | 152 | #ifdef SER_DBG 153 | Serial << F("Config changed. Data: "); pHex(data,len, SERIAL_DBG_PHEX_MODE_LEN | SERIAL_DBG_PHEX_MODE_LF); 154 | Serial << F("lowBatLimit: ") << regs.ch0.l0.lowBatLimit << F("\n"); 155 | Serial << F("ledMode: ") << regs.ch0.l0.ledMode << F("\n"); 156 | Serial << F("burstRx: ") << regs.ch0.l0.burstRx << F("\n"); 157 | Serial << F("transmDevTryMax: ") << transmDevTryMax << F("\n"); 158 | Serial << F("altitude: ") << altitude << F("\n"); 159 | #endif 160 | } 161 | 162 | void cmdStatusRequest(uint8_t *data, uint8_t len) { 163 | Serial << F("status request, data: "); pHex(data,len, SERIAL_DBG_PHEX_MODE_LF); 164 | _delay_ms(50); 165 | } 166 | 167 | void HM_Remote_Event(uint8_t *data, uint8_t len) { 168 | Serial << F("remote event, data: "); pHex(data,len, SERIAL_DBG_PHEX_MODE_LF); 169 | } 170 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Sensirion/examples/NonBlocking/NonBlocking.pde: -------------------------------------------------------------------------------- 1 | /* 2 | * Example code for SHT1x or SHT7x sensors demonstrating blocking calls 3 | * for temperature and humidity measurement in the setup routine and 4 | * non-blocking calls in the main loop. The pin 13 LED is flashed as a 5 | * background task while temperature and humidity measurements are made. 6 | * Note that the status register read/write demonstration code places the 7 | * sensor in low resolution mode. Delete it to stay in high res mode. 8 | * 9 | * This example contains two versions of the code: one that checks library 10 | * function return codes for error indications and one that does not. 11 | * The version with error checking may be useful in debuging possible 12 | * connection issues with the sensor. A #define selects between versions. 13 | */ 14 | 15 | #include 16 | 17 | #define ENA_ERRCHK // Enable error checking code 18 | 19 | const byte dataPin = 2; // SHTxx serial data 20 | const byte sclkPin = 3; // SHTxx serial clock 21 | const byte ledPin = 13; // Arduino built-in LED 22 | const unsigned long TRHSTEP = 5000UL; // Sensor query period 23 | const unsigned long BLINKSTEP = 250UL; // LED blink period 24 | 25 | Sensirion sht = Sensirion(dataPin, sclkPin); 26 | 27 | unsigned int rawData; 28 | float temperature; 29 | float humidity; 30 | float dewpoint; 31 | 32 | byte ledState = 0; 33 | byte measActive = false; 34 | byte measType = TEMP; 35 | 36 | unsigned long trhMillis = 0; // Time interval tracking 37 | unsigned long blinkMillis = 0; 38 | 39 | #ifdef ENA_ERRCHK 40 | 41 | // This version of the code checks return codes for errors 42 | byte error = 0; 43 | 44 | void setup() { 45 | byte stat; 46 | Serial.begin(9600); 47 | pinMode(ledPin, OUTPUT); 48 | delay(15); // Wait >= 11 ms before first cmd 49 | // Demonstrate status register read/write 50 | if (error = sht.readSR(&stat)) // Read sensor status register 51 | logError(error); 52 | Serial.print("Status reg = 0x"); 53 | Serial.println(stat, HEX); 54 | if (error = sht.writeSR(LOW_RES)) // Set sensor to low resolution 55 | logError(error); 56 | if (error = sht.readSR(&stat)) // Read sensor status register again 57 | logError(error); 58 | Serial.print("Status reg = 0x"); 59 | Serial.println(stat, HEX); 60 | // Demonstrate blocking calls 61 | if (error = sht.measTemp(&rawData)) // sht.meas(TEMP, &rawData, BLOCK) 62 | logError(error); 63 | temperature = sht.calcTemp(rawData); 64 | if (error = sht.measHumi(&rawData)) // sht.meas(HUMI, &rawData, BLOCK) 65 | logError(error); 66 | humidity = sht.calcHumi(rawData, temperature); 67 | dewpoint = sht.calcDewpoint(humidity, temperature); 68 | logData(); 69 | } 70 | 71 | void loop() { 72 | unsigned long curMillis = millis(); // Get current time 73 | 74 | // Rapidly blink LED. Blocking calls take too long to allow this. 75 | if (curMillis - blinkMillis >= BLINKSTEP) { // Time to toggle the LED state? 76 | ledState ^= 1; 77 | digitalWrite(ledPin, ledState); 78 | blinkMillis = curMillis; 79 | } 80 | 81 | // Demonstrate non-blocking calls 82 | if (curMillis - trhMillis >= TRHSTEP) { // Time for new measurements? 83 | measActive = true; 84 | measType = TEMP; 85 | if (error = sht.meas(TEMP, &rawData, NONBLOCK)) // Start temp measurement 86 | logError(error); 87 | trhMillis = curMillis; 88 | } 89 | if (measActive && (error = sht.measRdy())) { // Check measurement status 90 | if (error != S_Meas_Rdy) 91 | logError(error); 92 | if (measType == TEMP) { // Process temp or humi? 93 | measType = HUMI; 94 | temperature = sht.calcTemp(rawData); // Convert raw sensor data 95 | if (error = sht.meas(HUMI, &rawData, NONBLOCK)) // Start humi measurement 96 | logError(error); 97 | } else { 98 | measActive = false; 99 | humidity = sht.calcHumi(rawData, temperature); // Convert raw sensor data 100 | dewpoint = sht.calcDewpoint(humidity, temperature); 101 | logData(); 102 | } 103 | } 104 | } 105 | 106 | #else // If ENA_ERRCHK is not defined 107 | 108 | // This code is the same as above but without error checking 109 | void setup() { 110 | byte stat; 111 | byte error = 0; 112 | Serial.begin(9600); 113 | pinMode(ledPin, OUTPUT); 114 | delay(15); // Wait >= 11 ms before first cmd 115 | // Demonstrate status register read/write 116 | sht.readSR(&stat); // Read sensor status register 117 | Serial.print("Status reg = 0x"); 118 | Serial.println(stat, HEX); 119 | sht.writeSR(LOW_RES); // Set sensor to low resolution 120 | sht.readSR(&stat); // Read sensor status register again 121 | Serial.print("Status reg = 0x"); 122 | Serial.println(stat, HEX); 123 | // Demonstrate blocking calls 124 | sht.measTemp(&rawData); // sht.meas(TEMP, &rawData, BLOCK) 125 | temperature = sht.calcTemp(rawData); 126 | sht.measHumi(&rawData); // sht.meas(HUMI, &rawData, BLOCK) 127 | humidity = sht.calcHumi(rawData, temperature); 128 | dewpoint = sht.calcDewpoint(humidity, temperature); 129 | logData(); 130 | } 131 | 132 | void loop() { 133 | unsigned long curMillis = millis(); // Get current time 134 | 135 | // Rapidly blink LED. Blocking calls take too long to allow this. 136 | if (curMillis - blinkMillis >= BLINKSTEP) { // Time to toggle the LED state? 137 | ledState ^= 1; 138 | digitalWrite(ledPin, ledState); 139 | blinkMillis = curMillis; 140 | } 141 | 142 | // Demonstrate non-blocking calls 143 | if (curMillis - trhMillis >= TRHSTEP) { // Time for new measurements? 144 | measActive = true; 145 | measType = TEMP; 146 | sht.meas(TEMP, &rawData, NONBLOCK); // Start temp measurement 147 | trhMillis = curMillis; 148 | } 149 | if (measActive && sht.measRdy()) { // Check measurement status 150 | if (measType == TEMP) { // Process temp or humi? 151 | measType = HUMI; 152 | temperature = sht.calcTemp(rawData); // Convert raw sensor data 153 | sht.meas(HUMI, &rawData, NONBLOCK); // Start humi measurement 154 | } else { 155 | measActive = false; 156 | humidity = sht.calcHumi(rawData, temperature); // Convert raw sensor data 157 | dewpoint = sht.calcDewpoint(humidity, temperature); 158 | logData(); 159 | } 160 | } 161 | } 162 | 163 | #endif // End of non-error-checking example 164 | 165 | void logData() { 166 | Serial.print("Temperature = "); Serial.print(temperature); 167 | Serial.print(" C, Humidity = "); Serial.print(humidity); 168 | Serial.print(" %, Dewpoint = "); Serial.print(dewpoint); 169 | Serial.println(" C"); 170 | } 171 | 172 | // The following code is only used with error checking enabled 173 | void logError(byte error) { 174 | switch (error) { 175 | case S_Err_NoACK: 176 | Serial.println("Error: No response (ACK) received from sensor!"); 177 | break; 178 | case S_Err_CRC: 179 | Serial.println("Error: CRC mismatch!"); 180 | break; 181 | case S_Err_TO: 182 | Serial.println("Error: Measurement timeout!"); 183 | break; 184 | default: 185 | Serial.println("Unknown error received!"); 186 | break; 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/TSL2561/examples/SFE_TSL2561_example/SFE_TSL2561_example.ino: -------------------------------------------------------------------------------- 1 | /* SFE_TSL2561 library example sketch 2 | 3 | This sketch shows how to use the SFE_TSL2561 4 | library to read the AMS/TAOS TSL2561 5 | light sensor. 6 | 7 | Product page: https://www.sparkfun.com/products/11824 8 | Hook-up guide: https://learn.sparkfun.com/tutorials/getting-started-with-the-tsl2561-luminosity-sensor 9 | 10 | Hardware connections: 11 | 12 | 3V3 to 3.3V 13 | GND to GND 14 | 15 | (WARNING: do not connect 3V3 to 5V 16 | or the sensor will be damaged!) 17 | 18 | You will also need to connect the I2C pins (SCL and SDA) to your Arduino. 19 | The pins are different on different Arduinos: 20 | 21 | SDA SCL 22 | Any Arduino "SDA" "SCL" 23 | Uno, Redboard, Pro A4 A5 24 | Mega2560, Due 20 21 25 | Leonardo 2 3 26 | 27 | You do not need to connect the INT (interrupt) pin 28 | for basic operation. 29 | 30 | Operation: 31 | 32 | Upload this sketch to your Arduino, and open the 33 | Serial Monitor window to 9600 baud. 34 | 35 | Have fun! -Your friends at SparkFun. 36 | 37 | Our example code uses the "beerware" license. 38 | You can do anything you like with this code. 39 | No really, anything. If you find it useful, 40 | buy me a beer someday. 41 | 42 | V10 Mike Grusin, SparkFun Electronics 12/26/2013 43 | */ 44 | 45 | // Your sketch must #include this library, and the Wire library 46 | // (Wire is a standard library included with Arduino): 47 | 48 | #include 49 | #include 50 | 51 | // Create an SFE_TSL2561 object, here called "light": 52 | 53 | SFE_TSL2561 light; 54 | 55 | // Global variables: 56 | 57 | boolean gain; // Gain setting, 0 = X1, 1 = X16; 58 | unsigned int ms; // Integration ("shutter") time in milliseconds 59 | 60 | void setup() 61 | { 62 | // Initialize the Serial port: 63 | 64 | Serial.begin(9600); 65 | Serial.println("TSL2561 example sketch"); 66 | 67 | // Initialize the SFE_TSL2561 library 68 | 69 | // You can pass nothing to light.begin() for the default I2C address (0x39), 70 | // or use one of the following presets if you have changed 71 | // the ADDR jumper on the board: 72 | 73 | // TSL2561_ADDR_0 address with '0' shorted on board (0x29) 74 | // TSL2561_ADDR default address (0x39) 75 | // TSL2561_ADDR_1 address with '1' shorted on board (0x49) 76 | 77 | // For more information see the hookup guide at: https://learn.sparkfun.com/tutorials/getting-started-with-the-tsl2561-luminosity-sensor 78 | 79 | light.begin(); 80 | 81 | // Get factory ID from sensor: 82 | // (Just for fun, you don't need to do this to operate the sensor) 83 | 84 | unsigned char ID; 85 | 86 | if (light.getID(ID)) 87 | { 88 | Serial.print("Got factory ID: 0X"); 89 | Serial.print(ID,HEX); 90 | Serial.println(", should be 0X5X"); 91 | } 92 | // Most library commands will return true if communications was successful, 93 | // and false if there was a problem. You can ignore this returned value, 94 | // or check whether a command worked correctly and retrieve an error code: 95 | else 96 | { 97 | byte error = light.getError(); 98 | printError(error); 99 | } 100 | 101 | // The light sensor has a default integration time of 402ms, 102 | // and a default gain of low (1X). 103 | 104 | // If you would like to change either of these, you can 105 | // do so using the setTiming() command. 106 | 107 | // If gain = false (0), device is set to low gain (1X) 108 | // If gain = high (1), device is set to high gain (16X) 109 | 110 | gain = 0; 111 | 112 | // If time = 0, integration will be 13.7ms 113 | // If time = 1, integration will be 101ms 114 | // If time = 2, integration will be 402ms 115 | // If time = 3, use manual start / stop to perform your own integration 116 | 117 | unsigned char time = 2; 118 | 119 | // setTiming() will set the third parameter (ms) to the 120 | // requested integration time in ms (this will be useful later): 121 | 122 | Serial.println("Set timing..."); 123 | light.setTiming(gain,time,ms); 124 | 125 | // To start taking measurements, power up the sensor: 126 | 127 | Serial.println("Powerup..."); 128 | light.setPowerUp(); 129 | 130 | // The sensor will now gather light during the integration time. 131 | // After the specified time, you can retrieve the result from the sensor. 132 | // Once a measurement occurs, another integration period will start. 133 | } 134 | 135 | void loop() 136 | { 137 | // Wait between measurements before retrieving the result 138 | // (You can also configure the sensor to issue an interrupt 139 | // when measurements are complete) 140 | 141 | // This sketch uses the TSL2561's built-in integration timer. 142 | // You can also perform your own manual integration timing 143 | // by setting "time" to 3 (manual) in setTiming(), 144 | // then performing a manualStart() and a manualStop() as in the below 145 | // commented statements: 146 | 147 | // ms = 1000; 148 | // light.manualStart(); 149 | delay(ms); 150 | // light.manualStop(); 151 | 152 | // Once integration is complete, we'll retrieve the data. 153 | 154 | // There are two light sensors on the device, one for visible light 155 | // and one for infrared. Both sensors are needed for lux calculations. 156 | 157 | // Retrieve the data from the device: 158 | 159 | unsigned int data0, data1; 160 | 161 | if (light.getData(data0,data1)) 162 | { 163 | // getData() returned true, communication was successful 164 | 165 | Serial.print("data0: "); 166 | Serial.print(data0); 167 | Serial.print(" data1: "); 168 | Serial.print(data1); 169 | 170 | // To calculate lux, pass all your settings and readings 171 | // to the getLux() function. 172 | 173 | // The getLux() function will return 1 if the calculation 174 | // was successful, or 0 if one or both of the sensors was 175 | // saturated (too much light). If this happens, you can 176 | // reduce the integration time and/or gain. 177 | // For more information see the hookup guide at: https://learn.sparkfun.com/tutorials/getting-started-with-the-tsl2561-luminosity-sensor 178 | 179 | double lux; // Resulting lux value 180 | boolean good; // True if neither sensor is saturated 181 | 182 | // Perform lux calculation: 183 | 184 | good = light.getLux(gain,ms,data0,data1,lux); 185 | 186 | // Print out the results: 187 | 188 | Serial.print(" lux: "); 189 | Serial.print(lux); 190 | if (good) Serial.println(" (good)"); else Serial.println(" (BAD)"); 191 | } 192 | else 193 | { 194 | // getData() returned false because of an I2C error, inform the user. 195 | 196 | byte error = light.getError(); 197 | printError(error); 198 | } 199 | } 200 | 201 | void printError(byte error) 202 | // If there's an I2C error, this function will 203 | // print out an explanation. 204 | { 205 | Serial.print("I2C error: "); 206 | Serial.print(error,DEC); 207 | Serial.print(", "); 208 | 209 | switch(error) 210 | { 211 | case 0: 212 | Serial.println("success"); 213 | break; 214 | case 1: 215 | Serial.println("data too long for transmit buffer"); 216 | break; 217 | case 2: 218 | Serial.println("received NACK on address (disconnected?)"); 219 | break; 220 | case 3: 221 | Serial.println("received NACK on data"); 222 | break; 223 | case 4: 224 | Serial.println("other error"); 225 | break; 226 | default: 227 | Serial.println("unknown error"); 228 | } 229 | } 230 | 231 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/BMP085/BMP085.cpp: -------------------------------------------------------------------------------- 1 | // This is a simple but accurate BMP085 sensor library that doesn't suck 2 | // Does high res temperature, pressure and altitude calculations based on 3 | // the datasheet documentation 4 | // (c) adafruit - MIT license - https://github.com/adafruit/BMP085-Library 5 | 6 | #include "BMP085.h" 7 | #include 8 | #include 9 | 10 | void BMP085::begin(uint8_t mode) { 11 | if (mode > BMP085_ULTRAHIGHRES) 12 | mode = BMP085_ULTRAHIGHRES; 13 | oversampling = mode; 14 | 15 | Wire.begin(); 16 | 17 | /* read calibration data */ 18 | ac1 = read16(BMP085_CAL_AC1); 19 | ac2 = read16(BMP085_CAL_AC2); 20 | ac3 = read16(BMP085_CAL_AC3); 21 | ac4 = read16(BMP085_CAL_AC4); 22 | ac5 = read16(BMP085_CAL_AC5); 23 | ac6 = read16(BMP085_CAL_AC6); 24 | 25 | b1 = read16(BMP085_CAL_B1); 26 | b2 = read16(BMP085_CAL_B2); 27 | 28 | mb = read16(BMP085_CAL_MB); 29 | mc = read16(BMP085_CAL_MC); 30 | md = read16(BMP085_CAL_MD); 31 | #if (BMP085_DEBUG == 1) 32 | Serial.print("ac1 = "); Serial.println(ac1, DEC); 33 | Serial.print("ac2 = "); Serial.println(ac2, DEC); 34 | Serial.print("ac3 = "); Serial.println(ac3, DEC); 35 | Serial.print("ac4 = "); Serial.println(ac4, DEC); 36 | Serial.print("ac5 = "); Serial.println(ac5, DEC); 37 | Serial.print("ac6 = "); Serial.println(ac6, DEC); 38 | 39 | Serial.print("b1 = "); Serial.println(b1, DEC); 40 | Serial.print("b2 = "); Serial.println(b2, DEC); 41 | 42 | Serial.print("mb = "); Serial.println(mb, DEC); 43 | Serial.print("mc = "); Serial.println(mc, DEC); 44 | Serial.print("md = "); Serial.println(md, DEC); 45 | #endif 46 | } 47 | 48 | uint16_t BMP085::readRawTemperature(void) { 49 | write8(BMP085_CONTROL, BMP085_READTEMPCMD); 50 | _delay_ms(5); 51 | #if BMP085_DEBUG == 1 52 | Serial.print("Raw temp: "); Serial.println(read16(BMP085_TEMPDATA)); 53 | #endif 54 | return read16(BMP085_TEMPDATA); 55 | } 56 | 57 | uint32_t BMP085::readRawPressure(void) { 58 | uint32_t raw; 59 | 60 | write8(BMP085_CONTROL, BMP085_READPRESSURECMD + (oversampling << 6)); 61 | 62 | if (oversampling == BMP085_ULTRALOWPOWER) 63 | _delay_ms(5); 64 | else if (oversampling == BMP085_STANDARD) 65 | _delay_ms(8); 66 | else if (oversampling == BMP085_HIGHRES) 67 | _delay_ms(14); 68 | else 69 | _delay_ms(26); 70 | 71 | raw = read16(BMP085_PRESSUREDATA); 72 | raw <<= 8; 73 | raw |= read8(BMP085_PRESSUREDATA+2); 74 | raw >>= (8 - oversampling); 75 | #if BMP085_DEBUG == 1 76 | Serial.print("Raw pressure: "); Serial.println(raw); 77 | #endif 78 | return raw; 79 | } 80 | 81 | 82 | int32_t BMP085::readPressure(void) { 83 | int32_t UT, UP, B3, B5, B6, X1, X2, X3, p; 84 | uint32_t B4, B7; 85 | 86 | UT = readRawTemperature(); 87 | UP = readRawPressure(); 88 | 89 | #if BMP085_DEBUG == 1 90 | // use datasheet numbers! 91 | UT = 27898; 92 | UP = 23843; 93 | ac6 = 23153; 94 | ac5 = 32757; 95 | mc = -8711; 96 | md = 2868; 97 | b1 = 6190; 98 | b2 = 4; 99 | ac3 = -14383; 100 | ac2 = -72; 101 | ac1 = 408; 102 | ac4 = 32741; 103 | oversampling = 0; 104 | #endif 105 | 106 | // do temperature calculations 107 | X1 = ((UT - (int32_t)ac6) * (int32_t)ac5) >> 15; 108 | X2 = ((int32_t)mc << 11) - (X1 + md)/2; // round up 109 | X2 /= (X1 + md); 110 | B5 = X1 + X2; 111 | 112 | #if BMP085_DEBUG == 1 113 | Serial.print("X1 = "); Serial.println(X1); 114 | Serial.print("X2 = "); Serial.println(X2); 115 | Serial.print("B5 = "); Serial.println(B5); 116 | #endif 117 | 118 | // do pressure calcs 119 | B6 = B5 - 4000; 120 | X1 = ((int32_t)b2 * ( (B6 * B6)>>12 )) >> 11; 121 | X2 = ((int32_t)ac2 * B6) >> 11; 122 | X3 = X1 + X2; 123 | B3 = ((((int32_t)ac1*4 + X3) << oversampling) + 2) / 4; 124 | 125 | #if BMP085_DEBUG == 1 126 | Serial.print("B6 = "); Serial.println(B6); 127 | Serial.print("X1 = "); Serial.println(X1); 128 | Serial.print("X2 = "); Serial.println(X2); 129 | Serial.print("B3 = "); Serial.println(B3); 130 | #endif 131 | 132 | X1 = ((int32_t)ac3 * B6) >> 13; 133 | X2 = ((int32_t)b1 * ((B6 * B6) >> 12)) >> 16; 134 | X3 = ((X1 + X2) + 2) >> 2; 135 | B4 = ((uint32_t)ac4 * (uint32_t)(X3 + 32768)) >> 15; 136 | B7 = ((uint32_t)UP - B3) * (uint32_t)( 50000UL >> oversampling ); 137 | 138 | #if BMP085_DEBUG == 1 139 | Serial.print("X1 = "); Serial.println(X1); 140 | Serial.print("X2 = "); Serial.println(X2); 141 | Serial.print("B4 = "); Serial.println(B4); 142 | Serial.print("B7 = "); Serial.println(B7); 143 | #endif 144 | 145 | if (B7 < 0x80000000) { 146 | p = (B7 * 2) / B4; 147 | } else { 148 | p = (B7 * 2) / B3; 149 | } 150 | X1 = (p >> 8) * (p >> 8); 151 | X1 = (X1 * 3038) >> 16; 152 | X2 = (-7357 * p) >> 16; 153 | 154 | #if BMP085_DEBUG == 1 155 | Serial.print("p = "); Serial.println(p); 156 | Serial.print("X1 = "); Serial.println(X1); 157 | Serial.print("X2 = "); Serial.println(X2); 158 | #endif 159 | 160 | p = p + ((X1 + X2 + (int32_t)3791)>>4); 161 | #if BMP085_DEBUG == 1 162 | Serial.print("p = "); Serial.println(p); 163 | #endif 164 | return p; 165 | } 166 | 167 | 168 | float BMP085::readTemperature(void) { 169 | int32_t UT, X1, X2, B5; // following ds convention 170 | float temp; 171 | 172 | UT = readRawTemperature(); 173 | 174 | #if BMP085_DEBUG == 1 175 | // use datasheet numbers! 176 | UT = 27898; 177 | ac6 = 23153; 178 | ac5 = 32757; 179 | mc = -8711; 180 | md = 2868; 181 | #endif 182 | 183 | // step 1 184 | X1 = ((UT - (int32_t)ac6) * (int32_t)ac5) >> 15; 185 | X2 = ((int32_t)mc << 11) / (X1 + (int32_t)md); 186 | B5 = X1 + X2; 187 | temp = (B5 + 8) >> 4; 188 | temp /= 10; 189 | 190 | return temp; 191 | } 192 | 193 | float BMP085::readAltitude(float sealevelPressure) { 194 | float altitude; 195 | 196 | float pressure = readPressure(); 197 | 198 | altitude = 44330 * (1.0 - pow(pressure /sealevelPressure,0.1903)); 199 | 200 | return altitude; 201 | } 202 | 203 | 204 | /*********************************************************************/ 205 | 206 | uint8_t BMP085::read8(uint8_t a) { 207 | uint8_t ret; 208 | 209 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 210 | #if (ARDUINO >= 100) 211 | Wire.write(a); // sends register address to read from 212 | #else 213 | Wire.send(a); // sends register address to read from 214 | #endif 215 | Wire.endTransmission(); // end transmission 216 | 217 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 218 | Wire.requestFrom(BMP085_I2CADDR, 1);// send data n-bytes read 219 | #if (ARDUINO >= 100) 220 | ret = Wire.read(); // receive DATA 221 | #else 222 | ret = Wire.receive(); // receive DATA 223 | #endif 224 | Wire.endTransmission(); // end transmission 225 | 226 | return ret; 227 | } 228 | 229 | uint16_t BMP085::read16(uint8_t a) { 230 | uint16_t ret; 231 | 232 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 233 | #if (ARDUINO >= 100) 234 | Wire.write(a); // sends register address to read from 235 | #else 236 | Wire.send(a); // sends register address to read from 237 | #endif 238 | Wire.endTransmission(); // end transmission 239 | 240 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 241 | Wire.requestFrom(BMP085_I2CADDR, 2);// send data n-bytes read 242 | #if (ARDUINO >= 100) 243 | ret = Wire.read(); // receive DATA 244 | ret <<= 8; 245 | ret |= Wire.read(); // receive DATA 246 | #else 247 | ret = Wire.receive(); // receive DATA 248 | ret <<= 8; 249 | ret |= Wire.receive(); // receive DATA 250 | #endif 251 | Wire.endTransmission(); // end transmission 252 | 253 | return ret; 254 | } 255 | 256 | void BMP085::write8(uint8_t a, uint8_t d) { 257 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 258 | #if (ARDUINO >= 100) 259 | Wire.write(a); // sends register address to read from 260 | Wire.write(d); // write data 261 | #else 262 | Wire.send(a); // sends register address to read from 263 | Wire.send(d); // write data 264 | #endif 265 | Wire.endTransmission(); // end transmission 266 | } 267 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Wire/Wire.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | TwoWire.cpp - TWI/I2C library for Wiring & Arduino 3 | Copyright (c) 2006 Nicholas Zambetti. All right reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts 20 | */ 21 | 22 | extern "C" { 23 | #include 24 | #include 25 | #include 26 | #include "twi.h" 27 | } 28 | 29 | #include "Wire.h" 30 | 31 | // Initialize Class Variables ////////////////////////////////////////////////// 32 | 33 | uint8_t TwoWire::rxBuffer[BUFFER_LENGTH]; 34 | uint8_t TwoWire::rxBufferIndex = 0; 35 | uint8_t TwoWire::rxBufferLength = 0; 36 | 37 | uint8_t TwoWire::txAddress = 0; 38 | uint8_t TwoWire::txBuffer[BUFFER_LENGTH]; 39 | uint8_t TwoWire::txBufferIndex = 0; 40 | uint8_t TwoWire::txBufferLength = 0; 41 | 42 | uint8_t TwoWire::transmitting = 0; 43 | void (*TwoWire::user_onRequest)(void); 44 | void (*TwoWire::user_onReceive)(int); 45 | 46 | // Constructors //////////////////////////////////////////////////////////////// 47 | 48 | TwoWire::TwoWire() 49 | { 50 | } 51 | 52 | // Public Methods ////////////////////////////////////////////////////////////// 53 | 54 | void TwoWire::begin(void) 55 | { 56 | rxBufferIndex = 0; 57 | rxBufferLength = 0; 58 | 59 | txBufferIndex = 0; 60 | txBufferLength = 0; 61 | 62 | twi_init(); 63 | } 64 | 65 | void TwoWire::begin(uint8_t address) 66 | { 67 | twi_setAddress(address); 68 | twi_attachSlaveTxEvent(onRequestService); 69 | twi_attachSlaveRxEvent(onReceiveService); 70 | begin(); 71 | } 72 | 73 | void TwoWire::begin(int address) 74 | { 75 | begin((uint8_t)address); 76 | } 77 | 78 | uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) 79 | { 80 | // clamp to buffer length 81 | if(quantity > BUFFER_LENGTH){ 82 | quantity = BUFFER_LENGTH; 83 | } 84 | // perform blocking read into buffer 85 | uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop); 86 | // set rx buffer iterator vars 87 | rxBufferIndex = 0; 88 | rxBufferLength = read; 89 | 90 | return read; 91 | } 92 | 93 | uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) 94 | { 95 | return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); 96 | } 97 | 98 | uint8_t TwoWire::requestFrom(int address, int quantity) 99 | { 100 | return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); 101 | } 102 | 103 | uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) 104 | { 105 | return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); 106 | } 107 | 108 | void TwoWire::beginTransmission(uint8_t address) 109 | { 110 | // indicate that we are transmitting 111 | transmitting = 1; 112 | // set address of targeted slave 113 | txAddress = address; 114 | // reset tx buffer iterator vars 115 | txBufferIndex = 0; 116 | txBufferLength = 0; 117 | } 118 | 119 | void TwoWire::beginTransmission(int address) 120 | { 121 | beginTransmission((uint8_t)address); 122 | } 123 | 124 | // 125 | // Originally, 'endTransmission' was an f(void) function. 126 | // It has been modified to take one parameter indicating 127 | // whether or not a STOP should be performed on the bus. 128 | // Calling endTransmission(false) allows a sketch to 129 | // perform a repeated start. 130 | // 131 | // WARNING: Nothing in the library keeps track of whether 132 | // the bus tenure has been properly ended with a STOP. It 133 | // is very possible to leave the bus in a hung state if 134 | // no call to endTransmission(true) is made. Some I2C 135 | // devices will behave oddly if they do not see a STOP. 136 | // 137 | uint8_t TwoWire::endTransmission(uint8_t sendStop) 138 | { 139 | // transmit buffer (blocking) 140 | int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1, sendStop); 141 | // reset tx buffer iterator vars 142 | txBufferIndex = 0; 143 | txBufferLength = 0; 144 | // indicate that we are done transmitting 145 | transmitting = 0; 146 | return ret; 147 | } 148 | 149 | // This provides backwards compatibility with the original 150 | // definition, and expected behaviour, of endTransmission 151 | // 152 | uint8_t TwoWire::endTransmission(void) 153 | { 154 | return endTransmission(true); 155 | } 156 | 157 | // must be called in: 158 | // slave tx event callback 159 | // or after beginTransmission(address) 160 | size_t TwoWire::write(uint8_t data) 161 | { 162 | if(transmitting){ 163 | // in master transmitter mode 164 | // don't bother if buffer is full 165 | if(txBufferLength >= BUFFER_LENGTH){ 166 | setWriteError(); 167 | return 0; 168 | } 169 | // put byte in tx buffer 170 | txBuffer[txBufferIndex] = data; 171 | ++txBufferIndex; 172 | // update amount in buffer 173 | txBufferLength = txBufferIndex; 174 | }else{ 175 | // in slave send mode 176 | // reply to master 177 | twi_transmit(&data, 1); 178 | } 179 | return 1; 180 | } 181 | 182 | // must be called in: 183 | // slave tx event callback 184 | // or after beginTransmission(address) 185 | size_t TwoWire::write(const uint8_t *data, size_t quantity) 186 | { 187 | if(transmitting){ 188 | // in master transmitter mode 189 | for(size_t i = 0; i < quantity; ++i){ 190 | write(data[i]); 191 | } 192 | }else{ 193 | // in slave send mode 194 | // reply to master 195 | twi_transmit(data, quantity); 196 | } 197 | return quantity; 198 | } 199 | 200 | // must be called in: 201 | // slave rx event callback 202 | // or after requestFrom(address, numBytes) 203 | int TwoWire::available(void) 204 | { 205 | return rxBufferLength - rxBufferIndex; 206 | } 207 | 208 | // must be called in: 209 | // slave rx event callback 210 | // or after requestFrom(address, numBytes) 211 | int TwoWire::read(void) 212 | { 213 | int value = -1; 214 | 215 | // get each successive byte on each call 216 | if(rxBufferIndex < rxBufferLength){ 217 | value = rxBuffer[rxBufferIndex]; 218 | ++rxBufferIndex; 219 | } 220 | 221 | return value; 222 | } 223 | 224 | // must be called in: 225 | // slave rx event callback 226 | // or after requestFrom(address, numBytes) 227 | int TwoWire::peek(void) 228 | { 229 | int value = -1; 230 | 231 | if(rxBufferIndex < rxBufferLength){ 232 | value = rxBuffer[rxBufferIndex]; 233 | } 234 | 235 | return value; 236 | } 237 | 238 | void TwoWire::flush(void) 239 | { 240 | // XXX: to be implemented. 241 | } 242 | 243 | // behind the scenes function that is called when data is received 244 | void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) 245 | { 246 | // don't bother if user hasn't registered a callback 247 | if(!user_onReceive){ 248 | return; 249 | } 250 | // don't bother if rx buffer is in use by a master requestFrom() op 251 | // i know this drops data, but it allows for slight stupidity 252 | // meaning, they may not have read all the master requestFrom() data yet 253 | if(rxBufferIndex < rxBufferLength){ 254 | return; 255 | } 256 | // copy twi rx buffer into local read buffer 257 | // this enables new reads to happen in parallel 258 | for(uint8_t i = 0; i < numBytes; ++i){ 259 | rxBuffer[i] = inBytes[i]; 260 | } 261 | // set rx iterator vars 262 | rxBufferIndex = 0; 263 | rxBufferLength = numBytes; 264 | // alert user program 265 | user_onReceive(numBytes); 266 | } 267 | 268 | // behind the scenes function that is called when data is requested 269 | void TwoWire::onRequestService(void) 270 | { 271 | // don't bother if user hasn't registered a callback 272 | if(!user_onRequest){ 273 | return; 274 | } 275 | // reset tx buffer iterator vars 276 | // !!! this will kill any pending pre-master sendTo() activity 277 | txBufferIndex = 0; 278 | txBufferLength = 0; 279 | // alert user program 280 | user_onRequest(); 281 | } 282 | 283 | // sets function called on slave write 284 | void TwoWire::onReceive( void (*function)(int) ) 285 | { 286 | user_onReceive = function; 287 | } 288 | 289 | // sets function called on slave read 290 | void TwoWire::onRequest( void (*function)(void) ) 291 | { 292 | user_onRequest = function; 293 | } 294 | 295 | // Preinstantiate Objects ////////////////////////////////////////////////////// 296 | 297 | TwoWire Wire = TwoWire(); 298 | 299 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/TSL2561/TSL2561.h: -------------------------------------------------------------------------------- 1 | /* 2 | TSL2561 illumination sensor library for Arduino 3 | Mike Grusin, SparkFun Electronics 4 | 5 | This library provides functions to access the TAOS TSL2561 6 | Illumination Sensor. 7 | 8 | Our example code uses the "beerware" license. You can do anything 9 | you like with this code. No really, anything. If you find it useful, 10 | buy me a beer someday. 11 | 12 | version 1.0 2013/09/20 MDG initial version 13 | */ 14 | 15 | #ifndef TSL2561_h 16 | #define TSL2561_h 17 | 18 | #if defined(ARDUINO) && ARDUINO >= 100 19 | #include "Arduino.h" 20 | #else 21 | #include "WProgram.h" 22 | #endif 23 | 24 | #define INTEGATION_TIME_14 0 25 | #define INTEGATION_TIME_101 1 26 | #define INTEGATION_TIME_402 2 27 | #define INTEGATION_TIME_MANUAL 3 28 | 29 | #define TSL2561_ADDR_0 0x29 // address with '0' shorted on board 30 | #define TSL2561_ADDR 0x39 // default address 31 | #define TSL2561_ADDR_1 0x49 // address with '1' shorted on board 32 | 33 | // TSL2561 registers 34 | #define TSL2561_CMD 0x80 35 | #define TSL2561_CMD_CLEAR 0xC0 36 | #define TSL2561_REG_CONTROL 0x00 37 | #define TSL2561_REG_TIMING 0x01 38 | #define TSL2561_REG_THRESH_L 0x02 39 | #define TSL2561_REG_THRESH_H 0x04 40 | #define TSL2561_REG_INTCTL 0x06 41 | #define TSL2561_REG_ID 0x0A 42 | #define TSL2561_REG_DATA_0 0x0C 43 | #define TSL2561_REG_DATA_1 0x0E 44 | 45 | #define TSL2561_INTERRUPT_CONTROL_DISABLED 0b00 46 | #define TSL2561_INTERRUPT_CONTROL_LEVEL 0b01 47 | #define TSL2561_INTERRUPT_CONTROL_SMBALERT 0b10 48 | 49 | #define TSL2561_INTERRUPT_PSELECT_EVERY_ADC 0b0000 50 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_1 0b0001 51 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_2 0b0010 52 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_3 0b0011 53 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_4 0b0100 54 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_5 0b0101 55 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_6 0b0110 56 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_7 0b0110 57 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_8 0b0111 58 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_9 0b1001 59 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_10 0b1010 60 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_11 0b1011 61 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_12 0b1100 62 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_13 0b1101 63 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_14 0b1110 64 | #define TSL2561_INTERRUPT_PSELECT_OUT_OF_RANGE_15 0b1111 65 | 66 | #define TSL2561_INTERRUPT_CONTROL_DISABLED 0b00 67 | 68 | class TSL2561 { 69 | public: 70 | /** 71 | * The constructor 72 | */ 73 | TSL2561(void); 74 | 75 | /** 76 | * Initialize TSL2561 library with default address (0x39). 77 | */ 78 | void begin(void); 79 | 80 | /** 81 | * Initialize TSL2561 library to arbitrary address or: 82 | * TSL2561_ADDR_0 (0x29 address pin connected to gnd) 83 | * TSL2561_ADDR (0x39 address pin not connected) 84 | * TSL2561_ADDR_1 (0x49 address pin conneted to vcc) 85 | */ 86 | void begin(char i2c_address); 87 | 88 | /** 89 | * Turn on TSL2561, begin integrations 90 | * Returns true (1) if successful, false (0) if there was an I2C error 91 | * (Also see getError() below) 92 | */ 93 | boolean setPowerUp(void); 94 | 95 | /** 96 | * Turn off TSL2561 97 | * Returns true (1) if successful, false (0) if there was an I2C error 98 | * (Also see getError() below) 99 | */ 100 | boolean setPowerDown(void); 101 | 102 | /** 103 | * If gain = false (0), device is set to low gain (1X) 104 | * If gain = high (1), device is set to high gain (16X) 105 | * If time = 0, integration will be 13.7ms 106 | * If time = 1, integration will be 101ms 107 | * If time = 2, integration will be 402ms 108 | * If time = 3, use manual start / stop 109 | * Returns true (1) if successful, false (0) if there was an I2C error 110 | * (Also see getError() below) 111 | */ 112 | boolean setTiming(boolean gain, unsigned char timeConst); 113 | 114 | /** 115 | * Starts a manual integration period 116 | * After running this command, you must manually stop integration with manualStop() 117 | * Internally sets integration time to 3 for manual integration (gain is unchanged) 118 | * Returns true (1) if successful, false (0) if there was an I2C error 119 | * (Also see getError() below) 120 | */ 121 | boolean manualStart(void); 122 | 123 | /** 124 | * Stops a manual integration period 125 | * Returns true (1) if successful, false (0) if there was an I2C error 126 | * (Also see getError() below) 127 | */ 128 | boolean manualStop(void); 129 | 130 | /** 131 | * Retrieve raw integration results 132 | * data0 and data1 will be set to integration results 133 | * Returns true (1) if successful, false (0) if there was an I2C error 134 | * (Also see getError() below) 135 | */ 136 | boolean getData(unsigned int &CH0, unsigned int &CH1); 137 | 138 | boolean readData(unsigned int &data0, unsigned int &data1); 139 | 140 | void setIntergrationTime(uint16_t integrationTime); 141 | 142 | /** 143 | * Convert raw data to lux 144 | * CH0, CH1: results from getData() 145 | * lux will be set to resulting lux calculation 146 | * returns true (1) if calculation was successful 147 | * returns false (0) and lux = 0.0 if the sensor was satturated 148 | */ 149 | boolean getLux(unsigned int CH0, unsigned int CH1, double &lux); 150 | 151 | /** 152 | * Sets up interrupt operations 153 | * If control = 0, interrupt output disabled 154 | * If control = 1, use level interrupt, see setInterruptThreshold() 155 | * If persist = 0, every integration cycle generates an interrupt 156 | * If persist = 1, any value outside of threshold generates an interrupt 157 | * If persist = 2 to 15, value must be outside of threshold for 2 to 15 integration cycles 158 | * Returns true (1) if successful, false (0) if there was an I2C error 159 | * (Also see getError() below) 160 | */ 161 | boolean setInterruptControl(unsigned char control, unsigned char persist); 162 | 163 | /** 164 | * Set interrupt thresholds (channel 0 only) 165 | * low, high: 16-bit threshold values 166 | * Returns true (1) if successful, false (0) if there was an I2C error 167 | * (Also see getError() below) 168 | */ 169 | boolean setInterruptThreshold(uint16_t low, uint16_t high); 170 | 171 | /* 172 | * Clears an active interrupt 173 | * Returns true (1) if successful, false (0) if there was an I2C error 174 | * (Also see getError() below) 175 | */ 176 | boolean clearInterrupt(void); 177 | 178 | /* 179 | * Retrieves part and revision code from TSL2561 180 | * Sets ID to part ID (see datasheet) 181 | * Returns true (1) if successful, false (0) if there was an I2C error 182 | * (Also see getError() below) 183 | */ 184 | boolean getID(unsigned char &ID); 185 | 186 | /** 187 | * If any library command fails, you can retrieve an extended 188 | * error code using this command. Errors are from the wire library: 189 | * 0 = Success 190 | * 1 = Data too long to fit in transmit buffer 191 | * 2 = Received NACK on transmit of address 192 | * 3 = Received NACK on transmit of data 193 | * 4 = Other error 194 | */ 195 | byte getError(void); 196 | 197 | boolean setTimingManual(unsigned int ms); 198 | 199 | void __attribute__((always_inline)) delayloop16 (unsigned int count); 200 | 201 | double readBrightness(unsigned int &data0, unsigned int &data1); 202 | 203 | 204 | private: 205 | char _i2c_address; 206 | uint16_t _integrationTime; 207 | uint8_t _gain; 208 | byte _error; 209 | 210 | /** 211 | * Reads a byte from a TSL2561 address 212 | * Address: TSL2561 address (0 to 15) 213 | * Value will be set to stored byte 214 | * Returns true (1) if successful, false (0) if there was an I2C error 215 | * (Also see getError() above) 216 | */ 217 | boolean readByte(unsigned char address, unsigned char &value); 218 | 219 | /** 220 | * Write a byte to a TSL2561 address 221 | * Address: TSL2561 address (0 to 15) 222 | * Value: byte to write to address 223 | * Returns true (1) if successful, false (0) if there was an I2C error 224 | * (Also see getError() above) 225 | */ 226 | boolean writeByte(unsigned char address, unsigned char value); 227 | 228 | /** 229 | * Reads an unsigned integer (16 bits) from a TSL2561 address (low byte first) 230 | * Address: TSL2561 address (0 to 15), low byte first 231 | * Value will be set to stored unsigned integer 232 | * Returns true (1) if successful, false (0) if there was an I2C error 233 | * Also see getError() above) 234 | */ 235 | boolean readUInt(unsigned char address, unsigned int &value); 236 | 237 | /** 238 | * Write an unsigned integer (16 bits) to a TSL2561 address (low byte first) 239 | * Address: TSL2561 address (0 to 15), low byte first 240 | * Value: unsigned int to write to address 241 | * Returns true (1) if successful, false (0) if there was an I2C error 242 | * (Also see getError() above) 243 | */ 244 | boolean writeUInt(unsigned char address, unsigned int value); 245 | 246 | double CalculateLux(unsigned int ch0, unsigned int ch1); 247 | 248 | }; 249 | 250 | #endif 251 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Sensirion/Sensirion.cpp: -------------------------------------------------------------------------------- 1 | /* ========================================================================== */ 2 | /* Sensirion.cpp - Library for Sensirion SHT1x & SHT7x family temperature */ 3 | /* and humidity sensors */ 4 | /* Created by Markus Schatzl, November 28, 2008 */ 5 | /* Released into the public domain */ 6 | /* */ 7 | /* Revised (v1.1) by Carl Jackson, August 4, 2010 */ 8 | /* Rewritten (v2.0) by Carl Jackson, December 10, 2010 */ 9 | /* See README.txt file for details */ 10 | /* ========================================================================== */ 11 | 12 | 13 | /****************************************************************************** 14 | * Includes 15 | ******************************************************************************/ 16 | 17 | extern "C" { 18 | // AVR LibC Includes 19 | #include 20 | #include 21 | #include 22 | 23 | } 24 | 25 | #include "Sensirion.h" 26 | 27 | 28 | /****************************************************************************** 29 | * Definitions 30 | ******************************************************************************/ 31 | 32 | // Sensirion command definitions: adr command r/w 33 | const uint8_t MEAS_TEMP = 0x03; // 000 0001 1 34 | const uint8_t MEAS_HUMI = 0x05; // 000 0010 1 35 | const uint8_t STAT_REG_W = 0x06; // 000 0011 0 36 | const uint8_t STAT_REG_R = 0x07; // 000 0011 1 37 | const uint8_t SOFT_RESET = 0x1e; // 000 1111 0 38 | 39 | // Status register writable bits 40 | const uint8_t SR_MASK = 0x07; 41 | 42 | // getByte flags 43 | const bool noACK = false; 44 | const bool ACK = true; 45 | 46 | // Temperature & humidity equation constants 47 | // const float D1 = -40.1; // for deg C @ 5V 48 | const float D1 = -39.7; // for deg C @ 3.5V 49 | // const float D1 = -39.6; // for deg C @ 3V 50 | const float D2h = 0.01; // for deg C, 14-bit precision 51 | const float D2l = 0.04; // for deg C, 12-bit precision 52 | 53 | // const float C1 = -4.0000; // for V3 sensors 54 | // const float C2h = 0.0405; // for V3 sensors, 12-bit precision 55 | // const float C3h = -2.8000E-6; // for V3 sensors, 12-bit precision 56 | // const float C2l = 0.6480; // for V3 sensors, 8-bit precision 57 | // const float C3l = -7.2000E-4; // for V3 sensors, 8-bit precision 58 | const float C1 = -2.0468; // for V4 sensors 59 | const float C2h = 0.0367; // for V4 sensors, 12-bit precision 60 | const float C3h = -1.5955E-6; // for V4 sensors, 12-bit precision 61 | const float C2l = 0.5872; // for V4 sensors, 8-bit precision 62 | const float C3l = -4.0845E-4; // for V4 sensors, 8-bit precision 63 | 64 | const float T1 = 0.01; // for V3 and V4 sensors 65 | const float T2h = 0.00008; // for V3 and V4 sensors, 12-bit precision 66 | const float T2l = 0.00128; // for V3 and V4 sensors, 8-bit precision 67 | 68 | 69 | /****************************************************************************** 70 | * Constructors 71 | ******************************************************************************/ 72 | 73 | void Sensirion::config(uint8_t dataPin, uint8_t clockPin) { 74 | // Initialize private storage for library functions 75 | _pinData = dataPin; 76 | _pinClock = clockPin; 77 | _presult = NULL; // No pending measurement 78 | _stat_reg = 0x00; // Sensor status register default state 79 | 80 | // Initialize CLK signal direction 81 | // Note: All functions exit with CLK low and DAT in input mode 82 | pinMode(_pinClock, OUTPUT); 83 | 84 | // Return sensor to default state 85 | resetConnection(); // Reset communication link with sensor 86 | putByte(SOFT_RESET); // Send soft reset command 87 | } 88 | 89 | 90 | /****************************************************************************** 91 | * User functions 92 | ******************************************************************************/ 93 | 94 | // All-in-one (blocking): Returns temperature, humidity, & dewpoint 95 | uint8_t Sensirion::measure(float *temp, float *humi, float *dew) { 96 | uint16_t rawData; 97 | uint8_t error; 98 | if (error = measTemp(&rawData)) 99 | return error; 100 | *temp = calcTemp(rawData); 101 | if (error = measHumi(&rawData)) 102 | return error; 103 | *humi = calcHumi(rawData, *temp); 104 | *dew = calcDewpoint(*humi, *temp); 105 | return 0 ; 106 | } 107 | 108 | // Initiate measurement. If blocking, wait for result 109 | uint8_t Sensirion::meas(uint8_t cmd, uint16_t *result, bool block) { 110 | uint8_t error, i; 111 | #ifdef CRC_ENA 112 | _crc = bitrev(_stat_reg & SR_MASK); // Initialize CRC calculation 113 | #endif 114 | startTransmission(); 115 | if (cmd == TEMP) 116 | cmd = MEAS_TEMP; 117 | else 118 | cmd = MEAS_HUMI; 119 | if (error = putByte(cmd)) 120 | return error; 121 | #ifdef CRC_ENA 122 | calcCRC(cmd, &_crc); // Include command byte in CRC calculation 123 | #endif 124 | // If non-blocking, save pointer to result and return 125 | if (!block) { 126 | _presult = result; 127 | return 0; 128 | } 129 | // Otherwise, wait for measurement to complete with 720ms timeout 130 | i = 240; 131 | while (digitalRead(_pinData)) { 132 | i--; 133 | if (i == 0) 134 | return S_Err_TO; // Error: Timeout 135 | // delay(3); 136 | _delay_ms(3); 137 | 138 | } 139 | error = getResult(result); 140 | 141 | return error; 142 | } 143 | 144 | // Check if non-blocking measurement has completed 145 | // Non-zero return indicates complete (with or without error) 146 | uint8_t Sensirion::measRdy(void) { 147 | uint8_t error = 0; 148 | if (_presult == NULL) // Already done? 149 | return S_Meas_Rdy; 150 | if (digitalRead(_pinData) != 0) // Measurement ready yet? 151 | return 0; 152 | error = getResult(_presult); 153 | _presult = NULL; 154 | if (error) 155 | return error; // Only possible error is S_Err_CRC 156 | return S_Meas_Rdy; 157 | } 158 | 159 | // Get measurement result from sensor (plus CRC, if enabled) 160 | uint8_t Sensirion::getResult(uint16_t *result) { 161 | uint8_t val; 162 | #ifdef CRC_ENA 163 | val = getByte(ACK); 164 | calcCRC(val, &_crc); 165 | *result = val; 166 | val = getByte(ACK); 167 | calcCRC(val, &_crc); 168 | *result = (*result << 8) | val; 169 | val = getByte(noACK); 170 | val = bitrev(val); 171 | if (val != _crc) { 172 | *result = 0xFFFF; 173 | return S_Err_CRC; 174 | } 175 | #else 176 | *result = getByte(ACK); 177 | *result = (*result << 8) | getByte(noACK); 178 | #endif 179 | return 0; 180 | } 181 | 182 | // Write status register 183 | uint8_t Sensirion::writeSR(uint8_t value) { 184 | uint8_t error; 185 | value &= SR_MASK; // Mask off unwritable bits 186 | _stat_reg = value; // Save local copy 187 | startTransmission(); 188 | if (error = putByte(STAT_REG_W)) 189 | return error; 190 | return putByte(value); 191 | } 192 | 193 | // Read status register 194 | uint8_t Sensirion::readSR(uint8_t *result) { 195 | uint8_t val; 196 | uint8_t error = 0; 197 | #ifdef CRC_ENA 198 | _crc = bitrev(_stat_reg & SR_MASK); // Initialize CRC calculation 199 | #endif 200 | startTransmission(); 201 | if (error = putByte(STAT_REG_R)) { 202 | *result = 0xFF; 203 | return error; 204 | } 205 | #ifdef CRC_ENA 206 | calcCRC(STAT_REG_R, &_crc); // Include command byte in CRC calculation 207 | *result = getByte(ACK); 208 | calcCRC(*result, &_crc); 209 | val = getByte(noACK); 210 | val = bitrev(val); 211 | if (val != _crc) { 212 | *result = 0xFF; 213 | error = S_Err_CRC; 214 | } 215 | #else 216 | *result = getByte(noACK); 217 | #endif 218 | return error; 219 | } 220 | 221 | // Public reset function 222 | // Note: Soft reset returns sensor status register to default values 223 | uint8_t Sensirion::reset(void) { 224 | _stat_reg = 0x00; // Sensor status register default state 225 | resetConnection(); // Reset communication link with sensor 226 | return putByte(SOFT_RESET); // Send soft reset command & return status 227 | } 228 | 229 | 230 | /****************************************************************************** 231 | * Sensirion data communication 232 | ******************************************************************************/ 233 | 234 | // Write byte to sensor and check for acknowledge 235 | uint8_t Sensirion::putByte(uint8_t value) { 236 | uint8_t mask, i; 237 | uint8_t error = 0; 238 | pinMode(_pinData, OUTPUT); // Set data line to output mode 239 | mask = 0x80; // Bit mask to transmit MSB first 240 | for (i = 8; i > 0; i--) { 241 | digitalWrite(_pinData, value & mask); 242 | PULSE_SHORT; 243 | digitalWrite(_pinClock, HIGH); // Generate clock pulse 244 | PULSE_LONG; 245 | digitalWrite(_pinClock, LOW); 246 | PULSE_SHORT; 247 | mask >>= 1; // Shift mask for next data bit 248 | } 249 | pinMode(_pinData, INPUT); // Return data line to input mode 250 | #ifdef DATA_PU 251 | digitalWrite(_pinData, DATA_PU); // Restore internal pullup state 252 | #endif 253 | digitalWrite(_pinClock, HIGH); // Clock #9 for ACK 254 | PULSE_LONG; 255 | if (digitalRead(_pinData)) // Verify ACK ('0') received from sensor 256 | error = S_Err_NoACK; 257 | PULSE_SHORT; 258 | digitalWrite(_pinClock, LOW); // Finish with clock in low state 259 | return error; 260 | } 261 | 262 | // Read byte from sensor and send acknowledge if "ack" is true 263 | uint8_t Sensirion::getByte(bool ack) { 264 | uint8_t i; 265 | uint8_t result = 0; 266 | for (i = 8; i > 0; i--) { 267 | result <<= 1; // Shift received bits towards MSB 268 | digitalWrite(_pinClock, HIGH); // Generate clock pulse 269 | PULSE_SHORT; 270 | result |= digitalRead(_pinData); // Merge next bit into LSB position 271 | digitalWrite(_pinClock, LOW); 272 | PULSE_SHORT; 273 | } 274 | pinMode(_pinData, OUTPUT); 275 | digitalWrite(_pinData, !ack); // Assert ACK ('0') if ack == 1 276 | PULSE_SHORT; 277 | digitalWrite(_pinClock, HIGH); // Clock #9 for ACK / noACK 278 | PULSE_LONG; 279 | digitalWrite(_pinClock, LOW); // Finish with clock in low state 280 | PULSE_SHORT; 281 | pinMode(_pinData, INPUT); // Return data line to input mode 282 | #ifdef DATA_PU 283 | digitalWrite(_pinData, DATA_PU); // Restore internal pullup state 284 | #endif 285 | return result; 286 | } 287 | 288 | 289 | /****************************************************************************** 290 | * Sensirion signaling 291 | ******************************************************************************/ 292 | 293 | // Generate Sensirion-specific transmission start sequence 294 | // This is where Sensirion does not conform to the I2C standard and is 295 | // the main reason why the AVR TWI hardware support can not be used. 296 | // _____ ________ 297 | // DATA: |_______| 298 | // ___ ___ 299 | // SCK : ___| |___| |______ 300 | void Sensirion::startTransmission(void) { 301 | digitalWrite(_pinData, HIGH); // Set data register high before turning on 302 | pinMode(_pinData, OUTPUT); // output driver (avoid possible low pulse) 303 | PULSE_SHORT; 304 | digitalWrite(_pinClock, HIGH); 305 | PULSE_SHORT; 306 | digitalWrite(_pinData, LOW); 307 | PULSE_SHORT; 308 | digitalWrite(_pinClock, LOW); 309 | PULSE_LONG; 310 | digitalWrite(_pinClock, HIGH); 311 | PULSE_SHORT; 312 | digitalWrite(_pinData, HIGH); 313 | PULSE_SHORT; 314 | digitalWrite(_pinClock, LOW); 315 | PULSE_SHORT; 316 | // Unnecessary here since putByte always follows startTransmission 317 | // pinMode(_pinData, INPUT); 318 | } 319 | 320 | // Communication link reset 321 | // At least 9 SCK cycles with DATA=1, followed by transmission start sequence 322 | // ______________________________________________________ ________ 323 | // DATA: |_______| 324 | // _ _ _ _ _ _ _ _ _ ___ ___ 325 | // SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______| |___| |______ 326 | void Sensirion::resetConnection(void) { 327 | uint8_t i; 328 | digitalWrite(_pinData, HIGH); // Set data register high before turning on 329 | pinMode(_pinData, OUTPUT); // output driver (avoid possible low pulse) 330 | PULSE_LONG; 331 | for (i = 0; i < 9; i++) { 332 | digitalWrite(_pinClock, HIGH); 333 | PULSE_LONG; 334 | digitalWrite(_pinClock, LOW); 335 | PULSE_LONG; 336 | } 337 | startTransmission(); 338 | } 339 | 340 | 341 | /****************************************************************************** 342 | * Helper Functions 343 | ******************************************************************************/ 344 | 345 | // Calculates temperature in degrees C from raw sensor data 346 | float Sensirion::calcTemp(uint16_t rawData) { 347 | if (_stat_reg & LOW_RES) 348 | return D1 + D2l * (float) rawData; 349 | else 350 | return D1 + D2h * (float) rawData; 351 | } 352 | 353 | // Calculates relative humidity from raw sensor data 354 | // (with temperature compensation) 355 | float Sensirion::calcHumi(uint16_t rawData, float temp) { 356 | float humi; 357 | if (_stat_reg & LOW_RES) { 358 | humi = C1 + C2l * rawData + C3l * rawData * rawData; 359 | humi = (temp - 25.0) * (T1 + T2l * rawData) + humi; 360 | } else { 361 | humi = C1 + C2h * rawData + C3h * rawData * rawData; 362 | humi = (temp - 25.0) * (T1 + T2h * rawData) + humi; 363 | } 364 | if (humi > 100.0) humi = 100.0; 365 | if (humi < 0.1) humi = 0.1; 366 | return humi; 367 | } 368 | 369 | // Calculates dew point in degrees C 370 | float Sensirion::calcDewpoint(float humi, float temp) { 371 | float k; 372 | k = log(humi/100) + (17.62 * temp) / (243.12 + temp); 373 | return 243.12 * k / (17.62 - k); 374 | } 375 | 376 | #ifdef CRC_ENA 377 | // Calculate CRC for a single byte 378 | void Sensirion::calcCRC(uint8_t value, uint8_t *crc) { 379 | const uint8_t POLY = 0x31; // Polynomial: x**8 + x**5 + x**4 + 1 380 | uint8_t i; 381 | *crc ^= value; 382 | for (i = 8; i > 0; i--) { 383 | if (*crc & 0x80) 384 | *crc = (*crc << 1) ^ POLY; 385 | else 386 | *crc = (*crc << 1); 387 | } 388 | } 389 | 390 | // Bit-reverse a byte (for CRC calculations) 391 | uint8_t Sensirion::bitrev(uint8_t value) { 392 | uint8_t i; 393 | uint8_t result = 0; 394 | for (i = 8; i > 0; i--) { 395 | result = (result << 1) | (value & 0x01); 396 | value >>= 1; 397 | } 398 | return result; 399 | } 400 | #endif 401 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/Wire/utility/twi.c: -------------------------------------------------------------------------------- 1 | /* 2 | twi.c - TWI/I2C library for Wiring & Arduino 3 | Copyright (c) 2006 Nicholas Zambetti. All right reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | 19 | Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "Arduino.h" // for digitalWrite 29 | 30 | #ifndef cbi 31 | #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 32 | #endif 33 | 34 | #ifndef sbi 35 | #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 36 | #endif 37 | 38 | #include "pins_arduino.h" 39 | #include "twi.h" 40 | 41 | static volatile uint8_t twi_state; 42 | static volatile uint8_t twi_slarw; 43 | static volatile uint8_t twi_sendStop; // should the transaction end with a stop 44 | static volatile uint8_t twi_inRepStart; // in the middle of a repeated start 45 | 46 | static void (*twi_onSlaveTransmit)(void); 47 | static void (*twi_onSlaveReceive)(uint8_t*, int); 48 | 49 | static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH]; 50 | static volatile uint8_t twi_masterBufferIndex; 51 | static volatile uint8_t twi_masterBufferLength; 52 | 53 | static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; 54 | static volatile uint8_t twi_txBufferIndex; 55 | static volatile uint8_t twi_txBufferLength; 56 | 57 | static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; 58 | static volatile uint8_t twi_rxBufferIndex; 59 | 60 | static volatile uint8_t twi_error; 61 | 62 | /* 63 | * Function twi_init 64 | * Desc readys twi pins and sets twi bitrate 65 | * Input none 66 | * Output none 67 | */ 68 | void twi_init(void) 69 | { 70 | // initialize state 71 | twi_state = TWI_READY; 72 | twi_sendStop = true; // default value 73 | twi_inRepStart = false; 74 | 75 | // activate internal pullups for twi. 76 | digitalWrite(SDA, 1); 77 | digitalWrite(SCL, 1); 78 | 79 | // initialize twi prescaler and bit rate 80 | cbi(TWSR, TWPS0); 81 | cbi(TWSR, TWPS1); 82 | TWBR = ((F_CPU / TWI_FREQ) - 16) / 2; 83 | 84 | /* twi bit rate formula from atmega128 manual pg 204 85 | SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR)) 86 | note: TWBR should be 10 or higher for master mode 87 | It is 72 for a 16mhz Wiring board with 100kHz TWI */ 88 | 89 | // enable twi module, acks, and twi interrupt 90 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA); 91 | } 92 | 93 | /* 94 | * Function twi_slaveInit 95 | * Desc sets slave address and enables interrupt 96 | * Input none 97 | * Output none 98 | */ 99 | void twi_setAddress(uint8_t address) 100 | { 101 | // set twi slave address (skip over TWGCE bit) 102 | TWAR = address << 1; 103 | } 104 | 105 | /* 106 | * Function twi_readFrom 107 | * Desc attempts to become twi bus master and read a 108 | * series of bytes from a device on the bus 109 | * Input address: 7bit i2c device address 110 | * data: pointer to byte array 111 | * length: number of bytes to read into array 112 | * sendStop: Boolean indicating whether to send a stop at the end 113 | * Output number of bytes read 114 | */ 115 | uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop) 116 | { 117 | uint8_t i; 118 | 119 | // ensure data will fit into buffer 120 | if(TWI_BUFFER_LENGTH < length){ 121 | return 0; 122 | } 123 | 124 | // wait until twi is ready, become master receiver 125 | while(TWI_READY != twi_state){ 126 | continue; 127 | } 128 | twi_state = TWI_MRX; 129 | twi_sendStop = sendStop; 130 | // reset error state (0xFF.. no error occured) 131 | twi_error = 0xFF; 132 | 133 | // initialize buffer iteration vars 134 | twi_masterBufferIndex = 0; 135 | twi_masterBufferLength = length-1; // This is not intuitive, read on... 136 | // On receive, the previously configured ACK/NACK setting is transmitted in 137 | // response to the received byte before the interrupt is signalled. 138 | // Therefor we must actually set NACK when the _next_ to last byte is 139 | // received, causing that NACK to be sent in response to receiving the last 140 | // expected byte of data. 141 | 142 | // build sla+w, slave device address + w bit 143 | twi_slarw = TW_READ; 144 | twi_slarw |= address << 1; 145 | 146 | if (true == twi_inRepStart) { 147 | // if we're in the repeated start state, then we've already sent the start, 148 | // (@@@ we hope), and the TWI statemachine is just waiting for the address byte. 149 | // We need to remove ourselves from the repeated start state before we enable interrupts, 150 | // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning 151 | // up. Also, don't enable the START interrupt. There may be one pending from the 152 | // repeated start that we sent outselves, and that would really confuse things. 153 | twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR 154 | TWDR = twi_slarw; 155 | TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START 156 | } 157 | else 158 | // send start condition 159 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); 160 | 161 | // wait for read operation to complete 162 | while(TWI_MRX == twi_state){ 163 | continue; 164 | } 165 | 166 | if (twi_masterBufferIndex < length) 167 | length = twi_masterBufferIndex; 168 | 169 | // copy twi buffer to data 170 | for(i = 0; i < length; ++i){ 171 | data[i] = twi_masterBuffer[i]; 172 | } 173 | 174 | return length; 175 | } 176 | 177 | /* 178 | * Function twi_writeTo 179 | * Desc attempts to become twi bus master and write a 180 | * series of bytes to a device on the bus 181 | * Input address: 7bit i2c device address 182 | * data: pointer to byte array 183 | * length: number of bytes in array 184 | * wait: boolean indicating to wait for write or not 185 | * sendStop: boolean indicating whether or not to send a stop at the end 186 | * Output 0 .. success 187 | * 1 .. length to long for buffer 188 | * 2 .. address send, NACK received 189 | * 3 .. data send, NACK received 190 | * 4 .. other twi error (lost bus arbitration, bus error, ..) 191 | */ 192 | uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop) 193 | { 194 | uint8_t i; 195 | 196 | // ensure data will fit into buffer 197 | if(TWI_BUFFER_LENGTH < length){ 198 | return 1; 199 | } 200 | 201 | // wait until twi is ready, become master transmitter 202 | while(TWI_READY != twi_state){ 203 | continue; 204 | } 205 | twi_state = TWI_MTX; 206 | twi_sendStop = sendStop; 207 | // reset error state (0xFF.. no error occured) 208 | twi_error = 0xFF; 209 | 210 | // initialize buffer iteration vars 211 | twi_masterBufferIndex = 0; 212 | twi_masterBufferLength = length; 213 | 214 | // copy data to twi buffer 215 | for(i = 0; i < length; ++i){ 216 | twi_masterBuffer[i] = data[i]; 217 | } 218 | 219 | // build sla+w, slave device address + w bit 220 | twi_slarw = TW_WRITE; 221 | twi_slarw |= address << 1; 222 | 223 | // if we're in a repeated start, then we've already sent the START 224 | // in the ISR. Don't do it again. 225 | // 226 | if (true == twi_inRepStart) { 227 | // if we're in the repeated start state, then we've already sent the start, 228 | // (@@@ we hope), and the TWI statemachine is just waiting for the address byte. 229 | // We need to remove ourselves from the repeated start state before we enable interrupts, 230 | // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning 231 | // up. Also, don't enable the START interrupt. There may be one pending from the 232 | // repeated start that we sent outselves, and that would really confuse things. 233 | twi_inRepStart = false; // remember, we're dealing with an ASYNC ISR 234 | TWDR = twi_slarw; 235 | TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE); // enable INTs, but not START 236 | } 237 | else 238 | // send start condition 239 | TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA); // enable INTs 240 | 241 | // wait for write operation to complete 242 | while(wait && (TWI_MTX == twi_state)){ 243 | continue; 244 | } 245 | 246 | if (twi_error == 0xFF) 247 | return 0; // success 248 | else if (twi_error == TW_MT_SLA_NACK) 249 | return 2; // error: address send, nack received 250 | else if (twi_error == TW_MT_DATA_NACK) 251 | return 3; // error: data send, nack received 252 | else 253 | return 4; // other twi error 254 | } 255 | 256 | /* 257 | * Function twi_transmit 258 | * Desc fills slave tx buffer with data 259 | * must be called in slave tx event callback 260 | * Input data: pointer to byte array 261 | * length: number of bytes in array 262 | * Output 1 length too long for buffer 263 | * 2 not slave transmitter 264 | * 0 ok 265 | */ 266 | uint8_t twi_transmit(const uint8_t* data, uint8_t length) 267 | { 268 | uint8_t i; 269 | 270 | // ensure data will fit into buffer 271 | if(TWI_BUFFER_LENGTH < length){ 272 | return 1; 273 | } 274 | 275 | // ensure we are currently a slave transmitter 276 | if(TWI_STX != twi_state){ 277 | return 2; 278 | } 279 | 280 | // set length and copy data into tx buffer 281 | twi_txBufferLength = length; 282 | for(i = 0; i < length; ++i){ 283 | twi_txBuffer[i] = data[i]; 284 | } 285 | 286 | return 0; 287 | } 288 | 289 | /* 290 | * Function twi_attachSlaveRxEvent 291 | * Desc sets function called before a slave read operation 292 | * Input function: callback function to use 293 | * Output none 294 | */ 295 | void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) ) 296 | { 297 | twi_onSlaveReceive = function; 298 | } 299 | 300 | /* 301 | * Function twi_attachSlaveTxEvent 302 | * Desc sets function called before a slave write operation 303 | * Input function: callback function to use 304 | * Output none 305 | */ 306 | void twi_attachSlaveTxEvent( void (*function)(void) ) 307 | { 308 | twi_onSlaveTransmit = function; 309 | } 310 | 311 | /* 312 | * Function twi_reply 313 | * Desc sends byte or readys receive line 314 | * Input ack: byte indicating to ack or to nack 315 | * Output none 316 | */ 317 | void twi_reply(uint8_t ack) 318 | { 319 | // transmit master read ready signal, with or without ack 320 | if(ack){ 321 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); 322 | }else{ 323 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); 324 | } 325 | } 326 | 327 | /* 328 | * Function twi_stop 329 | * Desc relinquishes bus master status 330 | * Input none 331 | * Output none 332 | */ 333 | void twi_stop(void) 334 | { 335 | // send stop condition 336 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); 337 | 338 | // wait for stop condition to be exectued on bus 339 | // TWINT is not set after a stop condition! 340 | while(TWCR & _BV(TWSTO)){ 341 | continue; 342 | } 343 | 344 | // update twi state 345 | twi_state = TWI_READY; 346 | } 347 | 348 | /* 349 | * Function twi_releaseBus 350 | * Desc releases bus control 351 | * Input none 352 | * Output none 353 | */ 354 | void twi_releaseBus(void) 355 | { 356 | // release bus 357 | TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); 358 | 359 | // update twi state 360 | twi_state = TWI_READY; 361 | } 362 | 363 | SIGNAL(TWI_vect) 364 | { 365 | switch(TW_STATUS){ 366 | // All Master 367 | case TW_START: // sent start condition 368 | case TW_REP_START: // sent repeated start condition 369 | // copy device address and r/w bit to output register and ack 370 | TWDR = twi_slarw; 371 | twi_reply(1); 372 | break; 373 | 374 | // Master Transmitter 375 | case TW_MT_SLA_ACK: // slave receiver acked address 376 | case TW_MT_DATA_ACK: // slave receiver acked data 377 | // if there is data to send, send it, otherwise stop 378 | if(twi_masterBufferIndex < twi_masterBufferLength){ 379 | // copy data to output register and ack 380 | TWDR = twi_masterBuffer[twi_masterBufferIndex++]; 381 | twi_reply(1); 382 | }else{ 383 | if (twi_sendStop) 384 | twi_stop(); 385 | else { 386 | twi_inRepStart = true; // we're gonna send the START 387 | // don't enable the interrupt. We'll generate the start, but we 388 | // avoid handling the interrupt until we're in the next transaction, 389 | // at the point where we would normally issue the start. 390 | TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; 391 | twi_state = TWI_READY; 392 | } 393 | } 394 | break; 395 | case TW_MT_SLA_NACK: // address sent, nack received 396 | twi_error = TW_MT_SLA_NACK; 397 | twi_stop(); 398 | break; 399 | case TW_MT_DATA_NACK: // data sent, nack received 400 | twi_error = TW_MT_DATA_NACK; 401 | twi_stop(); 402 | break; 403 | case TW_MT_ARB_LOST: // lost bus arbitration 404 | twi_error = TW_MT_ARB_LOST; 405 | twi_releaseBus(); 406 | break; 407 | 408 | // Master Receiver 409 | case TW_MR_DATA_ACK: // data received, ack sent 410 | // put byte into buffer 411 | twi_masterBuffer[twi_masterBufferIndex++] = TWDR; 412 | case TW_MR_SLA_ACK: // address sent, ack received 413 | // ack if more bytes are expected, otherwise nack 414 | if(twi_masterBufferIndex < twi_masterBufferLength){ 415 | twi_reply(1); 416 | }else{ 417 | twi_reply(0); 418 | } 419 | break; 420 | case TW_MR_DATA_NACK: // data received, nack sent 421 | // put final byte into buffer 422 | twi_masterBuffer[twi_masterBufferIndex++] = TWDR; 423 | if (twi_sendStop) 424 | twi_stop(); 425 | else { 426 | twi_inRepStart = true; // we're gonna send the START 427 | // don't enable the interrupt. We'll generate the start, but we 428 | // avoid handling the interrupt until we're in the next transaction, 429 | // at the point where we would normally issue the start. 430 | TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; 431 | twi_state = TWI_READY; 432 | } 433 | break; 434 | case TW_MR_SLA_NACK: // address sent, nack received 435 | twi_stop(); 436 | break; 437 | // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case 438 | 439 | // Slave Receiver 440 | case TW_SR_SLA_ACK: // addressed, returned ack 441 | case TW_SR_GCALL_ACK: // addressed generally, returned ack 442 | case TW_SR_ARB_LOST_SLA_ACK: // lost arbitration, returned ack 443 | case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack 444 | // enter slave receiver mode 445 | twi_state = TWI_SRX; 446 | // indicate that rx buffer can be overwritten and ack 447 | twi_rxBufferIndex = 0; 448 | twi_reply(1); 449 | break; 450 | case TW_SR_DATA_ACK: // data received, returned ack 451 | case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack 452 | // if there is still room in the rx buffer 453 | if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ 454 | // put byte in buffer and ack 455 | twi_rxBuffer[twi_rxBufferIndex++] = TWDR; 456 | twi_reply(1); 457 | }else{ 458 | // otherwise nack 459 | twi_reply(0); 460 | } 461 | break; 462 | case TW_SR_STOP: // stop or repeated start condition received 463 | // put a null char after data if there's room 464 | if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ 465 | twi_rxBuffer[twi_rxBufferIndex] = '\0'; 466 | } 467 | // sends ack and stops interface for clock stretching 468 | twi_stop(); 469 | // callback to user defined callback 470 | twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); 471 | // since we submit rx buffer to "wire" library, we can reset it 472 | twi_rxBufferIndex = 0; 473 | // ack future responses and leave slave receiver state 474 | twi_releaseBus(); 475 | break; 476 | case TW_SR_DATA_NACK: // data received, returned nack 477 | case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack 478 | // nack back at master 479 | twi_reply(0); 480 | break; 481 | 482 | // Slave Transmitter 483 | case TW_ST_SLA_ACK: // addressed, returned ack 484 | case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack 485 | // enter slave transmitter mode 486 | twi_state = TWI_STX; 487 | // ready the tx buffer index for iteration 488 | twi_txBufferIndex = 0; 489 | // set tx buffer length to be zero, to verify if user changes it 490 | twi_txBufferLength = 0; 491 | // request for txBuffer to be filled and length to be set 492 | // note: user must call twi_transmit(bytes, length) to do this 493 | twi_onSlaveTransmit(); 494 | // if they didn't change buffer & length, initialize it 495 | if(0 == twi_txBufferLength){ 496 | twi_txBufferLength = 1; 497 | twi_txBuffer[0] = 0x00; 498 | } 499 | // transmit first byte from buffer, fall 500 | case TW_ST_DATA_ACK: // byte sent, ack returned 501 | // copy data to output register 502 | TWDR = twi_txBuffer[twi_txBufferIndex++]; 503 | // if there is more to send, ack, otherwise nack 504 | if(twi_txBufferIndex < twi_txBufferLength){ 505 | twi_reply(1); 506 | }else{ 507 | twi_reply(0); 508 | } 509 | break; 510 | case TW_ST_DATA_NACK: // received nack, we are done 511 | case TW_ST_LAST_DATA: // received ack, but we are done already! 512 | // ack future responses 513 | twi_reply(1); 514 | // leave slave receiver state 515 | twi_state = TWI_READY; 516 | break; 517 | 518 | // All 519 | case TW_NO_INFO: // no state information 520 | break; 521 | case TW_BUS_ERROR: // bus error, illegal stop/start 522 | twi_error = TW_BUS_ERROR; 523 | twi_stop(); 524 | break; 525 | } 526 | } 527 | 528 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/TSL2561/TSL2561.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | TSL2561 illumination sensor library for Arduino 3 | Mike Grusin, SparkFun Electronics 4 | 5 | This library provides functions to access the TAOS TSL2561 6 | Illumination Sensor. 7 | 8 | Our example code uses the "beerware" license. You can do anything 9 | you like with this code. No really, anything. If you find it useful, 10 | buy me a beer someday. 11 | 12 | version 1.0 2013/09/20 MDG initial version 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | /** 20 | * The constructor 21 | */ 22 | TSL2561::TSL2561(void) { 23 | } 24 | 25 | /** 26 | * Initialize TSL2561 library with default address (0x39). 27 | */ 28 | void TSL2561::begin(void) { 29 | begin(TSL2561_ADDR); 30 | } 31 | 32 | /** 33 | * Initialize TSL2561 library to arbitrary address or: 34 | * TSL2561_ADDR_0 (0x29 address pin connected to gnd) 35 | * TSL2561_ADDR (0x39 address pin not connected) 36 | * TSL2561_ADDR_1 (0x49 address pin conneted to vcc) 37 | */ 38 | void TSL2561::begin(char i2c_address) { 39 | _i2c_address = i2c_address; 40 | Wire.begin(); 41 | } 42 | 43 | /** 44 | * Turn on TSL2561, begin integrations 45 | * Returns true (1) if successful, false (0) if there was an I2C error 46 | * (Also see getError() below) 47 | */ 48 | boolean TSL2561::setPowerUp(void) { 49 | // Write 0x03 to command byte (power on) 50 | return(writeByte(TSL2561_REG_CONTROL, 0x03)); 51 | } 52 | 53 | /** 54 | * Turn off TSL2561 55 | * Returns true (1) if successful, false (0) if there was an I2C error 56 | * (Also see getError() below) 57 | */ 58 | boolean TSL2561::setPowerDown(void) { 59 | // Clear command byte (power off) 60 | return(writeByte(TSL2561_REG_CONTROL, 0x00)); 61 | } 62 | 63 | /** 64 | * If gain = false (0), device is set to low gain (1X) 65 | * If gain = high (1), device is set to high gain (16X) 66 | * If time = 0, integration will be 13.7ms 67 | * If time = 1, integration will be 101ms 68 | * If time = 2, integration will be 402ms 69 | * If time = 3, use manual start / stop 70 | * Returns true (1) if successful, false (0) if there was an I2C error 71 | * (Also see getError() below) 72 | */ 73 | boolean TSL2561::setTiming(boolean gain, unsigned char timeConst) { 74 | unsigned char timing; 75 | 76 | _gain = gain; 77 | 78 | if (timeConst == 0) { 79 | _integrationTime = 14; 80 | 81 | } else if (timeConst == 1) { 82 | _integrationTime = 101; 83 | 84 | } else if (timeConst == 2) { 85 | _integrationTime = 402; 86 | } else { 87 | _integrationTime = 0; 88 | } 89 | 90 | // Get timing byte 91 | if (readByte(TSL2561_REG_TIMING,timing)) { 92 | // Set gain (0 or 1) 93 | if (gain) 94 | timing |= 0x10; 95 | else 96 | timing &= ~0x10; 97 | 98 | // Set integration timeConst (0 to 3) 99 | timing &= ~0x03; 100 | timing |= (timeConst & 0x03); 101 | 102 | // Write modified timing byte back to device 103 | if (writeByte(TSL2561_REG_TIMING, timing)) { 104 | return(true); 105 | } 106 | } 107 | 108 | return(false); 109 | } 110 | 111 | boolean TSL2561::setTimingManual(unsigned int ms) { 112 | // if (writeByte(TSL2561_REG_TIMING, 0x81)) { 113 | 114 | Wire.beginTransmission(_i2c_address); 115 | Wire.write(0x81); 116 | Wire.write(0x03); 117 | Wire.endTransmission(); 118 | 119 | Wire.beginTransmission(_i2c_address); 120 | Wire.write(0x81); 121 | Wire.write(0x0B); 122 | Wire.endTransmission(); 123 | 124 | // Begin manual integration 125 | // writeByte(TSL2561_REG_TIMING, 0x0B); 126 | noInterrupts(); // disable all interrupts for accurate delay loop 127 | delayloop16( ((ms * 1930) - 830) ); // delay loop, wait ms AVR@8 mHz 128 | interrupts(); // enable interrupts again 129 | 130 | // Stop manual integration 131 | // writeByte(TSL2561_REG_TIMING, 0x03); 132 | Wire.beginTransmission(_i2c_address); 133 | Wire.write(0x81); 134 | Wire.write(0x03); 135 | Wire.endTransmission(); 136 | 137 | setIntergrationTime(ms); 138 | return(true); 139 | // } 140 | 141 | // return(false); 142 | 143 | } 144 | 145 | /** 146 | * Starts a manual integration period 147 | * After running this command, you must manually stop integration with manualStop() 148 | * Internally sets integration time to 3 for manual integration (gain is unchanged) 149 | * Returns true (1) if successful, false (0) if there was an I2C error 150 | * (Also see getError() below) 151 | */ 152 | boolean TSL2561::manualStart(void) { 153 | unsigned char timing; 154 | 155 | // Get timing byte 156 | if (readByte(TSL2561_REG_TIMING,timing)) { 157 | // Set integration time to 3 (manual integration) 158 | timing |= INTEGATION_TIME_MANUAL; 159 | 160 | if (writeByte(TSL2561_REG_TIMING, timing)) { 161 | // Begin manual integration 162 | timing |= 0x08; 163 | 164 | // Write modified timing byte back to device 165 | if (writeByte(TSL2561_REG_TIMING, timing)) { 166 | return(true); 167 | } 168 | } 169 | } 170 | 171 | return(false); 172 | } 173 | 174 | /** 175 | * Stops a manual integration period 176 | * Returns true (1) if successful, false (0) if there was an I2C error 177 | * (Also see getError() below) 178 | */ 179 | boolean TSL2561::manualStop(void) { 180 | unsigned char timing; 181 | 182 | // Get timing byte 183 | if (readByte(TSL2561_REG_TIMING,timing)) { 184 | // Stop manual integration 185 | timing &= ~0x08; 186 | 187 | // Write modified timing byte back to device 188 | if (writeByte(TSL2561_REG_TIMING, timing)) { 189 | return(true); 190 | } 191 | } 192 | 193 | return(false); 194 | } 195 | 196 | /** 197 | * Retrieve raw integration results 198 | * data0 and data1 will be set to integration results 199 | * Returns true (1) if successful, false (0) if there was an I2C error 200 | * (Also see getError() below) 201 | */ 202 | boolean TSL2561::getData(unsigned int &data0, unsigned int &data1) { 203 | // Get data0 and data1 out of result registers 204 | if (readUInt(TSL2561_REG_DATA_0,data0) && readUInt(TSL2561_REG_DATA_1,data1)) { 205 | return(true); 206 | } 207 | 208 | return(false); 209 | } 210 | 211 | void TSL2561::setIntergrationTime(uint16_t integrationTime) { 212 | _integrationTime = integrationTime; 213 | } 214 | 215 | /** 216 | * Convert raw data to lux 217 | * CH0, CH1: results from getData() 218 | * lux will be set to resulting lux calculation 219 | * returns true (1) if calculation was successful 220 | * returns false (0) and lux = 0.0 if the sensor was satturated 221 | */ 222 | boolean TSL2561::getLux(unsigned int CH0, unsigned int CH1, double &lux) { 223 | uint16_t satturationValue = 5047; 224 | 225 | if (_integrationTime > 178) { 226 | satturationValue = 0xFFFF; // 65535 227 | } else if (_integrationTime > 101) { 228 | satturationValue = 37177; 229 | } 230 | 231 | // Determine if either sensor saturated, calculation will not be accurate, break here 232 | if ((CH0 == satturationValue) || (CH1 == satturationValue)) { 233 | lux = 0.0; 234 | return(false); 235 | } else { 236 | lux = CalculateLux(CH0, CH1); 237 | } 238 | 239 | return true; 240 | } 241 | 242 | /** 243 | * Sets up interrupt operations 244 | * If control = 0, interrupt output disabled 245 | * If control = 1, use level interrupt, see setInterruptThreshold() 246 | * If persist = 0, every integration cycle generates an interrupt 247 | * If persist = 1, any value outside of threshold generates an interrupt 248 | * If persist = 2 to 15, value must be outside of threshold for 2 to 15 integration cycles 249 | * Returns true (1) if successful, false (0) if there was an I2C error 250 | * (Also see getError() below) 251 | */ 252 | boolean TSL2561::setInterruptControl(unsigned char control, unsigned char persist) { 253 | // Place control and persist bits into proper location in interrupt control register 254 | if (writeByte(TSL2561_REG_INTCTL, ((control & 0B00000011) << 4) | (persist & 0B00001111))) { 255 | return(true); 256 | } 257 | 258 | return(false); 259 | } 260 | 261 | /** 262 | * Set interrupt thresholds (channel 0 only) 263 | * low, high: 16-bit threshold values 264 | * Returns true (1) if successful, false (0) if there was an I2C error 265 | * (Also see getError() below) 266 | */ 267 | boolean TSL2561::setInterruptThreshold(uint16_t low, uint16_t high) { 268 | if (writeUInt(TSL2561_REG_THRESH_L, low) && writeUInt(TSL2561_REG_THRESH_H, high) ) { 269 | return(true); 270 | } 271 | 272 | return(false); 273 | } 274 | 275 | /* 276 | * Clears an active interrupt 277 | * Returns true (1) if successful, false (0) if there was an I2C error 278 | * (Also see getError() below) 279 | */ 280 | boolean TSL2561::clearInterrupt(void) { 281 | // Set up command byte for interrupt clear 282 | Wire.beginTransmission(_i2c_address); 283 | Wire.write(TSL2561_CMD_CLEAR); 284 | 285 | _error = Wire.endTransmission(); 286 | if (_error == 0) { 287 | return(true); 288 | } 289 | 290 | return(false); 291 | } 292 | 293 | /* 294 | * Retrieves part and revision code from TSL2561 295 | * Sets ID to part ID (see datasheet) 296 | * Returns true (1) if successful, false (0) if there was an I2C error 297 | * (Also see getError() below) 298 | */ 299 | boolean TSL2561::getID(unsigned char &ID) { 300 | // Get ID byte from ID register 301 | if (readByte(TSL2561_REG_ID,ID)) { 302 | return(true); 303 | } 304 | 305 | return(false); 306 | } 307 | 308 | /** 309 | * If any library command fails, you can retrieve an extended 310 | * error code using this command. Errors are from the wire library: 311 | * 0 = Success 312 | * 1 = Data too long to fit in transmit buffer 313 | * 2 = Received NACK on transmit of address 314 | * 3 = Received NACK on transmit of data 315 | * 4 = Other error 316 | */ 317 | byte TSL2561::getError(void) { 318 | return(_error); 319 | } 320 | 321 | // Private functions: 322 | 323 | /** 324 | * Reads a byte from a TSL2561 address 325 | * Address: TSL2561 address (0 to 15) 326 | * Value will be set to stored byte 327 | * Returns true (1) if successful, false (0) if there was an I2C error 328 | * (Also see getError() above) 329 | */ 330 | boolean TSL2561::readByte(unsigned char address, unsigned char &value) { 331 | // Set up command byte for read 332 | Wire.beginTransmission(_i2c_address); 333 | Wire.write((address & 0x0F) | TSL2561_CMD); 334 | _error = Wire.endTransmission(); 335 | 336 | // Read requested byte 337 | if (_error == 0) { 338 | Wire.requestFrom(_i2c_address, 1); 339 | if (Wire.available() == 1) { 340 | value = Wire.read(); 341 | return(true); 342 | } 343 | } 344 | 345 | return(false); 346 | } 347 | 348 | /** 349 | * Write a byte to a TSL2561 address 350 | * Address: TSL2561 address (0 to 15) 351 | * Value: byte to write to address 352 | * Returns true (1) if successful, false (0) if there was an I2C error 353 | * (Also see getError() above) 354 | */ 355 | boolean TSL2561::writeByte(unsigned char address, unsigned char value) { 356 | // Set up command byte for write 357 | 358 | Wire.beginTransmission(_i2c_address); 359 | Wire.write((address & 0x0F) | TSL2561_CMD); 360 | // Write byte 361 | Wire.write(value); 362 | 363 | _error = Wire.endTransmission(); 364 | if (_error == 0) { 365 | return(true); 366 | } 367 | 368 | return(false); 369 | } 370 | 371 | /** 372 | * Reads an unsigned integer (16 bits) from a TSL2561 address (low byte first) 373 | * Address: TSL2561 address (0 to 15), low byte first 374 | * Value will be set to stored unsigned integer 375 | * Returns true (1) if successful, false (0) if there was an I2C error 376 | * Also see getError() above) 377 | */ 378 | boolean TSL2561::readUInt(unsigned char address, unsigned int &value) { 379 | char high, low; 380 | 381 | // Set up command byte for read 382 | Wire.beginTransmission(_i2c_address); 383 | Wire.write((address & 0x0F) | TSL2561_CMD); 384 | _error = Wire.endTransmission(); 385 | 386 | // Read two bytes (low and high) 387 | if (_error == 0) { 388 | Wire.requestFrom(_i2c_address,2); 389 | if (Wire.available() == 2) { 390 | low = Wire.read(); 391 | high = Wire.read(); 392 | // Combine bytes into unsigned int 393 | value = word(high,low); 394 | return(true); 395 | } 396 | } 397 | 398 | return(false); 399 | } 400 | 401 | /** 402 | * Write an unsigned integer (16 bits) to a TSL2561 address (low byte first) 403 | * Address: TSL2561 address (0 to 15), low byte first 404 | * Value: unsigned int to write to address 405 | * Returns true (1) if successful, false (0) if there was an I2C error 406 | * (Also see getError() above) 407 | */ 408 | boolean TSL2561::writeUInt(unsigned char address, unsigned int value) { 409 | // Split int into lower and upper bytes, write each byte 410 | if (writeByte(address, lowByte(value)) && writeByte(address + 1, highByte(value))) { 411 | return(true); 412 | } 413 | 414 | return(false); 415 | } 416 | 417 | /** 418 | * 419 | */ 420 | void __attribute__((always_inline)) TSL2561::delayloop16 (unsigned int count) { 421 | /* Die Schleife dauert 4 * count + 3 Ticks */ 422 | asm volatile ( 423 | "1:" "\n\t" 424 | "sbiw %0,1" "\n\t" 425 | "brcc 1b" 426 | : "+w" (count) 427 | ); 428 | } 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | //**************************************************************************** 452 | // 453 | // Copyright  2004−2005 TAOS, Inc. 454 | // 455 | // THIS CODE AND INFORMATION IS PROVIDED ”AS IS” WITHOUT WARRANTY OF ANY 456 | // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 457 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR 458 | // PURPOSE. 459 | // 460 | // Module Name: 461 | // lux.cpp 462 | // 463 | //**************************************************************************** 464 | #define LUX_SCALE 14 // scale by 2^14 465 | #define RATIO_SCALE 9 // scale ratio by 2^9 466 | 467 | //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 468 | // Integration time scaling factors 469 | //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 470 | #define CH_SCALE 10 // scale channel values by 2^10 471 | #define CHSCALE_TINT0 0x7517 // 322/11 * 2^CH_SCALE 472 | #define CHSCALE_TINT1 0x0fe7 // 322/81 * 2^CH_SCALE 473 | //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 474 | // T Package coefficients 475 | //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 476 | #define K1T 0x0040 // 0.125 * 2^RATIO_SCALE 477 | #define B1T 0x01f2 // 0.0304 * 2^LUX_SCALE 478 | #define M1T 0x01be // 0.0272 * 2^LUX_SCALE 479 | #define K2T 0x0080 // 0.250 * 2^RATIO_SCALETSL2560, TSL2561 480 | #define B2T 0x0214 // 0.0325 * 2^LUX_SCALE 481 | #define M2T 0x02d1 // 0.0440 * 2^LUX_SCALE 482 | #define K3T 0x00c0 // 0.375 * 2^RATIO_SCALE 483 | #define B3T 0x023f // 0.0351 * 2^LUX_SCALE 484 | #define M3T 0x037b // 0.0544 * 2^LUX_SCALE 485 | #define K4T 0x0100 // 0.50 * 2^RATIO_SCALE 486 | #define B4T 0x0270 // 0.0381 * 2^LUX_SCALE 487 | #define M4T 0x03fe // 0.0624 * 2^LUX_SCALE 488 | #define K5T 0x0138 // 0.61 * 2^RATIO_SCALE 489 | #define B5T 0x016f // 0.0224 * 2^LUX_SCALE 490 | #define M5T 0x01fc // 0.0310 * 2^LUX_SCALE 491 | #define K6T 0x019a // 0.80 * 2^RATIO_SCALE 492 | #define B6T 0x00d2 // 0.0128 * 2^LUX_SCALE 493 | #define M6T 0x00fb // 0.0153 * 2^LUX_SCALE 494 | #define K7T 0x029a // 1.3 * 2^RATIO_SCALE 495 | #define B7T 0x0018 // 0.00146 * 2^LUX_SCALE 496 | #define M7T 0x0012 // 0.00112 * 2^LUX_SCALE 497 | #define K8T 0x029a // 1.3 * 2^RATIO_SCALE 498 | #define B8T 0x0000 // 0.000 * 2^LUX_SCALE 499 | #define M8T 0x0000 // 0.000 * 2^LUX_SCALE 500 | 501 | 502 | ////////////////////////////////////////////////////////////////////////////// 503 | // Routine: unsigned int CalculateLux(unsigned int ch0, unsigned int ch0) 504 | // 505 | // Description: Calculate the approximate illuminance (lux) given the raw 506 | // channel values of the TSL2560. The equation if implemented 507 | // as a piece−wise linear approximation. 508 | // 509 | // Arguments: unsigned int iGain − gain, where 0:1X, 1:16X 510 | // unsigned int tInt − integration time, where 0:13.7mS, 1:100mS, 2:402mS, 511 | // 3:Manual 512 | // unsigned int ch0 − raw channel value from channel 0 of TSL2560 513 | // unsigned int ch1 − raw channel value from channel 1 of TSL2560 514 | // 515 | // Return: unsigned int − the approximate illuminance (lux) 516 | // 517 | ////////////////////////////////////////////////////////////////////////////// 518 | double TSL2561::CalculateLux(unsigned int ch0, unsigned int ch1) { 519 | //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 520 | // first, scale the channel values depending on the gain and integration time 521 | // scale if integration time is NOT 402 msec 522 | unsigned long chScale, channel1, channel0; 523 | 524 | if (_integrationTime == 14) { // 13.7 msec 525 | chScale = CHSCALE_TINT0; 526 | 527 | } else if (_integrationTime == 101) { 528 | chScale = CHSCALE_TINT1; 529 | 530 | } else { // 402, assume no scaling 531 | chScale = (1 << CH_SCALE); 532 | } 533 | 534 | // scale if gain is NOT 16X 535 | if (!_gain) { 536 | chScale = chScale << 4; // scale 1X to 16X 537 | } 538 | 539 | // scale the channel values 540 | channel0 = (ch0 * chScale) >> CH_SCALE; 541 | channel1 = (ch1 * chScale) >> CH_SCALE; 542 | 543 | // find the ratio of the channel values (Channel1/Channel0) protect against divide by zero 544 | unsigned long ratio1 = 0; 545 | if (channel0 != 0) { 546 | ratio1 = (channel1 << (RATIO_SCALE+1)) / channel0; 547 | } 548 | 549 | // round the ratio value 550 | unsigned long ratio = (ratio1 + 1) >> 1; 551 | 552 | // is ratio <= eachBreak ? 553 | unsigned int b, m; 554 | // T package 555 | if ((ratio >= 0) && (ratio <= K1T)) { 556 | b=B1T; m=M1T; 557 | } else if (ratio <= K2T) { 558 | b=B2T; m=M2T; 559 | } else if (ratio <= K3T) { 560 | b=B3T; m=M3T; 561 | } else if (ratio <= K4T) { 562 | b=B4T; m=M4T; 563 | } else if (ratio <= K5T) { 564 | b=B5T; m=M5T; 565 | } else if (ratio <= K6T) { 566 | b=B6T; m=M6T; 567 | } else if (ratio <= K7T) { 568 | b=B7T; m=M7T; 569 | } else if (ratio > K8T) { 570 | b=B8T; m=M8T; 571 | } 572 | 573 | double temp = (channel0 * b) - (channel1 * m); 574 | temp = (temp < 0) ? 0 : temp; 575 | 576 | return(temp / 16384); 577 | } 578 | 579 | double TSL2561::readBrightness(unsigned int &data0, unsigned int &data1) { 580 | double lux = 0; 581 | 582 | begin(TSL2561_ADDR_0); 583 | setPowerUp(); 584 | 585 | // first measurement with low integration time and low resolution 586 | setTiming(false, INTEGATION_TIME_14); 587 | _delay_ms(50); 588 | getData(data0, data1); 589 | 590 | if ((data0 < 1000) && (data1 < 1000)) { 591 | boolean gain = ((data0 < 100) && (data1 < 100)) ? true : false; 592 | setTiming(gain, INTEGATION_TIME_402); 593 | _delay_ms(450); 594 | getData(data0, data1); 595 | 596 | } else if ((data0) < 2000 && (data1 < 2000)) { 597 | setTiming(false, INTEGATION_TIME_101); 598 | _delay_ms(150); 599 | getData(data0, data1); 600 | } 601 | 602 | boolean luxValid = getLux(data0, data1, lux); 603 | 604 | lux = (luxValid) ? lux : 65537; 605 | 606 | setPowerDown(); 607 | 608 | return lux; 609 | } 610 | 611 | -------------------------------------------------------------------------------- /Firmware-Src/Libraries/BMP085/README.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | README.txt at master from adafruit/BMP085-Library - GitHub 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 67 | 68 | 69 | 70 |
71 |
72 |
73 | 74 | 75 |
76 |

77 | adafruit / 78 | BMP085-Library 79 |

80 | 81 | 82 | 83 | 84 | 106 | 107 |
108 | 109 | 110 | 111 | 122 | 123 | 124 | 154 | 155 | 166 | 167 | 168 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 |
232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 |

Latest commit to the master branch

240 | 241 |
242 |

243 | Arduino 1.0 compatible 244 | 245 |

246 |
247 | commit 04a39d95d4 248 | 249 |
250 | 251 | PaintYourDragon 252 | authored 253 | 254 |
255 |
256 |
257 | 258 | 259 |
260 | 261 | 292 | 293 |
294 |
295 | 298 | 299 |
300 |
301 |
302 |
303 | Txt 304 | 100644 305 | 7 lines (4 sloc) 306 | 0.482 kb 307 |
308 | 313 |
314 |
315 | 316 | 317 | 327 | 330 | 331 |
318 |
1
319 | 2
320 | 3
321 | 4
322 | 5
323 | 6
324 | 7
325 | 
326 |
328 |
This is an Arduino library for the BMP085 barometric pressure/temperature/altitude sensors.

Pick one up at http://www.adafruit.com/products/391

To download. click the DOWNLOADS button in the top right corner, rename the uncompressed folder BMP085. Check that the BMP085 folder contains BMP085.cpp and BMP085.h

Place the BMP085 library folder your <arduinosketchfolder>/libraries/ folder. You may need to create the libraries subfolder if its your first library. Restart the IDE.
329 |
332 |
333 | 334 |
335 |
336 |
337 |
338 | 339 |
340 | 341 | 344 | 345 |
346 |
347 | 348 | 349 | 420 | 421 | 422 | 423 | 640 | 641 |
642 |

Markdown Cheat Sheet

643 | 644 |
645 | 646 |
647 |
648 |

Format Text

649 |

Headers

650 |
651 | # This is an <h1> tag
652 | ## This is an <h2> tag
653 | ###### This is an <h6> tag
654 |

Text styles

655 |
656 | *This text will be italic*
657 | _This will also be italic_
658 | **This text will be bold**
659 | __This will also be bold__
660 | 
661 | *You **can** combine them*
662 | 
663 |
664 |
665 |

Lists

666 |

Unordered

667 |
668 | * Item 1
669 | * Item 2
670 |   * Item 2a
671 |   * Item 2b
672 |

Ordered

673 |
674 | 1. Item 1
675 | 2. Item 2
676 | 3. Item 3
677 |    * Item 3a
678 |    * Item 3b
679 |
680 |
681 |

Miscellaneous

682 |

Images

683 |
684 | ![GitHub Logo](/images/logo.png)
685 | Format: ![Alt Text](url)
686 | 
687 |

Links

688 |
689 | http://github.com - automatic!
690 | [GitHub](http://github.com)
691 |

Blockquotes

692 |
693 | As Kanye West said:
694 | 
695 | > We're living the future so
696 | > the present is our past.
697 | 
698 |
699 |
700 |
701 | 702 |

Code Examples in Markdown

703 |
704 |

Syntax highlighting with GFM

705 |
706 | ```javascript
707 | function fancyAlert(arg) {
708 |   if(arg) {
709 |     $.facebox({div:'#foo'})
710 |   }
711 | }
712 | ```
713 |
714 |
715 |

Or, indent your code 4 spaces

716 |
717 | Here is a Python code example
718 | without syntax highlighting:
719 | 
720 |     def foo:
721 |       if not bar:
722 |         return true
723 |
724 |
725 |

Inline code for comments

726 |
727 | I think you should use an
728 | `<addr>` element here instead.
729 |
730 |
731 | 732 |
733 | 734 | 735 | 736 |
737 | 738 |
739 |

Something went wrong with that request. Please try again. Dismiss

740 |
741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | -------------------------------------------------------------------------------- /Schematic/SHT10-Adapter.brd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | <b>SHT10/11/15: digital humidity & temperature sensors</b><br> 129 | <ul> 130 | <li>Relative humidity and temperature sensors 131 | <li>Dew point 132 | <li>Fully calibrated, digital output 133 | <li>Excellent long-term stability 134 | <li>No external components required 135 | <li>Ultra low power consumption 136 | <li>Surface mountable 137 | <li>Small size 138 | <li>Automatic power down 139 | </ul> 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | >NAME 166 | >VALUE 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | <b>CAPACITOR</b><p> 175 | Pad definition corrected 2006.05.15, librarian@cadsoft.de 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | >NAME 185 | >VALUE 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | <b>Pin Headers</b><p> 194 | Naming:<p> 195 | MA = male<p> 196 | # contacts - # rows<p> 197 | W = angled<p> 198 | <author>Created by librarian@cadsoft.de</author> 199 | 200 | 201 | <b>PIN HEADER</b> 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | >NAME 233 | 1 234 | >VALUE 235 | 4 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | <b>EAGLE Design Rules</b> 262 | <p> 263 | Die Standard-Design-Rules sind so gewählt, dass sie für 264 | die meisten Anwendungen passen. Sollte ihre Platine 265 | besondere Anforderungen haben, treffen Sie die erforderlichen 266 | Einstellungen hier und speichern die Design Rules unter 267 | einem neuen Namen ab. 268 | <b>EAGLE Design Rules</b> 269 | <p> 270 | The default Design Rules have been set to cover 271 | a wide range of applications. Your particular design 272 | may have different requirements, so please make the 273 | necessary adjustments and save your customized 274 | design rules under a new name. 275 | <b>Seeed Studio EAGLE Design Rules</b> 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | --------------------------------------------------------------------------------