otp538u: C implementation; FTI; C++ wraps C

Signed-off-by: Jon Trulson <jtrulson@ics.com>
This commit is contained in:
Jon Trulson 2016-11-07 13:53:11 -07:00
parent 1aa748e3d6
commit 1630ebfca4
10 changed files with 906 additions and 393 deletions

View File

@ -134,6 +134,7 @@ add_example (mma7660)
add_example (buzzer)
add_example (ppd42ns)
add_example (guvas12d)
add_example (otp538u)
# Custom examples
add_custom_example (nmea_gps_i2c-example-c nmea_gps_i2c.c nmea_gps)

81
examples/c/otp538u.c Normal file
View File

@ -0,0 +1,81 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* 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 <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <upm_utilities.h>
#include <otp538u.h>
bool shouldRun = true;
// analog voltage, usually 3.3 or 5.0
#define OTP538U_AREF 5.0
void sig_handler(int signo)
{
if (signo == SIGINT)
shouldRun = false;
}
int main()
{
signal(SIGINT, sig_handler);
//! [Interesting]
// Instantiate a OTP538U on analog pins A0 and A1
// A0 is used for the Ambient Temperature and A1 is used for the
// Object temperature.
otp538u_context temps = otp538u_init(0, 1, OTP538U_AREF);
// enable debugging if you would like
// otp538u_set_debug(temps, true);
// Output ambient and object temperatures
while (shouldRun)
{
float ambient = 0, object = 0;
if (otp538u_get_ambient_temperature(temps, &ambient))
printf("otp538u_get_ambient_temperature() failed\n");
else if (otp538u_get_object_temperature(temps, &object))
printf("otp538u_get_object_temperature() failed\n");
else
printf("Ambient temp: %f C, Object temp: %f C\n",
ambient, object);
printf("\n");
upm_delay(1);
}
printf("Exiting\n");
otp538u_close(temps);
//! [Interesting]
return 0;
}

View File

@ -1,5 +1,9 @@
set (libname "otp538u")
set (libdescription "Otp538u IR temperature sensor")
set (module_src ${libname}.cxx)
set (module_hpp ${libname}.hpp)
upm_module_init()
upm_mixed_module_init (NAME otp538u
DESCRIPTION "OTP538U Analog IR temperature sensor"
C_HDR otp538u.h
C_SRC otp538u.c
CPP_HDR otp538u.hpp
CPP_SRC otp538u.cxx
FTI_SRC otp538u_fti.c
CPP_WRAPS_C
REQUIRES mraa)

374
src/otp538u/otp538u.c Normal file
View File

