Home | History | Annotate | Download | only in hp20x
      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