1/* 2 * Author: William Penner <william.penner@intel.com> 3 * Copyright (c) 2014 Intel Corporation. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 * THE SOFTWARE. 22 */ 23 24#include <iostream> 25#include <string> 26#include <stdexcept> 27 28#include <unistd.h> 29#include <stdlib.h> 30 31#include "htu21d.h" 32 33using namespace upm; 34 35HTU21D::HTU21D(int bus, int devAddr) : m_i2ControlCtx(bus) { 36 m_temperature = 0; 37 m_humidity = 0; 38 39 m_name = HTU21D_NAME; 40 41 m_controlAddr = devAddr; 42 m_bus = bus; 43 44 mraa::Result ret = m_i2ControlCtx.address(m_controlAddr); 45 if (ret != mraa::SUCCESS) { 46 throw std::invalid_argument(std::string(__FUNCTION__) + 47 ": mraa_i2c_address() failed"); 48 } 49 resetSensor(); 50} 51 52void 53HTU21D::resetSensor(void) 54{ 55 uint8_t data; 56 m_i2ControlCtx.address (m_controlAddr); 57 m_i2ControlCtx.write (&data, 1); 58 usleep(20000); 59} 60 61/* 62 * Convert register value to degC * 1000 63 */ 64int32_t 65HTU21D::convertTemp(int32_t regval) 66{ 67 return ((21965 * (regval & 0xFFFC)) >> 13) - 46850; 68} 69 70/* 71 * Convert register value to %RH * 1000 72 */ 73int32_t 74HTU21D::convertRH(int regval) 75{ 76 return ((15625 * (regval & 0xFFFC)) >> 13) - 6000; 77} 78 79int 80HTU21D::sampleData(void) 81{ 82 uint32_t itemp; 83 84 itemp = i2cReadReg_16(HTU21D_READ_TEMP_HOLD); 85 m_temperature = convertTemp(itemp); 86 87 itemp = i2cReadReg_16(HTU21D_READ_HUMIDITY_HOLD); 88 m_humidity = convertRH(itemp); 89 90 return 0; 91} 92 93float 94HTU21D::getTemperature(int bSampleData) 95{ 96 if (bSampleData) { 97 sampleData(); 98 } 99 return (float)m_temperature / 1000; 100} 101 102float 103HTU21D::getHumidity(int bSampleData) 104{ 105 if (bSampleData) { 106 sampleData(); 107 } 108 return (float)m_humidity / 1000; 109} 110 111/* 112 * Use the compensation equation from the datasheet to correct the 113 * current reading 114 * RHcomp = RHactualT + (25 - Tactual) * CoeffTemp 115 * RHcomp is in units of %RH * 1000 116 */ 117float 118HTU21D::getCompRH(int bSampleData) 119{ 120 if (bSampleData) { 121 sampleData(); 122 } 123 return (float)(m_humidity + (25000 - m_temperature) * 3 / 20) / 1000; 124} 125 126int 127HTU21D::setHeater(int bEnable) 128{ 129 uint8_t userreg; 130 131 userreg = i2cReadReg_8(HTU21D_READ_USER_REG); 132 if (bEnable) 133 userreg |= HTU21D_HEATER_ENABLE; 134 else 135 userreg &= ~HTU21D_HEATER_ENABLE; 136 if (i2cWriteReg(HTU21D_WRITE_USER_REG, userreg) < 0) 137 return -1; 138 139 return 0; 140} 141 142/* 143 * Test function: when reading the HTU21D many times rapidly should 144 * result in a temperature increase. This test will verify that the 145 * value is changing from read to read 146 */ 147 148int 149HTU21D::testSensor(void) 150{ 151 int i; 152 int iError = 0; 153 float fTemp, fHum; 154 float fTempMax, fTempMin; 155 float fHumMax, fHumMin; 156 float fHumFirst, fTempFirst; 157 158 fprintf(stdout, "Executing Sensor Test\n" ); 159 160 fHum = getHumidity(true); 161 fTemp = getTemperature(false); 162 fTempFirst = fTempMax = fTempMin = fTemp; 163 fHumFirst = fHumMax = fHumMin = fHum; 164 165 // Turn on the heater to make a sensor change 166 setHeater(true); 167 168 // Then sample the sensor a few times 169 for (i=0; i < 10; i++) { 170 fHum = getHumidity(true); 171 fTemp = getTemperature(false); 172 if (fHum < fHumMin) fHumMin = fHum; 173 if (fHum > fHumMax) fHumMax = fHum; 174 if (fTemp < fTempMin) fTempMin = fTemp; 175 if (fTemp > fTempMax) fTempMax = fTemp; 176 usleep(50000); 177 } 178 179 // Turn off the heater 180 setHeater(false); 181 182 // Now check the results 183 if ((fTemp - fTempFirst) <= 0) { 184 fprintf(stdout, " Temperature should have increased, but didn't\n" ); 185 iError++; 186 } 187 if (fHumMin == fHumMax) { 188 fprintf(stdout, " Humidity reading was unchanged - warning\n" ); 189 iError++; 190 } 191 if (fTempMin == fTempMax) { 192 fprintf(stdout, " Temperature reading was unchanged - warning\n" ); 193 iError++; 194 } 195 if (iError == 0) { 196 fprintf(stdout, " Device appears functional\n" ); 197 } 198 199 fprintf(stdout, " Test complete\n" ); 200 201 return iError; 202} 203 204/* 205 * Functions to read and write data to the i2c device 206 */ 207 208mraa::Result 209HTU21D::i2cWriteReg (uint8_t reg, uint8_t value) { 210 mraa::Result error = mraa::SUCCESS; 211 212 uint8_t data[2] = { reg, value }; 213 m_i2ControlCtx.address (m_controlAddr); 214 error = m_i2ControlCtx.write (data, 2); 215 if ( error != mraa::SUCCESS) 216 throw std::invalid_argument(std::string(__FUNCTION__) + 217 ": mraa_i2c_write() failed"); 218 219 return error; 220} 221 222uint16_t 223HTU21D::i2cReadReg_16 (int reg) { 224 uint16_t data; 225 m_i2ControlCtx.address(m_controlAddr); 226 data = (uint16_t)m_i2ControlCtx.readReg(reg) << 8; 227 data |= (uint16_t)m_i2ControlCtx.readReg(reg+1); 228 return data; 229} 230 231uint8_t 232HTU21D::i2cReadReg_8 (int reg) { 233 m_i2ControlCtx.address(m_controlAddr); 234 return m_i2ControlCtx.readReg(reg); 235} 236 237