t3311: Initial implementation

This module implements support for the Comet System T3311 Temperature
and Humidity transmitter.  It uses MODBUS over an RS232 serial port.

You must have libmodbus v3.1.2 (or greater) installed to compile and
use this driver.

Signed-off-by: Jon Trulson <jtrulson@ics.com>
Signed-off-by: Mihai Tudor Panu <mihai.tudor.panu@intel.com>
This commit is contained in:
Jon Trulson 2016-01-08 17:48:49 -07:00 committed by Mihai Tudor Panu
parent 5e37830bb7
commit bf82beaf9c
11 changed files with 1005 additions and 0 deletions

View File

@ -232,6 +232,10 @@ if (OPENZWAVE_FOUND)
endif()
add_example (nlgpio16)
add_example (ads1x15)
if (MODBUS_FOUND)
include_directories(${MODBUS_INCLUDE_DIRS})
add_example (t3311)
endif()
# These are special cases where you specify example binary, source file and module(s)
include_directories (${PROJECT_SOURCE_DIR}/src)

115
examples/c++/t3311.cxx Normal file
View File

@ -0,0 +1,115 @@
/*
* 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 <iostream>
#include <signal.h>
#include "t3311.h"
using namespace std;
bool shouldRun = true;
void sig_handler(int signo)
{
if (signo == SIGINT)
shouldRun = false;
}
int main(int argc, char **argv)
{
signal(SIGINT, sig_handler);
//! [Interesting]
string defaultDev = "/dev/ttyUSB0";
// if an argument was specified, use it as the device instead
if (argc > 1)
defaultDev = string(argv[1]);
cout << "Initializing..." << endl;
// Instantiate an T3311 instance, using MODBUS slave address 1, and
// default comm parameters (9600, 8, N, 2)
upm::T3311 *sensor = new upm::T3311(defaultDev, 1);
// output the serial number and firmware revision
cout << "Serial Number: " << sensor->getSerialNumber() << endl;
cout << "Firmware Revision: " << sensor->getFirmwareMajor()
<< "." << sensor->getFirmwareMinor() << endl;
cout << endl;
// update and print available values every second
while (shouldRun)
{
// update our values from the sensor
sensor->update();
// we show both C and F for temperature
cout << "Temperature: " << sensor->getTemperature()
<< " C / " << sensor->getTemperature(true) << " F"
<< endl;
cout << "Humidity: " << sensor->getHumidity()
<< " %" << endl;
// this value depends on the sensor configuration -- by default
// it is the dew point temperature
cout << "Computed Value: " << sensor->getComputedValue() << endl;
// with FW revisions > 2.44, extended computed data is available
if (sensor->extendedDataAvailable())
{
cout << "Dew Point Temperature: " << sensor->getDewPointTemperature()
<< " C / " << sensor->getDewPointTemperature(true) << " F"
<< endl;
cout << "Absolute Humidity: " << sensor->getAbsoluteHumidity()
<< " g/m3" << endl;
cout << "Specific Humidity: " << sensor->getSpecificHumidity()
<< " g/kg" << endl;
cout << "Mixing Ratio: " << sensor->getMixingRatio()
<< " g/kg" << endl;
cout << "Specific Enthalpy: " << sensor->getSpecificEnthalpy()
<< " kJ/kg" << endl;
}
cout << endl;
sleep(1);
}
cout << "Exiting..." << endl;
delete sensor;
//! [Interesting]
return 0;
}

View File

@ -0,0 +1,101 @@
/*jslint node:true, vars:true, bitwise:true, unparam:true */
/*jshint unused:true */
/*
* 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.
*/
var sensorObj = require('jsupm_t3311');
/************** Main code **************/
var defaultDev = "/dev/ttyUSB0";
// if an argument was specified, use it as the device instead
if (process.argv.length > 2)
{
defaultDev = process.argv[2];
}
console.log("Initializing...");
// Instantiate an T3311 instance, using MODBUS slave address 1, and
// default comm parameters (9600, 8, N, 2)
var sensor = new sensorObj.T3311(defaultDev, 1);
// output the serial number and firmware revision
console.log("Serial Number:", sensor.getSerialNumber());
console.log("Firmware Revision:", sensor.getFirmwareMajor() + "." +
sensor.getFirmwareMinor());
console.log("");
// update and print available values every second
setInterval(function()
{
// update our values from the sensor
sensor.update();
// we show both C and F for temperature
console.log("Temperature:", sensor.getTemperature(),
"C /", sensor.getTemperature(true), "F");
console.log("Humidity:", sensor.getHumidity(), "%");
// this value depends on the sensor configuration -- by default
// it is the dew point temperature
console.log("Computed Value:", sensor.getComputedValue());
// with FW revisions > 2.44, extended computed data is available
if (sensor.extendedDataAvailable())
{
console.log("Dew Point Temperature:", sensor.getDewPointTemperature(),
"C /", sensor.getDewPointTemperature(true), "F");
console.log("Absolute Humidity:", sensor.getAbsoluteHumidity(),
"g/m3");
console.log("Specific Humidity:", sensor.getSpecificHumidity(),
"g/kg");
console.log("Mixing Ratio:", sensor.getMixingRatio(),
"g/kg");
console.log("Specific Enthalpy:", sensor.getSpecificEnthalpy(),
"kJ/kg");
}
console.log("");
}, 1000);
process.on('SIGINT', function()
{
sensor = null;
sensorObj.cleanUp();
sensorObj = null;
console.log("Exiting...");
process.exit(0);
});

