/* * Author: Jon Trulson <jtrulson@ics.com> * Copyright (c) 2015 Intel Corporation. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include <unistd.h> #include <math.h> #include <iostream> #include <string> #include <stdexcept> #include "hp20x.h" using namespace upm; using namespace std; HP20X::HP20X(int bus, uint8_t address): m_i2c(bus) { m_addr = address; mraa::Result rv; if ( (rv = m_i2c.address(m_addr)) != mraa::SUCCESS) { throw std::invalid_argument(std::string(__FUNCTION__) + ": I2c.address() failed"); return; } } HP20X::~HP20X() { } bool HP20X::init(DSR_BITS_T dsr) { // wait for the device to report ready waitforDeviceReady(); m_dsr = dsr; // enable compensation? Datasheet says yes, but a register readback // says no. Data does seem stable, so.... compensationEnable(true); return true; } bool HP20X::isReady() { uint8_t intsrc = readReg(REG_INT_SRC); if (intsrc & INT_SRC_DEV_RDY) return true; return false; } bool HP20X::waitforDeviceReady() { const int maxRetries = 20; int retries = 0; while (retries < maxRetries) { if (isReady()) return true; usleep(20000); retries++; } throw std::runtime_error(std::string(__FUNCTION__) + ": timeout waiting for device to become ready"); return false; } bool HP20X::writeCmd(uint8_t cmd) { mraa::Result rv; if ((rv = m_i2c.writeByte(cmd)) != mraa::SUCCESS) { throw std::runtime_error(std::string(__FUNCTION__) + ": I2c.writeByte() failed"); return false; } return true; } bool HP20X::writeReg(HP20X_REG_T reg, uint8_t data) { waitforDeviceReady(); uint8_t r = CMD_WRITE_REG | reg; mraa::Result rv; if ((rv = m_i2c.writeReg(r, data)) != mraa::SUCCESS) { throw std::runtime_error(std::string(__FUNCTION__) + ": I2c.writeReg() failed"); return false; } return true; } uint8_t HP20X::readReg(HP20X_REG_T reg) { uint8_t r = CMD_READ_REG | reg; return m_i2c.readReg(r); } int HP20X::readData() { uint8_t buf[3] = {0}; if (!m_i2c.read(buf, 3)) { throw std::runtime_error(std::string(__FUNCTION__) + ": I2c.read() failed"); return 0; } // handle 24bit sign extension int minus = 1; if (buf[0] & 0x80) { // negative buf[0] &= 0x3f; minus = -1; } return ( minus * ((buf[0] << 16) | (buf[1] << 8) | buf[2]) ); } float HP20X::getTemperature() { // wait for the device to report ready waitforDeviceReady(); // start conversion, T only uint8_t cmd = CMD_ADC_CVT | (CHNL_T << CHNL_SHIFT) | (m_dsr << DSR_SHIFT); writeCmd(cmd); // wait for the device to report ready waitforDeviceReady(); // now read the temperature writeCmd(CMD_READ_T); return ((float)readData() / 100.0); } float HP20X::getPressure() { // wait for the device to report ready waitforDeviceReady(); // start conversion, PT only uint8_t cmd = CMD_ADC_CVT | (CHNL_PT << CHNL_SHIFT) | (m_dsr << DSR_SHIFT); writeCmd(cmd); // wait for the device to report ready waitforDeviceReady(); // now read the pressure writeCmd(CMD_READ_P); return ((float)readData() / 100.0); } float HP20X::getAltitude() { // wait for the device to report ready waitforDeviceReady(); // start conversion, PT only uint8_t cmd = CMD_ADC_CVT | (CHNL_PT << CHNL_SHIFT) | (m_dsr << DSR_SHIFT); writeCmd(cmd); // wait for the device to report ready waitforDeviceReady(); // now read the pressure writeCmd(CMD_READ_A); return ((float)readData() / 100.0); } void HP20X::compensationEnable(bool enable) { if (enable) writeReg(REG_PARA, PARA_CMPS_EN); else writeReg(REG_PARA, 0); } bool HP20X::setInterruptEnable(uint8_t bits) { return writeReg(REG_INT_EN, bits); } bool HP20X::setInterruptConfig(uint8_t bits) { return writeReg(REG_INT_CFG, bits); } uint8_t HP20X::getInterruptSource() { return readReg(REG_INT_SRC); } void HP20X::setDSR(DSR_BITS_T dsr) { m_dsr = dsr; } void HP20X::recalibrateInternal() { waitforDeviceReady(); writeCmd(CMD_ANA_CAL); } void HP20X::softReset() { waitforDeviceReady(); writeCmd(CMD_SOFT_RST); waitforDeviceReady(); } void HP20X::setAltitudeOffset(int16_t off) { writeReg(REG_ALT_OFF_LSB, (off & 0xff)); writeReg(REG_ALT_OFF_MSB, ((off >> 8) & 0xff)); } void HP20X::setPAThreshholds(int16_t low, int16_t med, int16_t high) { // low writeReg(REG_PA_L_TH_LSB, (low & 0xff)); writeReg(REG_PA_L_TH_MSB, ((low >> 8) & 0xff)); // medium writeReg(REG_PA_M_TH_LSB, (med & 0xff)); writeReg(REG_PA_M_TH_MSB, ((med >> 8) & 0xff)); // high writeReg(REG_PA_H_TH_LSB, (high & 0xff)); writeReg(REG_PA_H_TH_MSB, ((high >> 8) & 0xff)); } void HP20X::setTemperatureThreshholds(int8_t low, int8_t med, int8_t high) { // low writeReg(REG_T_L_TH, low); // medium writeReg(REG_T_M_TH, med); // high writeReg(REG_T_H_TH, high); }