@ -0,0 +1,374 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* 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 <assert.h>
#include <string.h>
#include <upm_utilities.h>
#include <upm_platform.h>
#include <otp538u.h>
#include "thermopile_vt_table.h"
#include "thermister_rt_table.h"
// To save memory space, we disable debugging on non-linux platforms
// by default (Zephyr). For other systems, enable as desired/possible.
#if defined(UPM_PLATFORM_LINUX)
# define OTP538U_DEBUG_ENABLED
#endif // UPM_PLATFORM_LINUX
otp538u_context otp538u_init(int pinA, int pinO, float aref)
{
otp538u_context dev =
(otp538u_context)malloc(sizeof(struct _otp538u_context));
if (!dev)
return NULL;
memset((void *)dev, 0, sizeof(struct _otp538u_context));
// 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);
otp538u_close(dev);
return NULL;
}
// initialize the MRAA contexts
if (!(dev->aioA = mraa_aio_init(pinA)))
{
printf("%s: mraa_aio_init(pinA) failed.\n", __FUNCTION__);
otp538u_close(dev);
return NULL;
}
if (!(dev->aioO = mraa_aio_init(pinO)))
{
printf("%s: mraa_aio_init(pinO) failed.\n", __FUNCTION__);
otp538u_close(dev);
return NULL;
}
// for subplatforms like the Arduino 101 with Firmata, we need to
// limit ADC resolution to 10b currently. For this sensor
// unfortunately, this means readings will be less accurate. This
// sensor really does need to measure with about 1mV accuracy.
const int adcHighRes = 4095;
const int adcLowRes = 1023;
bool isSubplatform = false;
dev->debug = false;
if (pinA >= 512 || pinO >= 512)
isSubplatform = true;
// this is the internal voltage reference on the Grove IR temp
// sensor module for the thermistor.
dev->internalVRef = 2.5;
// analog reference in use
dev->aref = aref;
// This is the value of the output resistor of the Grove IR
// temp sensor's SIG2 output (ambient)
dev->vResistance = 2000000; // 2M ohms
// This was the default offset voltage in the seeedstudio code. You
// can adjust as neccessary depending on your calibration.
dev->offsetVoltage = 0.014;
// We need around 1mV resolution (preferred), so use 12 bit
// resolution (4096) if we can.
//
// This logic is over complicated due to the fact that it is
// currently difficult to determine exactly what the capabilities of
// the platform (sub or otherwise) actually are. So for
// subplatforms, we always limit to 1024. Otherwise, we try 12b if
// the mraa_adc_raw_bits() says we can, though this isn't
// particularly accurate either, as it reports that the G2 can do
// 12b, when in reality it can not. We are just lucky that it works
// anyway (ie: will give 12b resolution, though underneath it's just
// scaling the real 10b value.). Sigh. But trying 12b resolution
// on the 101 via firmata will definitely break things, so don't
// even try until whatever the problem it has with 12b is fixed.
if (isSubplatform)
{
dev->adcResolution = adcLowRes; // 10b
}
else
{
if (mraa_adc_raw_bits() == 12)
dev->adcResolution = adcHighRes; // 12b
else
dev->adcResolution = adcLowRes; // 10b
}
// notify the user
if (dev->adcResolution == adcLowRes)
printf("Using 10 bit ADC resolution. Values will be less accurate.\n");
// enable 12 bit resolution, if we can
if (dev->adcResolution == adcHighRes)
mraa_aio_set_bit(dev->aioA, 12);
if (dev->adcResolution == adcHighRes)
mraa_aio_set_bit(dev->aioO, 12);
if (isSubplatform)
{
// The first analog read always seems to return 0 on the 101
// with firmata, so just do a couple of reads here and discard
// them. Then sleep for half a second. THIS IS A HACK. The
// real problem should be fixed elsewhere (Firmata?).
mraa_aio_read(dev->aioA);
mraa_aio_read(dev->aioO);
upm_delay_ms(500);
}
return dev;
}
void otp538u_close(otp538u_context dev)
{
assert(dev != NULL);
if (dev->aioA)
mraa_aio_close(dev->aioA);
if (dev->aioO)
mraa_aio_close(dev->aioO);
free(dev);
}
upm_result_t otp538u_get_ambient_temperature(const otp538u_context dev,
float *temperature)
{
assert(dev != NULL);
const int samples = 5;
int val = 0;
float temp = 0;
float res = 0;
for (int i=0; i<samples; i++)
{
val = mraa_aio_read(dev->aioA);
if (val == -1)
{
printf("%s: mraa_aio_read() failed.\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
temp += (float)val;
upm_delay_ms(10);
}
temp = temp / samples;
float volts = temp * dev->aref / dev->adcResolution;
#if defined(OTP538U_DEBUG_ENABLED)
if (dev->debug)
{
printf("\tAMB sample %f aref %f volts %f\n", temp, dev->aref,
volts);
}
#endif // OTP538U_DEBUG_ENABLED
// compute the resistance of the thermistor
res = dev->vResistance * volts / (dev->internalVRef - volts);
#if defined(OTP538U_DEBUG_ENABLED)
if (dev->debug)
{
printf("\tAMB computed resistance: %f\n", res);
}
#endif // OTP538U_DEBUG_ENABLED
// look it up in the thermistor (RT) resistence/temperature table
int rawslot;
int j;
for (j=0; j<otp538u_rt_table_max; j++)
if (otp538u_rt_table[j] < res)
{
rawslot = j;
break;
}
if (j >= otp538u_rt_table_max)
{
printf("%s: Ambient temperature out of range (high)\n", __FUNCTION__);
return UPM_ERROR_OUT_OF_RANGE;
}
// we need to compensate for the fact that we are supporting
// temperature values less than 0 (-20C), so adjust correspondingly
// so that we obtain the correct temperature 'slot'. This will be
// our base temperature.
int slot = rawslot - 20;
// too cold
if (slot < 0)
{
printf("%s: Ambient temperature out of range (low)\n", __FUNCTION__);
return UPM_ERROR_OUT_OF_RANGE;
}
// now compute the ambient temperature
float ambientTemp = slot - 1 +
(otp538u_rt_table[rawslot - 1]-res) / (otp538u_rt_table[rawslot - 1] -
otp538u_rt_table[rawslot]);
*temperature = ambientTemp;
return UPM_SUCCESS;
}
upm_result_t otp538u_get_object_temperature(const otp538u_context dev,
float *temperature)
{
assert(dev != NULL);
const int samples = 5;
const float reference_vol = 0.5; // what is this value? (from seeedstudio)
const float tempIncrement = 10.0;
int val = 0;
float temp = 0;
float ambTemp = 0.0;
if (otp538u_get_ambient_temperature(dev, &ambTemp))
return UPM_ERROR_OPERATION_FAILED;
for (int i=0; i<samples; i++)
{
val = mraa_aio_read(dev->aioO);
if (val == -1)
{
printf("%s: mraa_aio_read() failed.\n", __FUNCTION__);
return UPM_ERROR_OPERATION_FAILED;
}
temp += val;
upm_delay_ms(10);
}
temp = temp / samples;
#if defined(OTP538U_DEBUG_ENABLED)
if (dev->debug)
printf("\tOBJ sample %f ", temp);
#endif // OTP538U_DEBUG_ENABLED
float volts = temp * dev->aref / dev->adcResolution;
#if defined(OTP538U_DEBUG_ENABLED)
if (dev->debug)
printf("VOLTS: %f ", volts);
#endif // OTP538U_DEBUG_ENABLED
float sensorVolts = volts - (reference_vol + dev->offsetVoltage);
#if defined(OTP538U_DEBUG_ENABLED)
if (dev->debug)
printf("Sensor Voltage (computed): %f\n", sensorVolts);
#endif // OTP538U_DEBUG_ENABLED
// search the VT (voltage/temperature) table to find the object
// temperature.
int slot;
// add +2 to compensate for the -20C and -10C slots below zero
int voltOffset = (int)(ambTemp / 10) + 1 + 2;
float voltage = sensorVolts * 10.0;
for (slot=0; slot<(otp538u_vt_table_max - 1); slot++)
{
if ( (voltage > otp538u_vt_table[slot][voltOffset]) &&
(voltage < otp538u_vt_table[slot+1][voltOffset]) )
{
break;
}
}
if (slot >= (otp538u_vt_table_max - 1))
{
printf("%s: Object temperature out of range (high)\n", __FUNCTION__);
return UPM_ERROR_OUT_OF_RANGE;
}
float objTemp = ((float)tempIncrement * voltage) /
( otp538u_vt_table[slot + 1][voltOffset] -
otp538u_vt_table[slot][voltOffset] );
#if defined(OTP538U_DEBUG_ENABLED)
if (dev->debug)
{
printf("\tVoltage (%f): TABLE VALUE [%d][%d] = %f\n", voltage,
slot, voltOffset, otp538u_vt_table[slot][voltOffset]);
}
#endif // OTP538U_DEBUG_ENABLED
*temperature = ambTemp + objTemp;
return UPM_SUCCESS;
}
void otp538u_set_voltage_offset(const otp538u_context dev, float offset)
{
assert(dev != NULL);
dev->offsetVoltage = offset;
}
void otp538u_set_output_resistence(const otp538u_context dev,
int resistance)
{
assert(dev != NULL);
dev->vResistance = resistance;
}
void otp538u_set_ivref(const otp538u_context dev, float vref)
{
assert(dev != NULL);
dev->internalVRef = vref;
}
void otp538u_set_debug(const otp538u_context dev, bool enable)
{
assert(dev != NULL);
dev->debug = enable;
#if !defined(UPM_PLATFORM_LINUX) && !defined(OTP538U_DEBUG_ENABLED)
if (enable)
printf("%s: Debugging not enabled at compilation time.\n",
__FUNCTION__);
#endif // !UPM_PLATFORM_LINUX && !OTP538U_DEBUG_ENABLED
}

View File

@ -1,6 +1,6 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* 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
@ -28,258 +28,40 @@
#include "otp538u.hpp"
#include "thermopile_vt_table.hpp"
#include "thermister_rt_table.hpp"
using namespace upm;
using namespace std;
OTP538U::OTP538U(int pinA, int pinO, float aref)
OTP538U::OTP538U(int pinA, int pinO, float aref) :
m_otp538u(otp538u_init(pinA, pinO, aref))
{
const int adcHighRes = 4095;
const int adcLowRes = 1023;
// for subplatforms like the Arduino 101, we need to limit ADC
// resolution to 10b currently. For this sensor unfortunately, this
// means readings will be less accurate. This sensor really does
// need to measure with about 1mV accuracy.
bool isSubplatform = false;
m_debug = false;
if (pinA >= 512 || pinO >= 512)
isSubplatform = true;
// this is the internal voltage reference on the Grove IR temp
// sensor module for the thermistor.
m_internalVRef = 2.5;
// analog reference in use
m_aref = aref;
// This is the value of the output resistor of the Grove IR
// temp sensor's SIG2 output (ambient)
m_vResistance = 2000000; // 2M ohms
// This was the default offset voltage in the seeedstudio code. You
// can adjust as neccessary depending on your calibration.
m_offsetVoltage = 0.014;
// We need around 1mV resolution (preferred), so use 12 bit
// resolution (4096) if we can.
//
// This logic is over complicated due to the fact that it is
// currently difficult to determine exactly what the capabilities of
// the platform (sub or otherwise) actually are. So for
// subplatforms, we always limit to 1024. Otherwise, we try 12b if
// the mraa_adc_raw_bits() says we can, though this isn't
// particularly accurate either, as it reports that the G2 can do
// 12b, when in reality it can not. We are just lucky that it works
// anyway (ie: will give 12b resolution, though underneath it's just
// scaling the real 10b value.). Sigh. But trying 12b resolution
// on the 101 via firmata will definitely break things, so don't
// even try until whatever the problem it has with 12b is fixed.
if (isSubplatform)
{
m_adcResolution = adcLowRes; // 10b
}
else
{
if (mraa_adc_raw_bits() == 12)
m_adcResolution = adcHighRes; // 12b
else
m_adcResolution = adcLowRes; // 10b
}
// notify the user
if (m_adcResolution == adcLowRes)
cerr << "Using 10 bit ADC resolution. Values will be less accurate."
<< endl;
if ( !(m_aioA = mraa_aio_init(pinA)) )
{
throw std::invalid_argument(std::string(__FUNCTION__) +
": mraa_gpio_init(pinA) failed");
return;
}
// enable 12 bit resolution, if we can
if (m_adcResolution == adcHighRes)
mraa_aio_set_bit(m_aioA, 12);
if ( !(m_aioO = mraa_aio_init(pinO)) )
{
throw std::invalid_argument(std::string(__FUNCTION__) +
": mraa_gpio_init(pinO) failed");
return;
}
// enable 12 bit resolution, if we can
if (m_adcResolution == adcHighRes)
mraa_aio_set_bit(m_aioO, 12);
if (isSubplatform)
{
// The first analog read always seems to return 0 on the 101
// with firmata, so just do a couple of reads here and discard
// them. Then sleep for half a second. THIS IS A HACK. The
// real problem should be fixed elsewhere (Firmata?).
mraa_aio_read(m_aioA);
mraa_aio_read(m_aioO);
usleep(500000);
}
if (!m_otp538u)
throw std::runtime_error(std::string(__FUNCTION__) +
": otp538u_init() failed");
}
OTP538U::~OTP538U()
{
mraa_aio_close(m_aioA);
mraa_aio_close(m_aioO);
otp538u_close(m_otp538u);
}
float OTP538U::ambientTemperature()
{
const int samples = 5;
int val = 0;
float temp = 0;
float res = 0;
for (int i=0; i<samples; i++)
{
val = mraa_aio_read(m_aioA);
if (val == -1) {
if (otp538u_get_ambient_temperature(m_otp538u, &temp))
throw std::runtime_error(std::string(__FUNCTION__) +
": failed to do aio read");
}
temp += (float)val;
usleep(10000);
}
temp = temp / samples;
": otp538u_get_ambient_temperature() failed");
float volts = temp * m_aref / m_adcResolution;
if (m_debug)
{
cerr << "\tAMB sample " << temp << " m_aref " << m_aref
<< " VOLTS " << volts << endl;
}
// compute the resistance of the thermistor
res = m_vResistance * volts / (m_internalVRef - volts);
if (m_debug)
{
cerr << "\tAMB computed resistance: " << res << endl;
}
// look it up in the thermistor (RT) resistence/temperature table
int rawslot;
int j;
for (j=0; j<otp538u_rt_table_max; j++)
if (otp538u_rt_table[j] < res)
{
rawslot = j;
break;
}
if (j >= otp538u_rt_table_max)
{
throw std::out_of_range(std::string(__FUNCTION__) +
": ambient temperature out of range (high).");
return 0;
}
// we need to compensate for the fact that we are supporting
// temperature values less than 0 (-20C), so adjust correspondingly
// so that we obtain the correct temperature 'slot'. This will be
// our base temperature.
int slot = rawslot - 20;
// too cold
if (slot < 0)
{
throw std::out_of_range(std::string(__FUNCTION__) +
": ambient temperature out of range (low).");
return 0;
}
// now compute the ambient temperature
float ambientTemp = slot - 1 +
(otp538u_rt_table[rawslot - 1]-res) / (otp538u_rt_table[rawslot - 1] -
otp538u_rt_table[rawslot]);
return ambientTemp;
return temp;
}
float OTP538U::objectTemperature()
{
const int samples = 5;
const float reference_vol= 0.5; // what is this value? (from seeedstudio)
const float tempIncrement=10;
int val = 0;
float temp = 0;
float ambTemp = ambientTemperature();
for (int i=0; i<samples; i++)
{
val = mraa_aio_read(m_aioO);
if (val == -1) {
if (otp538u_get_object_temperature(m_otp538u, &temp))
throw std::runtime_error(std::string(__FUNCTION__) +
": failed to do aio read.");
return 0;
}
temp += val;
usleep(10000);
}
": otp538u_get_object_temperature() failed");
temp = temp / samples;
if (m_debug)
cerr << "\tOBJ sample " << temp << " ";
float volts = temp * m_aref / m_adcResolution;
if (m_debug)
cerr << "VOLTS: " << volts << " ";
float sensorVolts = volts - (reference_vol + m_offsetVoltage);
if (m_debug)
cerr << "Sensor Voltage (computed): " << sensorVolts << endl;
// search the VT (voltage/temperature) table to find the object
// temperature.
int slot;
// add +2 to compensate for the -20C and -10C slots below zero
int voltOffset = int(ambTemp / 10) + 1 + 2;
float voltage = sensorVolts * 10.0;
for (slot=0; slot<(otp538u_vt_table_max - 1); slot++)
{
if ( (voltage > otp538u_vt_table[slot][voltOffset]) &&
(voltage < otp538u_vt_table[slot+1][voltOffset]) )
{
break;
}
}
if (slot >= (otp538u_vt_table_max - 1))
{
throw std::out_of_range(std::string(__FUNCTION__) +
": object temperature out of range.");
return 0;
}
float objTemp = (float(tempIncrement) * voltage) /
( otp538u_vt_table[slot + 1][voltOffset] -
otp538u_vt_table[slot][voltOffset] );
if (m_debug)
{
cerr << "\tVoltage (" << voltage << "): TABLE VALUE [" << slot << "][" <<
voltOffset << "] = " << otp538u_vt_table[slot][voltOffset] << endl;
}
return (ambTemp + objTemp);
return temp;
}