90
examples/python/t3311.py Normal file
View File

@ -0,0 +1,90 @@
#!/usr/bin/python
# 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.
import time, sys, signal, atexit
import pyupm_t3311 as sensorObj
## Exit handlers ##
# This function stops python from printing a stacktrace when you hit control-C
def SIGINTHandler(signum, frame):
raise SystemExit
# This function lets you run code on exit
def exitHandler():
print "Exiting"
sys.exit(0)
# Register exit handlers
atexit.register(exitHandler)
signal.signal(signal.SIGINT, SIGINTHandler)
defaultDev = "/dev/ttyUSB0"
# if an argument was specified, use it as the device instead
if (len(sys.argv) > 1):
defaultDev = sys.argv[1]
print "Initializing..."
# Instantiate an T3311 instance, using MODBUS slave address 1, and
# default comm parameters (9600, 8, N, 2)
sensor = sensorObj.T3311(defaultDev, 1)
# output the serial number and firmware revision
print "Serial Number:", sensor.getSerialNumber()
print "Firmware Revision: {0}.{1}".format(sensor.getFirmwareMajor(),
sensor.getFirmwareMinor())
print
# update and print available values every second
while (1):
# update our values from the sensor
sensor.update()
# we show both C and F for temperature
print "Temperature:", sensor.getTemperature(), "C /",
print sensor.getTemperature(True), "F"
print "Humidity:", sensor.getHumidity(), "%"
# this value depends on the sensor configuration -- by default
# it is the dew point temperature
print "Computed Value:", sensor.getComputedValue()
# with FW revisions > 2.44, extended computed data is available
if (sensor.extendedDataAvailable()):
print "Dew Point Temperature:", sensor.getDewPointTemperature(),
print "C /", sensor.getDewPointTemperature(True), "F"
print "Absolute Humidity:", sensor.getAbsoluteHumidity(), "g/m3"
print "Specific Humidity:", sensor.getSpecificHumidity(),
print "g/kg"
print "Mixing Ratio:", sensor.getMixingRatio(), "g/kg"
print "Specific Enthalpy:", sensor.getSpecificEnthalpy(),
print "kJ/kg"
print
time.sleep(1)

21
src/t3311/CMakeLists.txt Normal file
View File

@ -0,0 +1,21 @@
set (libname "t3311")
set (libdescription "upm module for the Comet System T3311")
set (module_src ${libname}.cxx)
set (module_h ${libname}.h)
pkg_search_module(MODBUS libmodbus)
if (MODBUS_FOUND)
set (reqlibname "libmodbus")
include_directories(${MODBUS_INCLUDE_DIRS})
upm_module_init()
add_dependencies(${libname} ${MODBUS_LIBRARIES})
target_link_libraries(${libname} ${MODBUS_LIBRARIES})
if (BUILDSWIG)
if (BUILDSWIGNODE)
swig_link_libraries (jsupm_${libname} ${MODBUS_LIBRARIES} ${MRAA_LIBRARIES} ${NODE_LIBRARIES})
endif()
if (BUILDSWIGPYTHON)
swig_link_libraries (pyupm_${libname} ${MODBUS_LIBRARIES} ${PYTHON_LIBRARIES} ${MRAA_LIBRARIES})
endif()
endif()
endif ()

