1 /* 2 * Author: Jon Trulson <jtrulson (at) ics.com> 3 * Copyright (c) 2015 Intel Corporation. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be 14 * included in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25 #include <unistd.h> 26 #include <math.h> 27 #include <iostream> 28 #include <string> 29 #include <stdexcept> 30 31 #include "hp20x.h" 32 33 using namespace upm; 34 using namespace std; 35 36 37 HP20X::HP20X(int bus, uint8_t address): 38 m_i2c(bus) 39 { 40 m_addr = address; 41 42 mraa::Result rv; 43 if ( (rv = m_i2c.address(m_addr)) != mraa::SUCCESS) 44 { 45 throw std::invalid_argument(std::string(__FUNCTION__) + 46 ": I2c.address() failed"); 47 return; 48 } 49 } 50 51 HP20X::~HP20X() 52 { 53 } 54 55 bool HP20X::init(DSR_BITS_T dsr) 56 { 57 // wait for the device to report ready 58 waitforDeviceReady(); 59 60 m_dsr = dsr; 61 62 // enable compensation? Datasheet says yes, but a register readback 63 // says no. Data does seem stable, so.... 64 compensationEnable(true); 65 66 return true; 67 } 68 69 bool HP20X::isReady() 70 { 71 uint8_t intsrc = readReg(REG_INT_SRC); 72 73 if (intsrc & INT_SRC_DEV_RDY) 74 return true; 75 76 return false; 77 } 78 79 bool HP20X::waitforDeviceReady() 80 { 81 const int maxRetries = 20; 82 83 int retries = 0; 84 85 while (retries < maxRetries) 86 { 87 if (isReady()) 88 return true; 89 90 usleep(20000); 91 retries++; 92 } 93 94 throw std::runtime_error(std::string(__FUNCTION__) + 95 ": timeout waiting for device to become ready"); 96 97 return false; 98 } 99 100 bool HP20X::writeCmd(uint8_t cmd) 101 { 102 mraa::Result rv; 103 if ((rv = m_i2c.writeByte(cmd)) != mraa::SUCCESS) 104 { 105 throw std::runtime_error(std::string(__FUNCTION__) + 106 ": I2c.writeByte() failed"); 107 return false; 108 } 109 110 return true; 111 } 112 113 bool HP20X::writeReg(HP20X_REG_T reg, uint8_t data) 114 { 115 waitforDeviceReady(); 116 117 uint8_t r = CMD_WRITE_REG | reg; 118 119 mraa::Result rv; 120 if ((rv = m_i2c.writeReg(r, data)) != mraa::SUCCESS) 121 { 122 throw std::runtime_error(std::string(__FUNCTION__) + 123 ": I2c.writeReg() failed"); 124 return false; 125 } 126 127 return true; 128 } 129 130 uint8_t HP20X::readReg(HP20X_REG_T reg) 131 { 132 uint8_t r = CMD_READ_REG | reg; 133 134 return m_i2c.readReg(r); 135 } 136 137 int HP20X::readData() 138 { 139 uint8_t buf[3] = {0}; 140 141 if (!m_i2c.read(buf, 3)) 142 { 143 throw std::runtime_error(std::string(__FUNCTION__) + 144 ": I2c.read() failed"); 145 return 0; 146 } 147 148 // handle 24bit sign extension 149 int minus = 1; 150 if (buf[0] & 0x80) 151 { 152 // negative 153 buf[0] &= 0x3f; 154 minus = -1; 155 } 156 157 return ( minus * ((buf[0] << 16) | (buf[1] << 8) | buf[2]) ); 158 } 159 160 float HP20X::getTemperature() 161 { 162 // wait for the device to report ready 163 waitforDeviceReady(); 164 165 // start conversion, T only 166 uint8_t cmd = CMD_ADC_CVT | (CHNL_T << CHNL_SHIFT) | (m_dsr << DSR_SHIFT); 167 writeCmd(cmd); 168 169 // wait for the device to report ready 170 waitforDeviceReady(); 171 172 // now read the temperature 173 writeCmd(CMD_READ_T); 174 175 return ((float)readData() / 100.0); 176 } 177 178 float HP20X::getPressure() 179 { 180 // wait for the device to report ready 181 waitforDeviceReady(); 182 183 // start conversion, PT only 184 uint8_t cmd = CMD_ADC_CVT | (CHNL_PT << CHNL_SHIFT) | (m_dsr << DSR_SHIFT); 185 writeCmd(cmd); 186 187 // wait for the device to report ready 188 waitforDeviceReady(); 189 190 // now read the pressure 191 writeCmd(CMD_READ_P); 192 193 return ((float)readData() / 100.0); 194 } 195 196 float HP20X::getAltitude() 197 { 198 // wait for the device to report ready 199 waitforDeviceReady(); 200 201 // start conversion, PT only 202 uint8_t cmd = CMD_ADC_CVT | (CHNL_PT << CHNL_SHIFT) | (m_dsr << DSR_SHIFT); 203 writeCmd(cmd); 204 205 // wait for the device to report ready 206 waitforDeviceReady(); 207 208 // now read the pressure 209 writeCmd(CMD_READ_A); 210 211 return ((float)readData() / 100.0); 212 } 213 214 void HP20X::compensationEnable(bool enable) 215 { 216 if (enable) 217 writeReg(REG_PARA, PARA_CMPS_EN); 218 else 219 writeReg(REG_PARA, 0); 220 } 221 222 bool HP20X::setInterruptEnable(uint8_t bits) 223 { 224 return writeReg(REG_INT_EN, bits); 225 } 226 227 bool HP20X::setInterruptConfig(uint8_t bits) 228 { 229 return writeReg(REG_INT_CFG, bits); 230 } 231 232 uint8_t HP20X::getInterruptSource() 233 { 234 return readReg(REG_INT_SRC); 235 } 236 237 void HP20X::setDSR(DSR_BITS_T dsr) 238 { 239 m_dsr = dsr; 240 } 241 242 void HP20X::recalibrateInternal() 243 { 244 waitforDeviceReady(); 245 writeCmd(CMD_ANA_CAL); 246 } 247 248 void HP20X::softReset() 249 { 250 waitforDeviceReady(); 251 writeCmd(CMD_SOFT_RST); 252 waitforDeviceReady(); 253 } 254 255 void HP20X::setAltitudeOffset(int16_t off) 256 { 257 writeReg(REG_ALT_OFF_LSB, (off & 0xff)); 258 writeReg(REG_ALT_OFF_MSB, ((off >> 8) & 0xff)); 259 } 260 261 void HP20X::setPAThreshholds(int16_t low, int16_t med, int16_t high) 262 { 263 // low 264 writeReg(REG_PA_L_TH_LSB, (low & 0xff)); 265 writeReg(REG_PA_L_TH_MSB, ((low >> 8) & 0xff)); 266 267 // medium 268 writeReg(REG_PA_M_TH_LSB, (med & 0xff)); 269 writeReg(REG_PA_M_TH_MSB, ((med >> 8) & 0xff)); 270 271 // high 272 writeReg(REG_PA_H_TH_LSB, (high & 0xff)); 273 writeReg(REG_PA_H_TH_MSB, ((high >> 8) & 0xff)); 274 } 275 276 void HP20X::setTemperatureThreshholds(int8_t low, int8_t med, int8_t high) 277 { 278 // low 279 writeReg(REG_T_L_TH, low); 280 281 // medium 282 writeReg(REG_T_M_TH, med); 283 284 // high 285 writeReg(REG_T_H_TH, high); 286 } 287 288