153
src/otp538u/otp538u.h Normal file
View File

@ -0,0 +1,153 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* 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 <stdlib.h>
#include <stdio.h>
#include <upm.h>
#include <mraa/aio.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file otp538u.h
* @library otp538u
* @brief C API for the OTP538U IR Temperature Sensor
*
* @include otp538u.c
*/
/**
* device context
*/
typedef struct _otp538u_context
{
mraa_aio_context aioA;
mraa_aio_context aioO;
bool debug;
float internalVRef;
float aref;
int vResistance;
float offsetVoltage;
int adcResolution;
} *otp538u_context;
/**
* OTP538U constructor
*
* @param pinA Analog pin to use for the ambient temperature
* @param pinO Analog pin to use for the object temperature
* @param aref Analog reference voltage
* @return intialized context, or NULL if error
*/
otp538u_context otp538u_init(int pinA, int pinO, float aref);
/**
* OTP538U destructor
*
* @param dev Device context
*/
void otp538u_close(otp538u_context dev);
/**
* Gets the ambient temperature in Celsius
*
* @param dev Device context
* @param temp Ambient temperature
* @return UPM status
*/
upm_result_t otp538u_get_ambient_temperature(const otp538u_context dev,
float *temperature);
/**
* Gets the object temperature in Celsius
*
* @param dev Device context
* @param temp Object temperature
* @return UPM status
*/
upm_result_t otp538u_get_object_temperature(const otp538u_context dev,
float *temperature);
/**
* Sets the offset voltage
*
* The Seeed Studio wiki gives an example of calibrating the sensor
* and calculating the offset voltage to apply. Currently, the
* default value is set, but you can use the function to set one
* of your own.
*
* @param dev Device context
* @param vOffset Desired offset voltage
*/
void otp538u_set_voltage_offset(const otp538u_context dev, float offset);
/**
* Sets the output resistance value
*
* The Seeed Studio wiki example uses a value of 2,000,000 in one of
* the equations used to calculate voltage. The value is the
* resistance of a resistor they use in the output stage of their
* SIG2 output. This was 'decoded' by looking at the EAGLE* files
* containing their schematics for this device.
*
* @param dev Device context
* @param outResistance Value of the output resistor; default is 2M Ohm
*/
void otp538u_set_output_resistence(const otp538u_context dev,
int resistance);
/**
* Sets the reference voltage of the internal Seeed Studio voltage
* regulator on the sensor board.
*
* The Seeed Studio wiki example uses a value of 2.5 in one of the
* equations used to calculate the resistance of the ambient
* thermistor. The value is the voltage of an internal voltage
* regulator used on the sensor board. This was 'decoded' by
* looking at the EAGLE files containing their schematics for this
* device.
*
* @param dev Device context
* @param vref Reference voltage of the internal sensor; default
* is 2.5
*/
void otp538u_set_ivref(const otp538u_context dev, float vref);
/**
* Enable debugging output (linux platforms only).
*
* @param dev Device context
* @param true to enable some debug output, false otherwise
*/
void otp538u_set_debug(const otp538u_context dev, bool enable);
#ifdef __cplusplus
}
#endif