23
src/t3311/javaupm_t3311.i Normal file
View File

@ -0,0 +1,23 @@
%module javaupm_t3311
%include "../upm.i"
%include "typemaps.i"
%include "cpointer.i"
%include "arrays_java.i";
%include "../java_buffer.i"
%{
#include "t3311.h"
%}
%include "t3311.h"
%pragma(java) jniclasscode=%{
static {
try {
System.loadLibrary("javaupm_t3311");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load. \n" + e);
System.exit(1);
}
}
%}

11
src/t3311/jsupm_t3311.i Normal file
View File

@ -0,0 +1,11 @@
%module jsupm_t3311
%include "../upm.i"
%include "stdint.i"
%include "cpointer.i"
%pointer_functions(float, floatp);
%include "t3311.h"
%{
#include "t3311.h"
%}

15
src/t3311/pyupm_t3311.i Normal file
View File

@ -0,0 +1,15 @@
// Include doxygen-generated documentation
%include "pyupm_doxy2swig.i"
%module pyupm_t3311
%include "../upm.i"
%include "stdint.i"
%include "cpointer.i"
%feature("autodoc", "3");
%pointer_functions(float, floatp);
%include "t3311.h"
%{
#include "t3311.h"
%}

309
src/t3311/t3311.cxx Normal file
View File

