/* * Author: Jon Trulson * Copyright (c) 2016 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 #include #include #include #include "ds18b20.hpp" using namespace upm; using namespace std; // conversion from celsius to fahrenheit static float c2f(float c) { return (c * (9.0 / 5.0) + 32.0); } DS18B20::DS18B20(int uart) : m_uart(uart) { m_devicesFound = 0; // check basic access to the 1-wire bus (presence detect) mraa::Result rv; if ((rv = m_uart.reset()) != mraa::SUCCESS) { throw std::runtime_error(std::string(__FUNCTION__) + ": reset() failed, no devices on bus?"); } } DS18B20::~DS18B20() { } void DS18B20::init() { // iterate through the bus and build up a list of detected DS18B20 // devices (only) // empty the map, in case this method has already been run once // before m_devicesFound = 0; m_deviceMap.clear(); sensor_info_t sinfo; // defaults sinfo.temperature = 0.0; sinfo.resolution = RESOLUTION_12BITS; // start the search from scratch string id = m_uart.search(true); if (id.empty()) { throw std::runtime_error(std::string(__FUNCTION__) + ": no devices detected on bus"); } while (!id.empty()) { // The first byte (id[0]]) is the device type (family) code. We // are only interested in the family code for these devices. if ((uint8_t)id[0] == DS18B20_FAMILY_CODE) { // we have a winner, add it to our map and continue searching sinfo.id = id; m_deviceMap[m_devicesFound] = sinfo; m_devicesFound++; } // continue search id = m_uart.search(false); } if (!m_devicesFound) { throw std::runtime_error(std::string(__FUNCTION__) + ": no DS18B20 devices found on bus"); } // iterate through the found devices and query their resolutions for (int i=0; i>= _CFG_RESOLUTION_SHIFT; switch (scratch[4] & _CFG_RESOLUTION_MASK) { case 0: m_deviceMap[i].resolution = RESOLUTION_9BITS; break; case 1: m_deviceMap[i].resolution = RESOLUTION_10BITS; break; case 2: m_deviceMap[i].resolution = RESOLUTION_11BITS; break; case 3: m_deviceMap[i].resolution = RESOLUTION_12BITS; break; } // reset the bus m_uart.reset(); } } void DS18B20::update(int index) { if (index >= m_devicesFound) { throw std::out_of_range(std::string(__FUNCTION__) + ": device index out of range"); } // should we update all of them? bool doAll = (index < 0) ? true : false; if (doAll) { // if we want to update all of them, we will first send the // convert command to all of them, then wait. This will be // faster, timey-wimey wise, then converting, sleeping, and // reading each individual sensor. for (int i=0; i= m_devicesFound) { throw std::out_of_range(std::string(__FUNCTION__) + ": device index out of range"); } static const int numScratch = 9; uint8_t scratch[numScratch]; // read the 9-byte scratchpad m_uart.command(CMD_READ_SCRATCHPAD, m_deviceMap[index].id); for (int i=0; i>= 4; // compensate for sign if (negative) temp -= 65536; // 2^^16 // convert return ( float(temp) + (float(frac) * 0.0625) ); } float DS18B20::getTemperature(int index, bool fahrenheit) { if (index < 0 || index >= m_devicesFound) { throw std::out_of_range(std::string(__FUNCTION__) + ": device index out of range"); } if (fahrenheit) return c2f(m_deviceMap[index].temperature); else return m_deviceMap[index].temperature; } void DS18B20::setResolution(int index, RESOLUTIONS_T res) { if (index < 0 || index >= m_devicesFound) { throw std::out_of_range(std::string(__FUNCTION__) + ": device index out of range"); } static const int numScratch = 9; uint8_t scratch[numScratch]; // read the 9-byte scratchpad m_uart.command(CMD_READ_SCRATCHPAD, m_deviceMap[index].id); for (int i=0; i= m_devicesFound) { throw std::out_of_range(std::string(__FUNCTION__) + ": device index out of range"); } // issue the command m_uart.command(CMD_COPY_SCRATCHPAD, m_deviceMap[index].id); sleep(1); // to be safe... } void DS18B20::recallEEPROM(int index) { if (index < 0 || index >= m_devicesFound) { throw std::out_of_range(std::string(__FUNCTION__) + ": device index out of range"); } // issue the command m_uart.command(CMD_RECALL_EEPROM, m_deviceMap[index].id); // issue read timeslots until a '1' is read back, indicating completion while (!m_uart.writeBit(1)) usleep(100); }