View File

@ -1,6 +1,6 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* 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
@ -24,7 +24,7 @@
#pragma once
#include <string>
#include <mraa/aio.h>
#include <otp538u.h>
namespace upm {
@ -112,7 +112,10 @@ namespace upm {
*
* @param vOffset Desired offset voltage
*/
void setVoltageOffset(float vOffset) { m_offsetVoltage = vOffset; };
void setVoltageOffset(float vOffset)
{
otp538u_set_voltage_offset(m_otp538u, vOffset);
};
/**
* Sets the output resistance value
@ -125,8 +128,10 @@ namespace upm {
*
* @param outResistance Value of the output resistor; default is 2M Ohm
*/
void setOutputResistence(int outResistance) {
m_vResistance = outResistance; };
void setOutputResistence(int outResistance)
{
otp538u_set_output_resistence(m_otp538u, outResistance);
};
/**
* Sets the reference voltage of the internal Seeed Studio voltage
@ -142,25 +147,24 @@ namespace upm {
* @param vref Reference voltage of the internal sensor; default
* is 2.5
*/
void setVRef(float vref) { m_internalVRef = vref; };
void setVRef(float vref)
{
otp538u_set_ivref(m_otp538u, vref);
};
/**
* Enable debugging output.
*
* @param true to enable some debug output, false otherwise
*/
void setDebug(bool enable) { m_debug = enable; };
void setDebug(bool enable)
{
otp538u_set_debug(m_otp538u, enable);
};
private:
bool m_debug;
float m_internalVRef;
float m_aref;
int m_vResistance;
float m_offsetVoltage;
int m_adcResolution;
mraa_aio_context m_aioA;
mraa_aio_context m_aioO;
protected:
otp538u_context m_otp538u;
};
}