@ -0,0 +1,309 @@
/*
* 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 <iostream>
#include <stdexcept>
#include <string>
#include <sstream>
#include <pthread.h>
#include "t3311.h"
using namespace upm;
using namespace std;
// conversion from fahrenheit to celcius and back
static float f2c(float f)
{
return ((f - 32.0) / (9.0 / 5.0));
}
static float c2f(float c)
{
return (c * (9.0 / 5.0) + 32.0);
}
// conversion from 1-byte BCD to decimal
static uint8_t bcd2dec(uint8_t bcd)
{
return (bcd / 16 * 10) + (bcd % 16);
}
T3311::T3311(std::string device, int address, int baud, int bits, char parity,
int stopBits) :
m_mbContext(0)
{
// check some of the parameters
if (!(bits == 7 || bits == 8))
{
throw std::out_of_range(std::string(__FUNCTION__) +
": bits must be 7 or 8");
}
if (!(parity == 'N' || parity == 'E' || parity == 'O'))
{
throw std::out_of_range(std::string(__FUNCTION__) +
": parity must be 'N', 'O', or 'E'");
}
if (!(stopBits == 1 || stopBits == 2))
{
throw std::out_of_range(std::string(__FUNCTION__) +
": stopBits must be 1 or 2");
}
m_temperature = 0.0;
m_humidity = 0.0;
m_computedValue = 0.0;
m_dewPointTemperature = 0.0;
m_absoluteHumidity = 0.0;
m_specificHumidity = 0.0;
m_mixingRatio = 0.0;
m_specificEnthalpy = 0.0;
// addresses are only 8bits wide
address &= 0xff;
// now, open/init the device and modbus context
if (!(m_mbContext = modbus_new_rtu(device.c_str(), baud, parity, bits,
stopBits)))
{
throw std::runtime_error(std::string(__FUNCTION__) +
": modbus_new_rtu() failed");
}
// set the slave address of the device we want to talk to
if (modbus_set_slave(m_mbContext, address))
{
throw std::runtime_error(std::string(__FUNCTION__) +
": modbus_set_slave() failed");
}
// set the serial mode
modbus_rtu_set_serial_mode(m_mbContext, MODBUS_RTU_RS232);
// now connect..
if (modbus_connect(m_mbContext))
{
throw std::runtime_error(std::string(__FUNCTION__) +
": modbus_connect() failed");
}
// This is a bit of a hack. The device uses bus power, which isn't
// provided unless the device has been opened and accessed. As a
// result, register reads will usually fail the first time the
// device is accessed after a power cycle. Here, we read the
// temperature value (which will most likely fail), then sleep,
// allowing the sensor to "boot". The datasheet says it takes at
// about 2 seconds to boot, we will wait for 5.
uint16_t tmp;
modbus_read_input_registers(m_mbContext, REG_TEMPERATURE, 1, &tmp);
// sleep for 5 seconds to give time for device to powerup and boot
sleep(5);
// turn off debugging
setDebug(false);
// now read the UNIT_SETTING reg to see what units we are getting
// our temperature data in.
tmp = readInputReg(REG_UNIT_SETTINGS);
if (tmp & 0x0001)
m_isCelcius = false;
else
m_isCelcius = true;
// read in the the FW_LO register (BCD encoded) and convert
tmp = readInputReg(REG_FW_LO);
// HI byte (major)
m_fwRevHi = (tmp >> 8) & 0xff;
m_fwRevHi = bcd2dec(m_fwRevHi);
// LO byte (minor)
m_fwRevLo = (tmp & 0xff);
m_fwRevLo = bcd2dec(m_fwRevLo);
if (m_fwRevHi >= 2 && m_fwRevLo >= 44)
m_isExtendedDataAvailable = true;
else
m_isExtendedDataAvailable = false;
// now get the serial number (BCD encoded 4-byte value, which we
// will pack into a string)
stringstream preformat;
uint8_t b;
// LO (but really HI)
tmp = readInputReg(REG_SERIAL_LO);
b = bcd2dec((tmp & 0xff00) >> 8);
preformat << int(b);
b = bcd2dec(tmp & 0x00ff);
preformat << int(b);
// HI (but really LO)
tmp = readInputReg(REG_SERIAL_HI);
b = bcd2dec((tmp & 0xff00) >> 8);
preformat << int(b);
b = bcd2dec(tmp & 0x00ff);
preformat << int(b);
m_serialNumber = preformat.str();
}
T3311::~T3311()
{
if (m_mbContext)
{
modbus_close(m_mbContext);
modbus_free(m_mbContext);
}
}
uint16_t T3311::readInputReg(int reg)
{
uint16_t val;
if (modbus_read_input_registers(m_mbContext, reg, 1, &val) <= 0)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": modbus_read_input_registers() failed");
}
return val;
}
int T3311::readInputRegs(int reg, int len, uint16_t *buf)
{
int rv;
if ((rv = modbus_read_input_registers(m_mbContext, reg, len, buf)) < 0)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": modbus_read_input_registers() failed");
}
return rv;
}
void T3311::update()
{
static const int dataLen = 9;
uint16_t data[dataLen];
// we read the 9 registers starting at the temperature
if (readInputRegs(REG_TEMPERATURE, dataLen, data) != dataLen)
{
throw std::runtime_error(std::string(__FUNCTION__) +
": read less than the expected 9 registers");
}
// temperature first, we always store as C
float tmpF = float((int16_t)data[0]) / 10.0;
if (m_isCelcius)
m_temperature = tmpF;
else
m_temperature = f2c(tmpF);
m_humidity = float((int16_t)data[1]) / 10.0;
m_computedValue = float((int16_t)data[2]) / 10.0;
// skip data[3], (pressure) as this device does not support it
// if extended info is supported, grab those too
if (extendedDataAvailable())
{
// we always store temps in C
tmpF = float((int16_t)data[4]) / 10.0;
if (m_isCelcius)
m_dewPointTemperature = tmpF;
else
m_dewPointTemperature = f2c(tmpF);
m_absoluteHumidity = float((int16_t)data[5]) / 10.0;
m_specificHumidity = float((int16_t)data[6]) / 10.0;
m_mixingRatio = float((int16_t)data[7]) / 10.0;
m_specificEnthalpy = float((int16_t)data[8]) / 10.0;
}
}
float T3311::getTemperature(bool fahrenheit)
{
if (fahrenheit)
return c2f(m_temperature);
else
return m_temperature;
}
float T3311::getHumidity()
{
return m_humidity;
}
float T3311::getComputedValue()
{
return m_computedValue;
}
float T3311::getDewPointTemperature(bool fahrenheit)
{
if (fahrenheit)
return c2f(m_dewPointTemperature);
else
return m_dewPointTemperature;
}
float T3311::getAbsoluteHumidity()
{
return m_absoluteHumidity;
}
float T3311::getSpecificHumidity()
{
return m_specificHumidity;
}
float T3311::getMixingRatio()
{
return m_mixingRatio;
}
float T3311::getSpecificEnthalpy()
{
return m_specificEnthalpy;
}
void T3311::setDebug(bool enable)
{
m_debugging = enable;
if (enable)
modbus_set_debug(m_mbContext, 1);
else
modbus_set_debug(m_mbContext, 0);
}

310
src/t3311/t3311.h Normal file
View File

@ -0,0 +1,310 @@
/*
* 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 <string>
#include <modbus/modbus.h>
namespace upm {
/**
* @brief T3311 Temperature and Humidity Sensor
* @defgroup t3311 libupm-t3311
* @ingroup uart temp
*/
/**
* @library t3311
* @sensor t3311
* @comname UPM API for the T3311 Temperature and Humidity Sensor
* @type temp
* @man comet
* @con uart
* @web http://www.cometsystem.com/products/reg-T3311
*
* @brief UPM API for the T3311 MODBUS Temperature and Humidity Sensor
*
* This module implements support for the Comet System T3311
* Temperature and Humidity transmitter. It uses MODBUS over an
* RS232 serial port. You must have libmodbus v3.1.2 (or greater)
* installed to compile and use this driver.
*
* This module was developed using libmodbus 3.1.2, and T3311
* Firmware revison 2.66 connected via a Prolific RS232 Serial to
* USB adaptor. You cannot use the built in TTL UART pins for
* accessing this device -- you must use a full serial RS232
* interface connected via USB.
*
* @snippet t3311.cxx Interesting
*/
class T3311 {
public:
// MODBUS input registers
typedef enum {
REG_TEMPERATURE = 0x0030,
REG_HUMIDITY = 0x0031,
// This value is configured in the device itself. By default,
// it represents the Dew Point Temperature. Use the
// configuration utility from Comet to adjust the configuration.
REG_COMPUTED = 0x0032,
// available in devices with FW > 2.44
REG_DEW_POINT = 0x0034,
REG_ABS_HUMIDITY = 0x0035,
REG_SPECIFIC_HUMIDITY = 0x0036,
REG_MIXING_RATIO = 0x0037,
REG_SPECIFIC_ENTHALPY = 0x0038,
// 32 bit serial number. These appear to be reversed when
// comparing against the TSensor config utility, so the
// datasheet is probably wrong.
REG_SERIAL_HI = 0x1034,
REG_SERIAL_LO = 0x1035,
// this is 'somewhat' documented (middle of page 15 in the
// Advantech-ADAM standard section) in the "Description of
// communications protocols of TXXXX series" document. We use
// it to simply detect whether the device is configured for
// Celcius or Fahrenheit data and compensate internally.
REG_UNIT_SETTINGS = 0x203F,
// firmware revision, BCD byte encoded. We only care about the
// LO word - the HI word just contains the manufacturing date.
REG_FW_HI = 0x3000,
REG_FW_LO = 0x3001
} REGS_T;
/**
* T3311 constructor
*
* @param device Path to the serial device
* @param address The MODBUS slave address
* @param baud The baudrate of the device. Default: 9600
* @param bits The number of bits per byte. Default: 8
* @param parity The parity of the connection, 'N' for None, 'E'
* for Even, 'O' for Odd. Default: 'N'
* @param stopBits The number of stop bits. Default: 2
*/
T3311(std::string device, int address, int baud=9600, int bits=8,
char parity='N', int stopBits=2);
/**
* T3311 Destructor
*/
~T3311();
/**
* Indicate whether the attached sensor supports extended Computed
* Data registers. Firmware versions at, or higher than 2.44
* provide this data.
*
* @return true if Extended Data is available, false otherwise
*/
bool extendedDataAvailable()
{
return m_isExtendedDataAvailable;
};
/**
* Read current values from the sensor and update internal stored
* values. This method must be called prior to querying any
* values, such as temperature or humidity.
*/
void update();
/**
* Get the current temperature. update() must have been called
* prior to calling this method.
*
* @param fahrenheit true to return the temperature in degrees
* fahrenheit, false to return the temperature in degrees celcius.
* The default is false (degrees Celcius).
* @return The last temperature reading in Celcius or Fahrenheit
*/
float getTemperature(bool fahrenheit=false);
/**
* Get the current relative humidity. update() must have been called
* prior to calling this method.
*
* @return The last humidity reading
*/
float getHumidity();
/**
* Get the current computed value. update() must have been
* called prior to calling this method. This value is configured
* via the configuration of the sensor using the sensors
* configuration utility, and can represent several different
* computed values. The default value from the factory is the
* current Dew Point Temperature.
*
* Since the actual value configured is unknown (and unknowable)
* to this driver, the units represented depend on how you have
* configured the device. This function simply returns the value
* without any conversion or interpretation, other than the
* default scaling.
*
* @return The last Computed Value
*/
float getComputedValue();
/**
* Get the current dew point temperature. update() must have been
* called prior to calling this method. This information is only
* available if the sensor supports Extended Data (ie:
* extendedDataAvailable() returns true).
*
* @param fahrenheit true to return the temperature in degrees
* fahrenheit, false to return the temperature in degrees celcius.
* The default is false (degrees Celcius).
* @return The last dew point temperature reading in Celcius or
* Fahrenheit
*/
float getDewPointTemperature(bool fahrenheit=false);
/**
* Get the current absolute humidity. update() must have been
* called prior to calling this method. This information is only
* available if the sensor supports Extended Data (ie:
* extendedDataAvailable() returns true).
*
* @return The last absolute humidity reading in g/m3 (grams per
* cubic meter).
*/
float getAbsoluteHumidity();
/**
* Get the current specific humidity. update() must have been
* called prior to calling this method. This information is only
* available if the sensor supports Extended Data (ie:
* extendedDataAvailable() returns true).
*
* @return The last specific humidity reading in g/kg (grams per
* kilogram).
*/
float getSpecificHumidity();
/**
* Get the current mixing ratio. update() must have been
* called prior to calling this method. This information is only
* available if the sensor supports Extended Data (ie:
* extendedDataAvailable() returns true).
*
* @return The last mixing ratio reading in g/kg (grams per
* kilogram).
*/
float getMixingRatio();
/**
* Get the current specific enthalopy, a measure of energy
* density. update() must have been called prior to calling this
* method. This information is only available if the sensor
* supports Extended Data (ie: extendedDataAvailable() returns
* true).
*
* @return The last specific enthalopy reading in kJ/kg
* (kilojoules per kilogram).
*/
float getSpecificEnthalpy();
/**
* Get the serial number of the sensor.
*
* @return The serial number
*/
std::string getSerialNumber()
{
return m_serialNumber;
};
/**
* Get the firmware revision major number.
*
* @return The firmware revsion major number.
*/
int getFirmwareMajor()
{
return m_fwRevHi;
};
/**
* Get the firmware revision minor number.
*
* @return The firmware revsion minor number.
*/
int getFirmwareMinor()
{
return m_fwRevLo;
};
/**
* Enable or disable debugging output. This primarily enables and
* disables libmodbus debugging output.
*
* @param enable true to enable debugging, false otherwise
*/
void setDebug(bool enable);
protected:
uint16_t readInputReg(int reg);
int readInputRegs(int reg, int len, uint16_t *buf);
// MODBUS context
modbus_t *m_mbContext;
// is the device reporting in C or F?
bool m_isCelcius;
// Is the device FW > than 2.44?
bool m_isExtendedDataAvailable;
int m_fwRevHi;
int m_fwRevLo;
std::string m_serialNumber;
private:
bool m_debugging;
// data
float m_temperature;
float m_humidity; // relative
float m_computedValue;
// with FW versions > 2.44, these other computed values are
// available.
float m_dewPointTemperature;
float m_absoluteHumidity;
float m_specificHumidity;
float m_mixingRatio;
float m_specificEnthalpy;
};
}

View File

@ -284,6 +284,12 @@
* @ingroup byman
*/
/**
* @brief Comet System
* @defgroup comet Comet
* @ingroup byman
*/
/**
* @brief EpicTinker
* @defgroup epict EpicTinker