From 8624a07b77491449d60deadfede59e452db19af1 Mon Sep 17 00:00:00 2001 From: Jon Trulson Date: Wed, 12 Oct 2016 16:36:08 -0600 Subject: [PATCH] lm35: add C driver and example; FTI; C++ wraps C Signed-off-by: Jon Trulson --- examples/c/CMakeLists.txt | 1 + examples/c/lm35.c | 72 ++++++++++++++++++++ src/lm35/CMakeLists.txt | 14 ++-- src/lm35/lm35.c | 106 ++++++++++++++++++++++++++++++ src/lm35/lm35.cxx | 32 ++++++--- src/lm35/lm35.h | 104 +++++++++++++++++++++++++++++ src/lm35/lm35.hpp | 125 +++++++++++++++++++---------------- src/lm35/lm35_fti.c | 135 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 519 insertions(+), 70 deletions(-) create mode 100644 examples/c/lm35.c create mode 100644 src/lm35/lm35.c create mode 100644 src/lm35/lm35.h create mode 100644 src/lm35/lm35_fti.c diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index 927bff53..1b8dac47 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -124,6 +124,7 @@ add_example (yg1006) add_example (biss0001) add_example (bmi160) add_example (jhd1313m1) +add_example (lm35) # Custom examples add_custom_example (nmea_gps_i2c-example-c nmea_gps_i2c.c nmea_gps) diff --git a/examples/c/lm35.c b/examples/c/lm35.c new file mode 100644 index 00000000..7e2b5496 --- /dev/null +++ b/examples/c/lm35.c @@ -0,0 +1,72 @@ +/* + * 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 "lm35.h" +#include "upm_utilities.h" + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + +int main() +{ + signal(SIGINT, sig_handler); + +//! [Interesting] + + // Instantiate a LM35 on analog pin A0, with a default analog + // reference voltage of 5.0 + lm35_context sensor = lm35_init(0, 5.0); + + // Every half second, sample the sensor and output the temperature + + while (shouldRun) + { + float temp; + if (lm35_get_temperature(sensor, &temp) != UPM_SUCCESS) + { + printf("lm35_get_temperature failed\n"); + return 1; + } + + printf("Temperature: %3.2f C\n", temp); + + upm_delay_ms(500); + } + +//! [Interesting] + + printf("Exiting\n"); + + lm35_close(sensor); + + return 0; +} diff --git a/src/lm35/CMakeLists.txt b/src/lm35/CMakeLists.txt index e2c15d47..5cfab624 100644 --- a/src/lm35/CMakeLists.txt +++ b/src/lm35/CMakeLists.txt @@ -1,5 +1,9 @@ -set (libname "lm35") -set (libdescription "upm DFRobot LM35 temperature sensor") -set (module_src ${libname}.cxx) -set (module_hpp ${libname}.hpp) -upm_module_init() +upm_mixed_module_init (NAME lm35 + DESCRIPTION "LM35 Temperature Sensor" + C_HDR lm35.h + C_SRC lm35.c + CPP_HDR lm35.hpp + CPP_SRC lm35.cxx + FTI_SRC lm35_fti.c + CPP_WRAPS_C + REQUIRES mraa) \ No newline at end of file diff --git a/src/lm35/lm35.c b/src/lm35/lm35.c new file mode 100644 index 00000000..59c0fe60 --- /dev/null +++ b/src/lm35/lm35.c @@ -0,0 +1,106 @@ +/* + * 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 "lm35.h" + +lm35_context lm35_init(int pin, float aref) +{ + lm35_context dev = + (lm35_context)malloc(sizeof(struct _lm35_context)); + + if (!dev) + return NULL; + + // make sure MRAA is initialized + int mraa_rv; + if ((mraa_rv = mraa_init()) != MRAA_SUCCESS) + { + printf("%s: mraa_init() failed (%d).\n", __FUNCTION__, mraa_rv); + lm35_close(dev); + return NULL; + } + + // initialize the MRAA context + + if (!(dev->aio = mraa_aio_init(pin))) + { + printf("%s: mraa_aio_init failed.\n", __FUNCTION__); + lm35_close(dev); + + return NULL; + } + + dev->ares = (float)((1 << mraa_aio_get_bit(dev->aio)) - 1); + dev->aref = aref; + dev->scale = 1.0; + dev->offset = 0.0; + + return dev; +} + +void lm35_close(lm35_context dev) +{ + assert(dev != NULL); + + if (dev->aio) + mraa_aio_close(dev->aio); + + free(dev); +} + +upm_result_t lm35_get_temperature(const lm35_context dev, float *temperature) +{ + assert(dev != NULL); + + int val = mraa_aio_read(dev->aio); + if (val < 0) + { + printf("%s: mraa_aio_read() failed\n", __FUNCTION__); + *temperature = 0.0; + return UPM_ERROR_OPERATION_FAILED; + } + + // convert to mV + float mV = ((float)val * (dev->aref / dev->ares) * 1000.0); + + // 10mV/degree C + *temperature = mV / 10.0; + *temperature = *temperature * dev->scale + (dev->offset * dev->scale); + return UPM_SUCCESS; +} + +void lm35_set_offset(const lm35_context dev, float offset) +{ + assert(dev != NULL); + + dev->offset = offset; +} + +void lm35_set_scale(const lm35_context dev, float scale) +{ + assert(dev != NULL); + + dev->scale = scale; +} diff --git a/src/lm35/lm35.cxx b/src/lm35/lm35.cxx index 03f478d2..f54e4f3d 100644 --- a/src/lm35/lm35.cxx +++ b/src/lm35/lm35.cxx @@ -1,6 +1,6 @@ /* * Author: Jon Trulson - * Copyright (c) 2015 Intel Corporation. + * Copyright (c) 2015-2016 Intel Corporation. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -23,29 +23,43 @@ */ #include +#include #include "lm35.hpp" using namespace std; using namespace upm; LM35::LM35(int pin, float aref) : - m_aio(pin) + m_lm35(lm35_init(pin, aref)) { - m_aRes = m_aio.getBit(); - m_aref = aref; + if (!m_lm35) + throw std::runtime_error(string(__FUNCTION__) + + ": lm35_init() failed"); } LM35::~LM35() { + lm35_close(m_lm35); } float LM35::getTemperature() { - int val = m_aio.read(); + float temp; + upm_result_t rv = lm35_get_temperature(m_lm35, &temp); - // convert to mV - float temp = (float(val) * (m_aref / float(1 << m_aRes))) * 1000.0; + if (rv) + throw std::runtime_error(string(__FUNCTION__) + + ": lm35_get_temperature() failed"); - // 10mV/degree C - return(temp / 10.0); + return temp; +} + +void LM35::setScale(float scale) +{ + lm35_set_scale(m_lm35, scale); +} + +void LM35::setOffset(float offset) +{ + lm35_set_offset(m_lm35, offset); } diff --git a/src/lm35/lm35.h b/src/lm35/lm35.h new file mode 100644 index 00000000..0a1d9846 --- /dev/null +++ b/src/lm35/lm35.h @@ -0,0 +1,104 @@ +/* + * 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. + */ +#pragma once + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @file lm35.h + * @library lm35 + * @brief C API for the LM35 Temperature Sensor + * + * @include lm35.c + */ + + /** + * device context + */ + typedef struct _lm35_context + { + mraa_aio_context aio; + + // ADC reference voltage + float aref; + // ADC resolution + float ares; + + // scale and offset + float scale; + float offset; + } *lm35_context; + + /** + * LM35 initialization. + * + * @param pin Analog pin to use + * @param aref Analog reference voltage + */ + lm35_context lm35_init(int pin, float aref); + + /** + * LM35 close. + */ + void lm35_close(lm35_context dev); + + /** + * Returns the temperature in degrees Celsius + * + * @param temperature A pointer to a float that will contain the + * measured temperature. + * @return UPM status + */ + upm_result_t lm35_get_temperature(const lm35_context dev, + float *temperature); + + /** + * Set sensor offset. This offset is applied to the return values + * before scaling. Default is 0.0. + * + * @param dev sensor context pointer + * @param offset Offset to apply. + */ + void lm35_set_offset(const lm35_context dev, float offset); + + /** + * Set sensor scale. This scale is applied to the return values + * before the offset is applied. Default is 1.0. + * + * @param dev sensor context pointer + * @param scale Scale to apply. + */ + void lm35_set_scale(const lm35_context dev, float scale); + + +#ifdef __cplusplus +} +#endif diff --git a/src/lm35/lm35.hpp b/src/lm35/lm35.hpp index 675c4f87..438675ba 100644 --- a/src/lm35/lm35.hpp +++ b/src/lm35/lm35.hpp @@ -1,6 +1,6 @@ /* * Author: Jon Trulson - * Copyright (c) 2015 Intel Corporation. + * Copyright (c) 2015-2016 Intel Corporation. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the @@ -25,70 +25,83 @@ #include #include -#include +#include "lm35.h" namespace upm { - /** - * @brief DFRobot LM35 Linear Temperature Sensor - * @defgroup lm35 libupm-lm35 - * @ingroup dfrobot analog temp - */ - - /** - * @library lm35 - * @sensor lm35 - * @comname DFRobot LM35 Linear Temperature Sensor - * @altname LM35 - * @type temp - * @man dfrobot - * @web http://www.dfrobot.com/index.php?route=product/product&product_id=76 - * @con analog - * - * @brief API for the DFRobot LM35 Linear Temperature Sensor - * - * This sensor returns an analog voltage proportional to the - * temperature of the ambient environment. - * - * It has a range of 2C to 150C. - * - * This driver was developed using the DFRobot LM35 Linear - * Temperature Sensor - * - * @image html lm35.jpg - * @snippet lm35.cxx Interesting - */ - - class LM35 { - public: + /** + * @brief DFRobot LM35 Linear Temperature Sensor + * @defgroup lm35 libupm-lm35 + * @ingroup dfrobot analog temp + */ /** - * LM35 constructor + * @library lm35 + * @sensor lm35 + * @comname DFRobot LM35 Linear Temperature Sensor + * @altname LM35 + * @type temp + * @man dfrobot + * @web http://www.dfrobot.com/index.php?route=product/product&product_id=76 + * @con analog * - * @param pin Analog pin to use - * @param aref Analog reference voltage; default is 5.0 V - */ - LM35(int pin, float aref=5.0); - - /** - * LM35 destructor - */ - ~LM35(); - - /** - * Returns the temperature in degrees Celsius + * @brief API for the DFRobot LM35 Linear Temperature Sensor * - * @return The Temperature in degrees Celsius + * This sensor returns an analog voltage proportional to the + * temperature of the ambient environment. + * + * It has a range of 2C to 150C. + * + * This driver was developed using the DFRobot LM35 Linear + * Temperature Sensor + * + * @image html lm35.jpg + * @snippet lm35.cxx Interesting */ - float getTemperature(); - protected: - mraa::Aio m_aio; + class LM35 { + public: - private: - float m_aref; - // ADC resolution - int m_aRes; - }; + /** + * LM35 constructor + * + * @param pin Analog pin to use + * @param aref Analog reference voltage; default is 5.0 V + */ + LM35(int pin, float aref=5.0); + + /** + * LM35 destructor + */ + ~LM35(); + + /** + * Returns the temperature in degrees Celsius + * + * @return The Temperature in degrees Celsius + */ + float getTemperature(); + + /** + * Set sensor scale. This scale is applied to the return values + * before the offset is applied. Default is 1.0. + * + * @param scale Scale to apply. + */ + void setScale(float scale); + + /** + * Set sensor offset. This offset is applied to the return values + * before scaling. Default is 0.0. + * + * @param offset Offset to apply. + */ + void setOffset(float offset); + + protected: + lm35_context m_lm35; + + private: + }; } diff --git a/src/lm35/lm35_fti.c b/src/lm35/lm35_fti.c new file mode 100644 index 00000000..c4163891 --- /dev/null +++ b/src/lm35/lm35_fti.c @@ -0,0 +1,135 @@ +/* + * 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 "lm35.h" + +#include +#include + +#include "upm_fti.h" +#include "upm_sensor.h" + +/** + * This file implements the Function Table Interface (FTI) for this sensor + */ + +const char upm_lm35_name[] = "LM35"; +const char upm_lm35_description[] = "LM35 Analog Temperature Sensor"; +const upm_protocol_t upm_lm35_protocol[] = {UPM_ANALOG}; +const upm_sensor_t upm_lm35_category[] = {UPM_TEMPERATURE}; + +// forward declarations +const upm_sensor_descriptor_t upm_lm35_get_descriptor(); +const void* upm_lm35_get_ft(upm_sensor_t sensor_type); +upm_result_t upm_lm35_get_value(void* dev, float* tempval, + upm_temperature_u unit); +void* upm_lm35_init_name(); +void upm_lm35_close(void* dev); +upm_result_t upm_lm35_set_offset(void *dev, float offset); +upm_result_t upm_lm35_set_scale(void *dev, float scale); + +const upm_sensor_descriptor_t upm_lm35_get_descriptor() +{ + upm_sensor_descriptor_t usd; + usd.name = upm_lm35_name; + usd.description = upm_lm35_description; + usd.protocol_size = 1; + usd.protocol = upm_lm35_protocol; + usd.category_size = 1; + usd.category = upm_lm35_category; + return usd; +} + +static const upm_sensor_ft ft = +{ + .upm_sensor_init_name = &upm_lm35_init_name, + .upm_sensor_close = &upm_lm35_close, + .upm_sensor_get_descriptor = &upm_lm35_get_descriptor +}; + +static const upm_temperature_ft tft = +{ + .upm_temperature_get_value = &upm_lm35_get_value, + .upm_temperature_set_scale = &upm_lm35_set_scale, + .upm_temperature_set_offset = &upm_lm35_set_offset, +}; + +const void* upm_lm35_get_ft(upm_sensor_t sensor_type) +{ + if (sensor_type == UPM_SENSOR) + return &ft; + + if (sensor_type == UPM_TEMPERATURE) + return &tft; + + return NULL; +} + +void* upm_lm35_init_name() +{ + return NULL; +} + +void upm_lm35_close(void* dev) +{ + lm35_close((lm35_context)dev); +} + +upm_result_t upm_lm35_set_offset(void *dev, float offset) +{ + lm35_set_offset((lm35_context)dev, offset); + return UPM_SUCCESS; +} +upm_result_t upm_lm35_set_scale(void *dev, float scale) +{ + lm35_set_scale((lm35_context)dev, scale); + return UPM_SUCCESS; +} + +upm_result_t upm_lm35_get_value(void* dev, float* tempval, + upm_temperature_u unit) +{ + float temp = 0.0; + upm_result_t rv = lm35_get_temperature((lm35_context)dev, &temp); + + if (rv != UPM_SUCCESS) + return rv; + + switch (unit) + { + case CELSIUS: + *tempval = temp; + return UPM_SUCCESS; + + case KELVIN: + *tempval = temp + 273.15; + return UPM_SUCCESS; + + case FAHRENHEIT: + *tempval = temp * (9.0/5.0) + 32.0; + return UPM_SUCCESS; + } + + return UPM_ERROR_INVALID_PARAMETER; +}