116
src/otp538u/otp538u_fti.c Normal file
View File

@ -0,0 +1,116 @@
/*
* Author: Jon Trulson <jtrulson@ics.com>
* 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 "otp538u.h"
#include "upm_fti.h"
#include "upm_sensor.h"
/**
* This file implements the Function Table Interface (FTI) for this sensor
*/
const char upm_otp538u_name[] = "OTP538U";
const char upm_otp538u_description[] = "IR Temperature Sensor";
const upm_protocol_t upm_otp538u_protocol[] = {UPM_ANALOG, UPM_ANALOG};
const upm_sensor_t upm_otp538u_category[] = {UPM_TEMPERATURE};
// forward declarations
const upm_sensor_descriptor_t upm_otp538u_get_descriptor();
const void* upm_otp538u_get_ft(upm_sensor_t sensor_type);
upm_result_t upm_otp538u_get_value_temperature(void* dev, float* tempval,
upm_temperature_u unit);
void* upm_otp538u_init_name();
void upm_otp538u_close(void* dev);
const upm_sensor_descriptor_t upm_otp538u_get_descriptor() {
upm_sensor_descriptor_t usd;
usd.name = upm_otp538u_name;
usd.description = upm_otp538u_description;
usd.protocol_size = 2;
usd.protocol = upm_otp538u_protocol;
usd.category_size = 1;
usd.category = upm_otp538u_category;
return usd;
}
static const upm_sensor_ft ft =
{
.upm_sensor_init_name = &upm_otp538u_init_name,
.upm_sensor_close = &upm_otp538u_close,
.upm_sensor_get_descriptor = &upm_otp538u_get_descriptor
};
static const upm_temperature_ft tft =
{
.upm_temperature_get_value = &upm_otp538u_get_value_temperature
};
const void* upm_otp538u_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_otp538u_init_name(){
return NULL;
}
void upm_otp538u_close(void* dev)
{
otp538u_close((otp538u_context)dev);
}
upm_result_t upm_otp538u_get_value_temperature(void* dev, float* tempval,
upm_temperature_u unit)
{
float temp = 0.0;
upm_result_t rv = otp538u_get_object_temperature((otp538u_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;
}

View File

@ -28,7 +28,7 @@
static const int otp538u_rt_table_max = 121;
static int otp538u_rt_table[otp538u_rt_table_max] = {
static int otp538u_rt_table[121] = {
919730, 869299, 821942, 777454, 735644, 696336, 659365, 624578, 591834,
561002, 531958, 504588, 478788, 454457, 431504, 409843, 389394, 370082,
351839, 334598, 318300, 302903, 288329, 274533, 261471, 249100, 237381,
@ -43,4 +43,3 @@ static int otp538u_rt_table[otp538u_rt_table_max] = {
10926, 10587, 10260, 9945, 9641, 9347, 9063, 8789, 8525, 8270, 8023,
7785, 7555, 7333, 7118, 6911
};

View File

@ -30,7 +30,7 @@ static const int otp538u_vt_table_max = 23;
// Thermistor temperature (C)
// { -20 -10 0 10 20 30 40 50 60 70 80 90 100 }
static float otp538u_vt_table[otp538u_vt_table_max][13] = {
static float otp538u_vt_table[23][13] = {
// object temp (C)
{0.000, -0.246, -0.523, -0.832, -1.177, -1.559, // -20C
-1.981, -2.446, -2.957, -3.516, -4.126, -4.791, -5.513},
@ -101,4 +101,3 @@ static float otp538u_vt_table[otp538u_vt_table_max][13] = {
{13.284, 13.191, 13.068, 12.913, 12.722, 12.494, // 200
12.225, 11.914, 11.557, 11.152, 10.695, 10.184, 9.616}
};