mirror of
https://github.com/eclipse/upm.git
synced 2025-07-06 20:01:12 +03:00
Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
d355f76226 | |||
4f6be750c7 | |||
bf7d7d1bda | |||
9acc752074 | |||
b6b7d892c2 | |||
1ca8d100ea | |||
96f1afffe3 | |||
899d873cbc | |||
dc8be495a9 | |||
c7b5204fe4 | |||
527615758a | |||
16b6fcf807 | |||
5a9f234a3e | |||
c7bd37b322 | |||
edcaed90e6 | |||
655ccee9af | |||
102d86870a | |||
a88ec4237d | |||
cf2b8c9a6e | |||
68aa067f82 | |||
24062f6a9d | |||
db8d708798 | |||
edfdf6ec34 | |||
7c66d5c321 | |||
0e365590c4 | |||
ba127ec4d4 | |||
b6572e1f28 | |||
02974f242e | |||
e809016152 |
@ -15,17 +15,17 @@ message (INFO " found mraa version: ${MRAA_VERSION}")
|
||||
|
||||
# Appends the cmake/modules path to MAKE_MODULE_PATH variable.
|
||||
set (CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH})
|
||||
set (LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}" CACHE PATH "Installation path for libraries")
|
||||
|
||||
# Set CMAKE_LIB_INSTALL_DIR if not defined
|
||||
# Set CMAKE_INSTALL_LIBDIR if not defined
|
||||
include(GNUInstallDirs)
|
||||
set (LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}" CACHE PATH "Installation path for libraries")
|
||||
|
||||
# Make a version file containing the current version from git.
|
||||
include (GetGitRevisionDescription)
|
||||
git_describe (VERSION "--tags")
|
||||
if ("x_${VERSION}" STREQUAL "x_GIT-NOTFOUND" OR "x_${VERSION}" STREQUAL "x_-128-NOTFOUND")
|
||||
message (WARNING " - Install git to compile a production UPM!")
|
||||
set (VERSION "v0.6.0-dirty")
|
||||
set (VERSION "v0.6.2-dirty")
|
||||
endif ()
|
||||
|
||||
message (INFO " - UPM Version ${VERSION}")
|
||||
@ -126,7 +126,6 @@ if (BUILDDOC)
|
||||
string (REPLACE "." ";" PYTHON_VERSION_LIST ${PYTHONLIBS_VERSION_STRING})
|
||||
list (GET PYTHON_VERSION_LIST 0 PYTHON_VERSION_MAJOR)
|
||||
list (GET PYTHON_VERSION_LIST 1 PYTHON_VERSION_MINOR)
|
||||
set (SITE_PACKAGES ${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages)
|
||||
configure_file (${CMAKE_CURRENT_SOURCE_DIR}/doxy/conf.py.in ${CMAKE_CURRENT_BINARY_DIR}/pydoc/conf.py @ONLY)
|
||||
configure_file (${CMAKE_CURRENT_SOURCE_DIR}/doxy/index.rst ${CMAKE_CURRENT_BINARY_DIR}/pydoc/index.rst COPYONLY)
|
||||
add_custom_target (pydoc ALL
|
||||
@ -153,9 +152,9 @@ if (BUILDDOC)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxy/node/${JSDOC_FILE} ${CMAKE_CURRENT_BINARY_DIR}/${JSDOC_FILE} COPYONLY)
|
||||
endforeach()
|
||||
add_custom_target(jsdoc ALL
|
||||
COMMAND ${NODE_EXECUTABLE} docgen -m upm -i xml -t ${CMAKE_CURRENT_SOURCE_DIR}/src -g ../../
|
||||
COMMAND ${NODEJS_EXECUTABLE} docgen -m upm -i xml -t ${CMAKE_CURRENT_SOURCE_DIR}/src -g ../../
|
||||
COMMAND ${YUIDOC_EXECUTABLE} -C --no-sort --helpers generators/yuidoc/helper.js --themedir generators/yuidoc/tmpl -o html/node jsdoc/yuidoc/upm
|
||||
COMMAND ${NODE_EXECUTABLE} tolower -i html/node
|
||||
COMMAND ${NODEJS_EXECUTABLE} tolower -i html/node
|
||||
DEPENDS doc
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMENT "Generating API documentation with Yuidoc" VERBATIM
|
||||
@ -206,12 +205,17 @@ if (RPM)
|
||||
set(CPACK_PACKAGE_VERSION ${VERSION})
|
||||
set(CPACK_GENERATOR "RPM")
|
||||
set(CPACK_PACKAGE_NAME "upm")
|
||||
set(upm_PACKAGE_ON_TAG ".")
|
||||
if ("${VERSION_COMMIT}" STREQUAL "")
|
||||
set(upm_PACKAGE_ON_TAG "")
|
||||
endif()
|
||||
set(CPACK_PACKAGE_VERSION
|
||||
"${upm_VERSION_MAJOR}.${upm_VERSION_MINOR}.${upm_VERSION_PATCH}.${upm_PACKAGE_ON_TAG}${VERSION_COMMIT}")
|
||||
"${upm_VERSION_MAJOR}.${upm_VERSION_MINOR}.${upm_VERSION_PATCH}${upm_PACKAGE_ON_TAG}${VERSION_COMMIT}")
|
||||
set(CPACK_PACKAGE_CONTACT "Intel IoT-Devkit")
|
||||
set(CPACK_PACKAGE_VENDOR "Intel IoT-Devkit")
|
||||
set(CPACK_RPM_PACKAGE_REQUIRES "mraa >= ${MRAA_VERSION}")
|
||||
set(CPACK_RPM_PACKAGE_PROVIDES "${CPACK_PACKAGE_NAME}-devel")
|
||||
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
|
||||
EXECUTE_PROCESS(COMMAND rpm --showrc
|
||||
COMMAND grep -E "dist[[:space:]]*\\."
|
||||
COMMAND sed -e "s/^.*dist\\s*\\.//"
|
||||
|
@ -114,6 +114,15 @@ API Documentation
|
||||
<a href="http://iotdk.intel.com/docs/master/upm/python"><img src="docs/icons/python.png"/></a>
|
||||
<a href="http://iotdk.intel.com/docs/master/upm/node"><img src="docs/icons/node.png"/></a>
|
||||
|
||||
### API Compatibility
|
||||
Even if we try our best not to, every once in a while we are forced to modify
|
||||
our API in a way that will break backwards compatibility. If you find yourself
|
||||
unable to compile code that was working fine before a library update, make sure
|
||||
you check the [API changes](docs/apichanges.md) section first.
|
||||
|
||||
**NOTE** - Our **C++ header files** will change their extension from *.h* to
|
||||
*.hpp* in the upcoming version.
|
||||
|
||||
### Changelog
|
||||
Version changelog [here](docs/changelog.md).
|
||||
|
||||
|
@ -94,4 +94,4 @@ if (NODEJS_EXECUTABLE)
|
||||
mark_as_advanced (NODEJS_EXECUTABLE)
|
||||
endif ()
|
||||
|
||||
mark_as_advanced (NODE_EXECUTABLE)
|
||||
mark_as_advanced (NODEJS_EXECUTABLE)
|
||||
|
20
docs/apichanges.md
Normal file
20
docs/apichanges.md
Normal file
@ -0,0 +1,20 @@
|
||||
API Changes {#apichanges}
|
||||
===============
|
||||
|
||||
**IMPORTANT NOTICE**
|
||||
|
||||
Our **C++ header files** will change their extension from *.h* to *.hpp*. This
|
||||
change is anticipated in the upcoming version and unfortunately will break
|
||||
source compatibility with previous versions of UPM for every library. You will
|
||||
need to update your code and change to the new extension format in your
|
||||
`#include` directives.
|
||||
|
||||
Here's a list of other API changes made to the library that break source/binary
|
||||
compatibility between releases:
|
||||
|
||||
* **my9221**, **groveledbar** and **grovecircularled** are now all part of the
|
||||
same library (my9221) and new functionality was added going to v.0.5.1
|
||||
* **stepmotor** driver API was changed significantly from v.0.4.1 to v.0.5.0
|
||||
* **eboled** library was greatly improved in version 0.4.0 and the `draw()`
|
||||
function was removed in favor of a more complete GFX library implementation
|
||||
|
@ -4,6 +4,25 @@ Changelog {#changelog}
|
||||
Here's a list summarizing some of the key undergoing changes to our library
|
||||
from earlier versions:
|
||||
|
||||
### v0.6.2
|
||||
|
||||
* Added a generic driver for taking snapshots from an USB camera device
|
||||
* New API changes section in documentation to let users know when the UPM API
|
||||
gets modified
|
||||
* Fixed some spelling errors and improved JavaScript documentation builds with
|
||||
newer versions of YUI and Node
|
||||
* Enhanced Cmake scripts and the build process
|
||||
* New sensors: vcap, e50hx
|
||||
|
||||
### v0.6.1
|
||||
|
||||
* Fixed library build process for different configurations across multiple
|
||||
environments reported by users.
|
||||
* Fixed multiple GFX library header clash and improved SSD1351 compatibility
|
||||
by changing SPI mode
|
||||
* Added Node and Python array typemaps for nrf24l01
|
||||
* Added 2 new JAVA examples
|
||||
|
||||
### v0.6.0
|
||||
|
||||
* Introduced C++ Interfaces for several sensor categories that will help
|
||||
|
@ -258,6 +258,13 @@ add_example (smartdrive)
|
||||
if (HAVE_FIRMATA)
|
||||
add_example (curieimu)
|
||||
endif ()
|
||||
if (BACNET_FOUND)
|
||||
include_directories(${BACNET_INCLUDE_DIRS})
|
||||
# we need access to bacnetmstp headers too
|
||||
include_directories(${PROJECT_SOURCE_DIR}/src/bacnetmstp)
|
||||
add_example (e50hx)
|
||||
endif()
|
||||
add_example (vcap)
|
||||
|
||||
# These are special cases where you specify example binary, source file and module(s)
|
||||
include_directories (${PROJECT_SOURCE_DIR}/src)
|
||||
|
@ -286,7 +286,7 @@ int main()
|
||||
else ads->setCompMode();
|
||||
break;
|
||||
case 18:
|
||||
cout << ads->getCompLatch() << cout;
|
||||
cout << ads->getCompLatch() << endl;
|
||||
break;
|
||||
case 19:
|
||||
cout << "select one of the following:" << endl;
|
||||
@ -296,7 +296,7 @@ int main()
|
||||
else ads->setCompLatch();
|
||||
break;
|
||||
case 20:
|
||||
cout << ads->getContinuous() << cout;
|
||||
cout << ads->getContinuous() << endl;
|
||||
break;
|
||||
case 21:
|
||||
cout << "select one of the following:" << endl;
|
||||
|
112
examples/c++/e50hx.cxx
Normal file
112
examples/c++/e50hx.cxx
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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 "e50hx.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace upm;
|
||||
|
||||
bool shouldRun = true;
|
||||
|
||||
void sig_handler(int signo)
|
||||
{
|
||||
if (signo == SIGINT)
|
||||
shouldRun = false;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
signal(SIGINT, sig_handler);
|
||||
|
||||
//! [Interesting]
|
||||
// You will need to edit this example to conform to your site and your
|
||||
// devices, specifically the Device Object Instance ID passed to the
|
||||
// constructor, and the arguments to initMaster() that are
|
||||
// appropriate for your BACnet network.
|
||||
|
||||
string defaultDev = "/dev/ttyUSB0";
|
||||
|
||||
// if an argument was specified, use it as the device instead
|
||||
if (argc > 1)
|
||||
defaultDev = string(argv[1]);
|
||||
|
||||
cout << "Using device " << defaultDev << endl;
|
||||
cout << "Initializing..." << endl;
|
||||
|
||||
// Instantiate an E50HX object for an E50HX device that has 1075425
|
||||
// as it's unique Device Object Instance ID. NOTE: You will
|
||||
// certainly want to change this to the correct value for your
|
||||
// device(s).
|
||||
E50HX *sensor = new E50HX(1075425);
|
||||
|
||||
// Initialize our BACnet master, if it has not already been
|
||||
// initialized, with the device and baudrate, choosing 1000001 as
|
||||
// our unique Device Object Instance ID, 2 as our MAC address and
|
||||
// using default values for maxMaster and maxInfoFrames
|
||||
sensor->initMaster(defaultDev, 38400, 1000001, 2);
|
||||
|
||||
// Uncomment to enable debugging output
|
||||
// sensor->setDebug(true);
|
||||
|
||||
cout << endl;
|
||||
cout << "Device Description: " << sensor->getDescription() << endl;
|
||||
cout << "Device Location: " << sensor->getLocation() << endl;
|
||||
cout << endl;
|
||||
|
||||
// update and print a few values every 5 seconds
|
||||
while (shouldRun)
|
||||
{
|
||||
cout << "System Voltage: "
|
||||
<< sensor->getAnalogValue(E50HX::AV_System_Voltage)
|
||||
<< " " << sensor->getAnalogValueUnits(E50HX::AV_System_Voltage)
|
||||
<< endl;
|
||||
|
||||
cout << "System Type: "
|
||||
<< sensor->getAnalogValue(E50HX::AV_System_Type)
|
||||
<< endl;
|
||||
|
||||
cout << "Energy Consumption: " << sensor->getAnalogInput(E50HX::AI_Energy)
|
||||
<< " " << sensor->getAnalogInputUnits(E50HX::AI_Energy)
|
||||
<< endl;
|
||||
|
||||
cout << "Power Up Counter: "
|
||||
<< sensor->getAnalogInput(E50HX::AI_Power_Up_Count)
|
||||
<< endl;
|
||||
|
||||
cout << endl;
|
||||
sleep(5);
|
||||
}
|
||||
|
||||
cout << "Exiting..." << endl;
|
||||
|
||||
delete sensor;
|
||||
|
||||
//! [Interesting]
|
||||
|
||||
return 0;
|
||||
}
|
@ -135,7 +135,7 @@ int main (int argc, char **argv)
|
||||
if (rv > 0)
|
||||
cout << "Received: " << radioBuffer << endl;
|
||||
|
||||
if (rv < 0) // some sort of read error occured
|
||||
if (rv < 0) // some sort of read error occurred
|
||||
{
|
||||
cerr << "Port read error." << endl;
|
||||
break;
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "ssd1306.h"
|
||||
|
||||
#define DEVICE_ADDRESS 0x3C
|
||||
#define BUS_NUMBER 0x6
|
||||
#define BUS_NUMBER 0x0
|
||||
|
||||
static uint8_t intel_logo[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
@ -77,7 +77,7 @@ int main (int argc, char **argv)
|
||||
if (rv > 0)
|
||||
write(1, nmeaBuffer, rv);
|
||||
|
||||
if (rv < 0) // some sort of read error occured
|
||||
if (rv < 0) // some sort of read error occurred
|
||||
{
|
||||
cerr << "Port read error." << endl;
|
||||
break;
|
||||
|
70
examples/c++/vcap.cxx
Normal file
70
examples/c++/vcap.cxx
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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 "vcap.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
//! [Interesting]
|
||||
|
||||
string defaultDev = "/dev/video0";
|
||||
|
||||
// if an argument was specified, use it as the device instead
|
||||
if (argc > 1)
|
||||
defaultDev = string(argv[1]);
|
||||
|
||||
cout << "Using device " << defaultDev << endl;
|
||||
cout << "Initializing..." << endl;
|
||||
|
||||
// Instantiate an VCAP instance, using the specified video device
|
||||
upm::VCAP *sensor = new upm::VCAP(defaultDev);
|
||||
|
||||
// enable some debug/verbose output
|
||||
sensor->setDebug(true);
|
||||
|
||||
// This is just a hint. The kernel can change this to a lower
|
||||
// resolution that the hardware supports. Use getWidth() and
|
||||
// getHeight() methods to see what the kernel actually chose if you
|
||||
// care.
|
||||
sensor->setResolution(1920, 1080);
|
||||
|
||||
// capture an image
|
||||
sensor->captureImage();
|
||||
|
||||
// convert and save it as a jpeg
|
||||
sensor->saveImage("video-img1.jpg");
|
||||
|
||||
cout << "Exiting..." << endl;
|
||||
|
||||
delete sensor;
|
||||
|
||||
//! [Interesting]
|
||||
|
||||
return 0;
|
||||
}
|
66
examples/java/AM2315Example.java
Normal file
66
examples/java/AM2315Example.java
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Author: Abhishek Malik <abhishek.malik@intel.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 upm_am2315.AM2315;
|
||||
|
||||
public class AM2315Example {
|
||||
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("javaupm_am2315");
|
||||
System.loadLibrary("mraajava");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
System.err.println(
|
||||
"Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" +
|
||||
e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// TODO Auto-generated method stub
|
||||
//! [Interesting]
|
||||
float humidity = 0;
|
||||
float temperature = 0;
|
||||
|
||||
// Instantiate the sensor
|
||||
AM2315 sensor = new AM2315(0, upm_am2315.javaupm_am2315Constants.AM2315_I2C_ADDRESS);
|
||||
sensor.testSensor();
|
||||
|
||||
while(true){
|
||||
// retrieving the humidity and temperature values
|
||||
humidity = sensor.getHumidity();
|
||||
temperature = sensor.getTemperature();
|
||||
|
||||
System.out.println("Temperature : "+temperature+" Humidity: "+humidity);
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
System.out.println("The following exception occurred: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
//! [Interesting]
|
||||
}
|
||||
|
||||
}
|
@ -42,7 +42,7 @@ public class Ad8232Example {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
System.out.println("The following error has occured: "+e.getMessage());
|
||||
System.out.println("The following error has occurred: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ public class Apds9002 {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
System.out.println("The following exception occured: "+e.getMessage());
|
||||
System.out.println("The following exception occurred: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
//! [Interesting]
|
||||
|
@ -6,13 +6,15 @@ macro(add_example example_name jar_name)
|
||||
set(example_jar "${CMAKE_CURRENT_BINARY_DIR}/../../src/${jar_name}/upm_${jar_name}.jar")
|
||||
|
||||
add_jar(${example_name} SOURCES ${example_src} INCLUDE_JARS ${example_jar})
|
||||
add_dependencies(${example_name} javaupm_${jar_name})
|
||||
endmacro()
|
||||
|
||||
macro(add_example_with_path example_name jar_path)
|
||||
macro(add_example_with_path example_name jar_path jar_name)
|
||||
set(example_src "${example_name}.java")
|
||||
set(example_jar "${CMAKE_CURRENT_BINARY_DIR}/../../src/${jar_path}")
|
||||
set(example_jar "${CMAKE_CURRENT_BINARY_DIR}/../../src/${jar_path}/upm_${jar_name}.jar")
|
||||
|
||||
add_jar(${example_name} SOURCES ${example_src} INCLUDE_JARS ${example_jar})
|
||||
add_dependencies(${example_name} javaupm_${jar_name})
|
||||
endmacro()
|
||||
|
||||
add_example(A110X_intrSample a110x)
|
||||
@ -110,14 +112,20 @@ add_example(TEAMS_Example teams)
|
||||
add_example(APA102Sample apa102)
|
||||
add_example(TEX00_Example tex00)
|
||||
add_example(BMI160_Example bmi160)
|
||||
add_example(Tsl2561 tsl2561)
|
||||
add_example(AM2315Example am2315)
|
||||
if (MODBUS_FOUND)
|
||||
add_example(H803X_Example h803x)
|
||||
endif()
|
||||
if (BACNET_FOUND)
|
||||
add_example(E50HX_Example e50hx)
|
||||
endif()
|
||||
add_example(VCAP_Example vcap)
|
||||
|
||||
add_example_with_path(Jhd1313m1_lcdSample lcd/upm_i2clcd.jar)
|
||||
add_example_with_path(Jhd1313m1Sample lcd/upm_i2clcd.jar)
|
||||
add_example_with_path(Lcm1602_i2cSample lcd/upm_i2clcd.jar)
|
||||
add_example_with_path(Lcm1602_parallelSample lcd/upm_i2clcd.jar)
|
||||
add_example_with_path(SSD1308_oledSample lcd/upm_i2clcd.jar)
|
||||
add_example_with_path(SSD1327_oledSample lcd/upm_i2clcd.jar)
|
||||
add_example_with_path(Jhd1313m1_lcdSample lcd i2clcd)
|
||||
add_example_with_path(Jhd1313m1Sample lcd i2clcd)
|
||||
add_example_with_path(Lcm1602_i2cSample lcd i2clcd)
|
||||
add_example_with_path(Lcm1602_parallelSample lcd i2clcd)
|
||||
add_example_with_path(SSD1308_oledSample lcd i2clcd)
|
||||
add_example_with_path(SSD1327_oledSample lcd i2clcd)
|
||||
|
||||
|
90
examples/java/E50HX_Example.java
Normal file
90
examples/java/E50HX_Example.java
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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 upm_e50hx.E50HX;
|
||||
|
||||
public class E50HX_Example
|
||||
{
|
||||
private static String defaultDev = "/dev/ttyUSB0";
|
||||
|
||||
public static void main(String[] args) throws InterruptedException
|
||||
{
|
||||
// ! [Interesting]
|
||||
|
||||
// You will need to edit this example to conform to your site
|
||||
// and your devices, specifically the Device Object Instance
|
||||
// ID passed to the constructor, and the arguments to
|
||||
// initMaster() that are appropriate for your BACnet network.
|
||||
|
||||
if (args.length > 0)
|
||||
defaultDev = args[0];
|
||||
System.out.println("Using device " + defaultDev);
|
||||
System.out.println("Initializing...");
|
||||
|
||||
// Instantiate an E50HX object for an E50HX device that has
|
||||
// 1075425 as it's unique Device Object Instance ID. NOTE:
|
||||
// You will certainly want to change this to the correct value
|
||||
// for your device(s).
|
||||
E50HX sensor = new E50HX(1075425);
|
||||
|
||||
// Initialize our BACnet master, if it has not already been
|
||||
// initialized, with the device and baudrate, choosing 1000001 as
|
||||
// our unique Device Object Instance ID, 2 as our MAC address and
|
||||
// using default values for maxMaster and maxInfoFrames
|
||||
sensor.initMaster(defaultDev, 38400, 1000001, 2);
|
||||
|
||||
// Uncomment to enable debugging output
|
||||
// sensor.setDebug(true);
|
||||
|
||||
System.out.println();
|
||||
System.out.println("Device Description: " + sensor.getDescription());
|
||||
System.out.println("Device Location: " + sensor.getLocation());
|
||||
System.out.println();
|
||||
|
||||
// update and print a few values every 5 seconds
|
||||
while (true)
|
||||
{
|
||||
System.out.println("System Voltage: "
|
||||
+ sensor.getAnalogValue(E50HX.ANALOG_VALUES_T.AV_System_Voltage)
|
||||
+ " "
|
||||
+ sensor.getAnalogValueUnits(E50HX.ANALOG_VALUES_T.AV_System_Voltage));
|
||||
|
||||
System.out.println("System Type: "
|
||||
+ sensor.getAnalogValue(E50HX.ANALOG_VALUES_T.AV_System_Type));
|
||||
|
||||
System.out.println("Energy Consumption: "
|
||||
+ sensor.getAnalogInput(E50HX.ANALOG_INPUTS_T.AI_Energy)
|
||||
+ " "
|
||||
+ sensor.getAnalogInputUnits(E50HX.ANALOG_INPUTS_T.AI_Energy));
|
||||
|
||||
System.out.println("Power Up Counter: "
|
||||
+ sensor.getAnalogInput(E50HX.ANALOG_INPUTS_T.AI_Power_Up_Count));
|
||||
|
||||
System.out.println();
|
||||
Thread.sleep(5000);
|
||||
}
|
||||
|
||||
// ! [Interesting]
|
||||
}
|
||||
}
|
@ -59,7 +59,7 @@ public class Gp2y0aExample {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
System.out.println("The following exception occured: "+e.getMessage());
|
||||
System.out.println("The following exception occurred: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
//! [Interesting]
|
||||
|
@ -39,7 +39,7 @@ public class GroveEmg {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
System.out.println("The following exception occured: "+e.getMessage());
|
||||
System.out.println("The following exception occurred: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ public class GroveGsr {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
System.out.println("The following exception occured: "+e.getMessage());
|
||||
System.out.println("The following exception occurred: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
//! [Interesting]
|
||||
|
@ -38,7 +38,7 @@ public class GroveO2Example {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
System.out.println("The following exception has occured: "+e.getMessage());
|
||||
System.out.println("The following exception has occurred: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
//! [Interesting]
|
||||
|
@ -42,7 +42,7 @@ public class HP20xExample {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
System.out.println("The following exception occured: "+e.getMessage());
|
||||
System.out.println("The following exception occurred: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
//! [Interesting]
|
||||
|
@ -39,7 +39,7 @@ public class Th02Example {
|
||||
Thread.sleep(500);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
System.out.println("The following exception has occured: "+e.getMessage());
|
||||
System.out.println("The following exception has occurred: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
61
examples/java/Tsl2561.java
Normal file
61
examples/java/Tsl2561.java
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Author: Abhishek Malik <abhishek.malik@intel.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 upm_tsl2561.TSL2561;
|
||||
|
||||
public class Tsl2561 {
|
||||
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("javaupm_tsl2561");
|
||||
System.loadLibrary("mraajava");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
System.err.println(
|
||||
"Native code library failed to load. See the chapter on Dynamic Linking Problems in the SWIG Java documentation for help.\n" +
|
||||
e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// TODO Auto-generated method stub
|
||||
//! [Interesting]
|
||||
TSL2561 sensor = null;
|
||||
int loopCount = 100;
|
||||
// Instantiate the sensor object
|
||||
sensor = new TSL2561();
|
||||
|
||||
for (int i=0; i<loopCount; i++){
|
||||
// retrieving and displaying the Lux value
|
||||
System.out.println("Lux: "+sensor.getLux());
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
System.out.println("The following exception occurred: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
//! [Interesting]
|
||||
}
|
||||
|
||||
}
|
60
examples/java/VCAP_Example.java
Normal file
60
examples/java/VCAP_Example.java
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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 upm_vcap.VCAP;
|
||||
|
||||
public class VCAP_Example
|
||||
{
|
||||
private static String defaultDev = "/dev/video0";
|
||||
|
||||
public static void main(String[] args) throws InterruptedException
|
||||
{
|
||||
// ! [Interesting]
|
||||
if (args.length > 0)
|
||||
defaultDev = args[0];
|
||||
|
||||
System.out.println("Using device " + defaultDev);
|
||||
System.out.println("Initializing...");
|
||||
|
||||
// Instantiate an VCAP instance, using the specified video device
|
||||
VCAP sensor = new VCAP(defaultDev);
|
||||
|
||||
// enable some debug/verbose output
|
||||
sensor.setDebug(true);
|
||||
|
||||
// This is just a hint. The kernel can change this to a lower
|
||||
// resolution that the hardware supports. Use getWidth() and
|
||||
// getHeight() methods to see what the kernel actually chose if you
|
||||
// care.
|
||||
sensor.setResolution(1920, 1080);
|
||||
|
||||
// capture an image
|
||||
sensor.captureImage();
|
||||
|
||||
// convert and save it as a jpeg
|
||||
sensor.saveImage("video-img1.jpg");
|
||||
|
||||
// ! [Interesting]
|
||||
}
|
||||
}
|
@ -43,7 +43,7 @@ public class WaterLevelSensor {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// TODO Auto-generated catch block
|
||||
System.out.println("The following exception occured: "+e.getMessage());
|
||||
System.out.println("The following exception occurred: "+e.getMessage());
|
||||
}
|
||||
}
|
||||
//! [Interesting]
|
||||
|
101
examples/javascript/e50hx.js
Normal file
101
examples/javascript/e50hx.js
Normal 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_e50hx');
|
||||
|
||||
|
||||
/************** Main code **************/
|
||||
|
||||
// You will need to edit this example to conform to your site and your
|
||||
// devices, specifically the Device Object Instance ID passed to the
|
||||
// constructor, and the arguments to initMaster() that are
|
||||
// appropriate for your BACnet network.
|
||||
|
||||
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("Using device " + defaultDev);
|
||||
console.log("Initializing...");
|
||||
|
||||
// Instantiate an E50HX object for an E50HX device that has 1075425
|
||||
// as it's unique Device Object Instance ID. NOTE: You will
|
||||
// certainly want to change this to the correct value for your
|
||||
// device(s).
|
||||
var sensor = new sensorObj.E50HX(1075425);
|
||||
|
||||
// Initialize our BACnet master, if it has not already been
|
||||
// initialized, with the device and baudrate, choosing 1000001 as
|
||||
// our unique Device Object Instance ID, 2 as our MAC address and
|
||||
// using default values for maxMaster and maxInfoFrames
|
||||
sensor.initMaster(defaultDev, 38400, 1000001, 2);
|
||||
|
||||
// Uncomment to enable debugging output
|
||||
// sensor.setDebug(true);
|
||||
|
||||
console.log("");
|
||||
console.log("Device Description:", sensor.getDescription());
|
||||
console.log("Device Location:", sensor.getLocation());
|
||||
console.log("");
|
||||
|
||||
// update and print a few values every 5 seconds
|
||||
setInterval(function()
|
||||
{
|
||||
console.log("System Voltage:",
|
||||
sensor.getAnalogValue(sensorObj.E50HX.AV_System_Voltage),
|
||||
" ",
|
||||
sensor.getAnalogValueUnits(sensorObj.E50HX.AV_System_Voltage));
|
||||
|
||||
console.log("System Type:",
|
||||
sensor.getAnalogValue(sensorObj.E50HX.AV_System_Type));
|
||||
|
||||
console.log("Energy Consumption:",
|
||||
sensor.getAnalogInput(sensorObj.E50HX.AI_Energy),
|
||||
" ",
|
||||
sensor.getAnalogInputUnits(sensorObj.E50HX.AI_Energy));
|
||||
|
||||
console.log("Power Up Counter:",
|
||||
sensor.getAnalogInput(sensorObj.E50HX.AI_Power_Up_Count));
|
||||
|
||||
console.log("");
|
||||
|
||||
}, 5000);
|
||||
|
||||
|
||||
process.on('SIGINT', function()
|
||||
{
|
||||
sensor = null;
|
||||
sensorObj.cleanUp();
|
||||
sensorObj = null;
|
||||
console.log("Exiting...");
|
||||
process.exit(0);
|
||||
});
|
@ -128,7 +128,7 @@ function runRadio()
|
||||
console.log("Received: " + resultStr);
|
||||
}
|
||||
|
||||
if (rv < 0) // some sort of read error occured
|
||||
if (rv < 0) // some sort of read error occurred
|
||||
{
|
||||
console.log("Port read error.");
|
||||
return;
|
||||
|
@ -90,7 +90,7 @@ function exit()
|
||||
|
||||
// Load i2clcd module
|
||||
var lcdObj = require('jsupm_i2clcd');
|
||||
var lcd = new lcdObj.SSD1306(6, 0x3c);
|
||||
var lcd = new lcdObj.SSD1306(0, 0x3C);
|
||||
var next = 0;
|
||||
|
||||
lcd.clear();
|
||||
|
@ -66,7 +66,7 @@ function getGPSInfo()
|
||||
process.stdout.write(GPSData)
|
||||
}
|
||||
|
||||
if (rv < 0) // some sort of read error occured
|
||||
if (rv < 0) // some sort of read error occurred
|
||||
{
|
||||
console.log("Port read error.");
|
||||
process.exit(0);
|
||||
|
69
examples/javascript/vcap.js
Normal file
69
examples/javascript/vcap.js
Normal file
@ -0,0 +1,69 @@
|
||||
/*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_vcap');
|
||||
|
||||
|
||||
/************** Main code **************/
|
||||
|
||||
var defaultDev = "/dev/video0";
|
||||
|
||||
// if an argument was specified, use it as the device instead
|
||||
if (process.argv.length > 2)
|
||||
{
|
||||
defaultDev = process.argv[2];
|
||||
}
|
||||
|
||||
console.log("Using device " + defaultDev);
|
||||
console.log("Initializing...");
|
||||
|
||||
// Instantiate an VCAP instance, using the specified video device
|
||||
var sensor = new sensorObj.VCAP(defaultDev);
|
||||
|
||||
// enable some debug/verbose output
|
||||
sensor.setDebug(true);
|
||||
|
||||
// This is just a hint. The kernel can change this to a lower
|
||||
// resolution that the hardware supports. Use getWidth() and
|
||||
// getHeight() methods to see what the kernel actually chose if you
|
||||
// care.
|
||||
sensor.setResolution(1920, 1080);
|
||||
|
||||
// capture an image
|
||||
sensor.captureImage();
|
||||
|
||||
// convert and save it as a jpeg
|
||||
sensor.saveImage("video-img1.jpg");
|
||||
|
||||
// make sure we clean up
|
||||
sensor = null;
|
||||
sensorObj.cleanUp();
|
||||
sensorObj = null;
|
||||
console.log("Exiting...");
|
||||
process.exit(0);
|
||||
|
95
examples/python/e50hx.py
Normal file
95
examples/python/e50hx.py
Normal file
@ -0,0 +1,95 @@
|
||||
#!/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_e50hx 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)
|
||||
|
||||
# You will need to edit this example to conform to your site and your
|
||||
# devices, specifically the Device Object Instance ID passed to the
|
||||
# constructor, and the arguments to initMaster() that are
|
||||
# appropriate for your BACnet network.
|
||||
|
||||
defaultDev = "/dev/ttyUSB0"
|
||||
|
||||
# if an argument was specified, use it as the device instead
|
||||
if (len(sys.argv) > 1):
|
||||
defaultDev = sys.argv[1]
|
||||
|
||||
print "Using device", defaultDev
|
||||
print "Initializing..."
|
||||
|
||||
# Instantiate an E50HX object for an E50HX device that has 1075425
|
||||
# as it's unique Device Object Instance ID. NOTE: You will
|
||||
# certainly want to change this to the correct value for your
|
||||
# device(s).
|
||||
sensor = sensorObj.E50HX(1075425)
|
||||
|
||||
# Initialize our BACnet master, if it has not already been
|
||||
# initialized, with the device and baudrate, choosing 1000001 as
|
||||
# our unique Device Object Instance ID, 2 as our MAC address and
|
||||
# using default values for maxMaster and maxInfoFrames
|
||||
sensor.initMaster(defaultDev, 38400, 1000001, 2)
|
||||
|
||||
# Uncomment to enable debugging output
|
||||
# sensor.setDebug(True);
|
||||
|
||||
# output the serial number and firmware revision
|
||||
print
|
||||
print "Device Description:", sensor.getDescription()
|
||||
print "Device Location:", sensor.getLocation()
|
||||
print
|
||||
|
||||
# update and print available values every second
|
||||
while (1):
|
||||
print "System Voltage:",
|
||||
print sensor.getAnalogValue(sensorObj.E50HX.AV_System_Voltage),
|
||||
print " ",
|
||||
print sensor.getAnalogValueUnits(sensorObj.E50HX.AV_System_Voltage)
|
||||
|
||||
print "System Type:",
|
||||
print sensor.getAnalogValue(sensorObj.E50HX.AV_System_Type)
|
||||
|
||||
print "Energy Consumption:",
|
||||
print sensor.getAnalogInput(sensorObj.E50HX.AI_Energy),
|
||||
print " ",
|
||||
print sensor.getAnalogInputUnits(sensorObj.E50HX.AI_Energy)
|
||||
|
||||
print "Power Up Counter:",
|
||||
print sensor.getAnalogInput(sensorObj.E50HX.AI_Power_Up_Count)
|
||||
|
||||
print
|
||||
time.sleep(5)
|
@ -123,7 +123,7 @@ else:
|
||||
resultStr += radioBuffer.__getitem__(x)
|
||||
print "Received:", resultStr
|
||||
|
||||
if (rv < 0): # some sort of read error occured
|
||||
if (rv < 0): # some sort of read error occurred
|
||||
print "Port read error."
|
||||
sys.exit(0)
|
||||
myCounter += 1
|
||||
|
@ -73,7 +73,7 @@ def getGPSInfo():
|
||||
GPSData += nmeaBuffer.__getitem__(x)
|
||||
sys.stdout.write(GPSData)
|
||||
|
||||
if (rv < 0): # some sort of read error occured
|
||||
if (rv < 0): # some sort of read error occurred
|
||||
print "Port read error."
|
||||
sys.exit(0)
|
||||
|
||||
|
67
examples/python/vcap.py
Normal file
67
examples/python/vcap.py
Normal file
@ -0,0 +1,67 @@
|
||||
#!/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_vcap 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/video0"
|
||||
|
||||
# if an argument was specified, use it as the device instead
|
||||
if (len(sys.argv) > 1):
|
||||
defaultDev = sys.argv[1]
|
||||
|
||||
print "Using device", defaultDev
|
||||
print "Initializing..."
|
||||
|
||||
# Instantiate an VCAP instance, using the specified video device
|
||||
sensor = sensorObj.VCAP(defaultDev)
|
||||
|
||||
# enable some debug/verbose output
|
||||
sensor.setDebug(True);
|
||||
|
||||
# This is just a hint. The kernel can change this to a lower
|
||||
# resolution that the hardware supports. Use getWidth() and
|
||||
# getHeight() methods to see what the kernel actually chose if you
|
||||
# care.
|
||||
sensor.setResolution(1920, 1080);
|
||||
|
||||
# capture an image
|
||||
sensor.captureImage();
|
||||
|
||||
# convert and save it as a jpeg
|
||||
sensor.saveImage("video-img1.jpg");
|
||||
|
@ -28,7 +28,11 @@ endmacro (upm_CREATE_INSTALL_PKGCONFIG)
|
||||
|
||||
macro(upm_SWIG_PYTHON)
|
||||
if (BUILDSWIGPYTHON AND BUILDSWIG)
|
||||
|
||||
|
||||
include_directories (
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
)
|
||||
|
||||
set_source_files_properties (pyupm_${libname}.i PROPERTIES CPLUSPLUS ON)
|
||||
set_source_files_properties (pyupm_${libname}.i PROPERTIES SWIG_FLAGS "-I${CMAKE_CURRENT_BINARY_DIR}/..")
|
||||
swig_add_module (pyupm_${libname} python pyupm_${libname}.i ${module_src})
|
||||
@ -40,7 +44,7 @@ macro(upm_SWIG_PYTHON)
|
||||
)
|
||||
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/_pyupm_${libname}.so
|
||||
${CMAKE_CURRENT_BINARY_DIR}/pyupm_${libname}.py
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages/
|
||||
DESTINATION ${LIB_INSTALL_DIR}/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages/
|
||||
COMPONENT ${libname})
|
||||
endif()
|
||||
endmacro()
|
||||
@ -57,8 +61,10 @@ macro(upm_SWIG_NODE)
|
||||
set (V8_VERSION_HEX "${V8_VERSION_HEX}0")
|
||||
string (LENGTH "${V8_VERSION_HEX}" V8_VERSION_HEX_length)
|
||||
endwhile ()
|
||||
|
||||
# include_directories (${NODE_INCLUDE_DIRS})
|
||||
|
||||
include_directories (
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/..
|
||||
)
|
||||
|
||||
set_property (SOURCE jsupm_${libname}.i PROPERTY SWIG_FLAGS "-node" "-DV8_VERSION=${V8_VERSION_HEX}")
|
||||
set_source_files_properties (jsupm_${libname}.i PROPERTIES CPLUSPLUS ON)
|
||||
@ -80,7 +86,7 @@ macro(upm_SWIG_NODE)
|
||||
message(FATAL_ERROR " **ERROR** GCC 4.7 or above is required to compile jsupm_${libname} ")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if (NOT ENABLECXX11)
|
||||
set_property (TARGET jsupm_${libname} PROPERTY CXX_STANDARD 11)
|
||||
set_property (TARGET jsupm_${libname} PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
@ -100,7 +106,6 @@ macro(upm_SWIG_NODE)
|
||||
|
||||
endif()
|
||||
createpackagejson(${libname})
|
||||
set (NODE_MODULE_INSTALL_PATH ${NODE_ROOT_DIR}/lib/node_modules/jsupm_${libname}/)
|
||||
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/jsupm_${libname}.node
|
||||
DESTINATION ${NODE_MODULE_INSTALL_PATH} COMPONENT ${libname})
|
||||
endif()
|
||||
@ -132,8 +137,8 @@ macro(upm_SWIG_JAVA)
|
||||
PREFIX "lib"
|
||||
SUFFIX ".so"
|
||||
)
|
||||
install (TARGETS javaupm_${libname} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/upm_${libname}.jar DESTINATION ${CMAKE_INSTALL_LIBDIR}/../lib/java)
|
||||
install (TARGETS javaupm_${libname} LIBRARY DESTINATION ${LIB_INSTALL_DIR})
|
||||
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/upm_${libname}.jar DESTINATION ${LIB_INSTALL_DIR}/../lib/java)
|
||||
|
||||
if (NOT DEFINED $ENV{JAVA_HOME_NATIVE})
|
||||
set (JAVAC $ENV{JAVA_HOME}/bin/javac)
|
||||
@ -161,7 +166,7 @@ macro(upm_doxygen)
|
||||
set (classname ${libname})
|
||||
endif()
|
||||
set (CMAKE_SWIG_FLAGS -DDOXYGEN=${DOXYGEN_FOUND})
|
||||
if (BUILDSWIG)
|
||||
if (BUILDSWIGPYTHON AND BUILDSWIG)
|
||||
add_dependencies (_pyupm_${libname} pyupm_doxy2swig)
|
||||
add_dependencies (pydoc _pyupm_${libname})
|
||||
else ()
|
||||
@ -174,8 +179,11 @@ if (SWIG_FOUND)
|
||||
if (BUILDSWIGPYTHON)
|
||||
if(NOT PYTHONLIBS_FOUND)
|
||||
find_package (PythonLibs ${PYTHONBUILD_VERSION} REQUIRED)
|
||||
string (REPLACE "." ";" PYTHON_VERSION_LIST ${PYTHONLIBS_VERSION_STRING})
|
||||
list (GET PYTHON_VERSION_LIST 0 PYTHON_VERSION_MAJOR)
|
||||
list (GET PYTHON_VERSION_LIST 1 PYTHON_VERSION_MINOR)
|
||||
endif()
|
||||
endif()
|
||||
endif(BUILDSWIGPYTHON)
|
||||
if (BUILDSWIGNODE)
|
||||
if(NOT NODE_FOUND)
|
||||
find_package(Node)
|
||||
@ -191,14 +199,20 @@ if (SWIG_FOUND)
|
||||
${NODE_ROOT_DIR}/include/deps/uv/include
|
||||
)
|
||||
macro(createpackagejson)
|
||||
configure_file (${PROJECT_SOURCE_DIR}/src/package.json.in ${CMAKE_CURRENT_BINARY_DIR}/package.json @ONLY)
|
||||
configure_file (${PROJECT_SOURCE_DIR}/src/package.json.in ${CMAKE_CURRENT_BINARY_DIR}/package.json @ONLY)
|
||||
# If a CMAKE_INSTALL_PREFIX has NOT been provided, set NODE_MODULE_INSTALL_PATH
|
||||
# base on the NODE_ROOT_DIR.
|
||||
if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
set (NODE_MODULE_INSTALL_PATH ${NODE_ROOT_DIR}/lib/node_modules/jsupm_${libname}/)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/package.json
|
||||
DESTINATION ${NODE_MODULE_INSTALL_PATH} COMPONENT ${libname})
|
||||
# If a CMAKE_INSTALL_PREFIX has been provided, set NODE_MODULE_INSTALL_PATH
|
||||
# relative to the provided install directory.
|
||||
else ()
|
||||
set (NODE_MODULE_INSTALL_PATH ${CMAKE_INSTALL_PREFIX}/lib/node_modules/jsupm_${libname}/)
|
||||
endif ()
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/package.json
|
||||
DESTINATION ${NODE_MODULE_INSTALL_PATH} COMPONENT ${libname})
|
||||
endmacro()
|
||||
|
||||
endif(BUILDSWIGNODE)
|
||||
|
||||
endif()
|
||||
|
||||
macro(upm_module_init)
|
||||
@ -207,7 +221,7 @@ macro(upm_module_init)
|
||||
foreach (linkflag ${ARGN})
|
||||
target_link_libraries (${libname} ${linkflag})
|
||||
endforeach ()
|
||||
include_directories (${MRAA_INCLUDE_DIRS} .)
|
||||
include_directories (${MRAA_INCLUDE_DIRS} . ..)
|
||||
target_link_libraries (${libname} ${MRAA_LIBRARIES})
|
||||
set_target_properties(
|
||||
${libname}
|
||||
@ -215,7 +229,7 @@ macro(upm_module_init)
|
||||
SOVERSION ${upm_VERSION_MAJOR}
|
||||
VERSION ${upm_VERSION_STRING}
|
||||
)
|
||||
upm_create_install_pkgconfig (upm-${libname}.pc ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
|
||||
upm_create_install_pkgconfig (upm-${libname}.pc ${LIB_INSTALL_DIR}/pkgconfig)
|
||||
if (SWIG_FOUND)
|
||||
if (NOT ";${PYTHONSWIG_BLACKLIST};" MATCHES ";${libname};")
|
||||
upm_swig_python()
|
||||
@ -230,7 +244,7 @@ macro(upm_module_init)
|
||||
if (BUILDDOC)
|
||||
upm_doxygen()
|
||||
endif()
|
||||
install(TARGETS ${libname} DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
install(TARGETS ${libname} DESTINATION ${LIB_INSTALL_DIR})
|
||||
install (FILES ${module_h} DESTINATION include/upm COMPONENT ${libname})
|
||||
|
||||
if (IPK)
|
||||
|
@ -113,7 +113,7 @@ namespace upm {
|
||||
/**
|
||||
* Set the zero point. This is the point measured and averaged
|
||||
* when the sensor is not moving. It is set at construction time
|
||||
* (averaged over a number of samples), but can be overriden here.
|
||||
* (averaged over a number of samples), but can be overridden here.
|
||||
*
|
||||
* @param zeroPoint The averaged zero point of the sensor at rest
|
||||
*/
|
||||
|
@ -62,7 +62,7 @@ class APA102
|
||||
*
|
||||
* @param ledCount Number of APA102 leds in the strip
|
||||
* @param spiBus SPI Bus number
|
||||
* @param batchMode (optional) Immediatly write to SPI (false, default) or wait for a pushState
|
||||
* @param batchMode (optional) Immediately write to SPI (false, default) or wait for a pushState
|
||||
* call (true)
|
||||
* @param csn (optional) Chip Select Pin
|
||||
*/
|
||||
|
24
src/bacnetmstp/CMakeLists.txt
Normal file
24
src/bacnetmstp/CMakeLists.txt
Normal file
@ -0,0 +1,24 @@
|
||||
set (libname "bacnetmstp")
|
||||
set (libdescription "upm driver module for BACnet MS/TP devices")
|
||||
set (module_src ${libname}.cxx device-client.c)
|
||||
set (module_h ${libname}.h)
|
||||
|
||||
pkg_search_module(BACNET libbacnet)
|
||||
if (BACNET_FOUND)
|
||||
set (reqlibname "libbacnet")
|
||||
include_directories(${BACNET_INCLUDE_DIRS})
|
||||
upm_module_init()
|
||||
add_dependencies(${libname} ${BACNET_LIBRARIES})
|
||||
target_link_libraries(${libname} ${BACNET_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
if (BUILDSWIG)
|
||||
if (BUILDSWIGNODE)
|
||||
swig_link_libraries (jsupm_${libname} ${BACNET_LIBRARIES} ${MRAA_LIBRARIES} ${NODE_LIBRARIES})
|
||||
endif()
|
||||
if (BUILDSWIGPYTHON)
|
||||
swig_link_libraries (pyupm_${libname} ${BACNET_LIBRARIES} ${PYTHON_LIBRARIES} ${MRAA_LIBRARIES})
|
||||
endif()
|
||||
if (BUILDSWIGJAVA)
|
||||
swig_link_libraries (javaupm_${libname} ${BACNET_LIBRARIES} ${MRAAJAVA_LDFLAGS} ${JAVA_LDFLAGS})
|
||||
endif()
|
||||
endif()
|
||||
endif ()
|
880
src/bacnetmstp/bacnetmstp.cxx
Normal file
880
src/bacnetmstp/bacnetmstp.cxx
Normal file
@ -0,0 +1,880 @@
|
||||
/*
|
||||
* 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 "bacnetmstp.h"
|
||||
#include "handlers.h"
|
||||
#include "client.h"
|
||||
#include "txbuf.h"
|
||||
#include "mstpdef.h"
|
||||
|
||||
using namespace upm;
|
||||
using namespace std;
|
||||
|
||||
// our singleton instance
|
||||
BACNETMSTP* BACNETMSTP::m_instance = 0;
|
||||
|
||||
BACNETMSTP::BACNETMSTP()
|
||||
{
|
||||
// set defaults here
|
||||
m_maxInfoFrames = DEFAULT_MAX_INFO_FRAMES;
|
||||
m_maxMaster = DEFAULT_MAX_MASTER;
|
||||
m_baudRate = 38400;
|
||||
m_macAddr = DEFAULT_MAX_MASTER;
|
||||
|
||||
m_initialized = false;
|
||||
|
||||
// 60 sec, for MS/TP
|
||||
m_adpuTimeoutMS = 60000;
|
||||
|
||||
m_deviceInstanceID = BACNET_MAX_INSTANCE;
|
||||
|
||||
memset(m_rxBuffer, 0, MAX_MPDU);
|
||||
|
||||
m_returnedValue = {0};
|
||||
m_targetAddress = {0};
|
||||
m_invokeID = 0;
|
||||
m_errorDetected = false;
|
||||
|
||||
setDebug(false);
|
||||
}
|
||||
|
||||
BACNETMSTP::~BACNETMSTP()
|
||||
{
|
||||
if (m_initialized)
|
||||
datalink_cleanup();
|
||||
}
|
||||
|
||||
void BACNETMSTP::setDebug(bool enable)
|
||||
{
|
||||
m_debugging = enable;
|
||||
}
|
||||
|
||||
void BACNETMSTP::clearErrors()
|
||||
{
|
||||
m_errorType = BACERR_TYPE_NONE;
|
||||
|
||||
// empty out all of our error/reject/abort info
|
||||
m_rejectReason = REJECT_REASON_OTHER;
|
||||
m_rejectString.clear();
|
||||
|
||||
m_abortReason = ABORT_REASON_OTHER;
|
||||
m_abortString.clear();
|
||||
|
||||
m_errorClass = ERROR_CLASS_DEVICE;
|
||||
m_errorCode = ERROR_CODE_OTHER;
|
||||
m_errorString.clear();
|
||||
|
||||
m_upmErrorString.clear();
|
||||
}
|
||||
|
||||
void BACNETMSTP::handlerError(BACNET_ADDRESS* src,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ERROR_CLASS error_class,
|
||||
BACNET_ERROR_CODE error_code)
|
||||
{
|
||||
if (instance()->m_debugging)
|
||||
cerr << __FUNCTION__ << ": entered" << endl;
|
||||
|
||||
if (address_match(&(instance()->m_targetAddress), src) &&
|
||||
(invoke_id == instance()->m_invokeID))
|
||||
{
|
||||
instance()->m_errorType = BACERR_TYPE_ERROR;
|
||||
instance()->m_errorClass = error_class;
|
||||
instance()->m_errorCode = error_code;
|
||||
instance()->m_errorString =
|
||||
bactext_error_class_name((int)error_class)
|
||||
+ string(": ") + bactext_error_code_name((int)error_code);
|
||||
|
||||
instance()->m_errorDetected = true;
|
||||
}
|
||||
}
|
||||
|
||||
void BACNETMSTP::handlerAbort(BACNET_ADDRESS* src,
|
||||
uint8_t invoke_id,
|
||||
uint8_t abort_reason,
|
||||
bool server)
|
||||
{
|
||||
(void)server; // not used
|
||||
|
||||
if (instance()->m_debugging)
|
||||
cerr << __FUNCTION__ << ": entered" << endl;
|
||||
|
||||
if (address_match(&(instance()->m_targetAddress), src) &&
|
||||
(invoke_id == instance()->m_invokeID))
|
||||
{
|
||||
instance()->m_errorType = BACERR_TYPE_ABORT;
|
||||
instance()->m_abortReason = abort_reason;
|
||||
instance()->m_abortString =
|
||||
bactext_abort_reason_name((int)abort_reason);
|
||||
|
||||
instance()->m_errorDetected = true;
|
||||
}
|
||||
}
|
||||
|
||||
void BACNETMSTP::handlerReject(BACNET_ADDRESS* src,
|
||||
uint8_t invoke_id,
|
||||
uint8_t reject_reason)
|
||||
{
|
||||
if (instance()->m_debugging)
|
||||
cerr << __FUNCTION__ << ": entered" << endl;
|
||||
|
||||
if (address_match(&(instance()->m_targetAddress), src) &&
|
||||
(invoke_id == instance()->m_invokeID))
|
||||
{
|
||||
instance()->m_errorType = BACERR_TYPE_REJECT;
|
||||
instance()->m_rejectReason = reject_reason;
|
||||
instance()->m_rejectString =
|
||||
bactext_reject_reason_name((int)reject_reason);
|
||||
|
||||
instance()->m_errorDetected = true;
|
||||
}
|
||||
}
|
||||
|
||||
void BACNETMSTP::handlerReadPropertyAck(uint8_t* service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS* src,
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA* service_data)
|
||||
{
|
||||
int len = 0;
|
||||
BACNET_READ_PROPERTY_DATA data;
|
||||
|
||||
if (address_match(&(instance()->m_targetAddress), src) &&
|
||||
(service_data->invoke_id == instance()->m_invokeID))
|
||||
{
|
||||
if (instance()->m_debugging)
|
||||
cerr << __FUNCTION__ << ": got readProp ack" << endl;
|
||||
|
||||
len = rp_ack_decode_service_request(service_request, service_len,
|
||||
&data);
|
||||
// FIXME: we don't currently handle arrays (len < service_len)
|
||||
if (len > 0)
|
||||
{
|
||||
bacapp_decode_application_data(data.application_data,
|
||||
data.application_data_len,
|
||||
&(instance()->m_returnedValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
// shouldn't happen?
|
||||
cerr << __FUNCTION__ << ": decode app data failed" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BACNETMSTP::handlerWritePropertyAck(BACNET_ADDRESS* src,
|
||||
uint8_t invoke_id)
|
||||
{
|
||||
if (address_match(&(instance()->m_targetAddress), src) &&
|
||||
(invoke_id == instance()->m_invokeID))
|
||||
{
|
||||
if (instance()->m_debugging)
|
||||
cerr << __FUNCTION__ << ": got writeProp ack" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void BACNETMSTP::initServiceHandlers()
|
||||
{
|
||||
// this is in device-client.c
|
||||
Device_Init(NULL);
|
||||
|
||||
// These are service requests we must handle from other masters
|
||||
|
||||
// we need to handle who-is to support dynamic device binding to us
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_WHO_IS, handler_who_is);
|
||||
|
||||
// handle i-am to support binding to other devices
|
||||
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM, handler_i_am_bind);
|
||||
|
||||
// set the handler for all the services we don't implement
|
||||
|
||||
// It is required to send the proper reject message...
|
||||
apdu_set_unrecognized_service_handler_handler(handler_unrecognized_service);
|
||||
|
||||
// we must implement read property (it's required)
|
||||
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
|
||||
handler_read_property);
|
||||
|
||||
// These are related to requests we make
|
||||
|
||||
// handle the data coming back from confirmed readProp requests
|
||||
apdu_set_confirmed_ack_handler(SERVICE_CONFIRMED_READ_PROPERTY,
|
||||
handlerReadPropertyAck);
|
||||
|
||||
// handle the simple ack for confirmed writeProp requests
|
||||
apdu_set_confirmed_simple_ack_handler(SERVICE_CONFIRMED_WRITE_PROPERTY,
|
||||
handlerWritePropertyAck);
|
||||
|
||||
// handle any errors coming back
|
||||
apdu_set_error_handler(SERVICE_CONFIRMED_READ_PROPERTY, handlerError);
|
||||
apdu_set_abort_handler(handlerAbort);
|
||||
apdu_set_reject_handler(handlerReject);
|
||||
}
|
||||
|
||||
BACNETMSTP* BACNETMSTP::instance()
|
||||
{
|
||||
if (!m_instance)
|
||||
m_instance = new BACNETMSTP;
|
||||
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
void BACNETMSTP::initMaster(std::string port, int baudRate,
|
||||
int deviceInstanceID, int macAddr, int maxMaster,
|
||||
int maxInfoFrames)
|
||||
{
|
||||
// first some checking
|
||||
|
||||
// if we are already initialized, then it's too late to change things now
|
||||
if (m_initialized)
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": Instance is already initialized, ignored."
|
||||
<< endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// baudrate
|
||||
// The standard allows (as of at least 2010) the following baud rates
|
||||
if ( !(baudRate == 9600 || baudRate == 19200 || baudRate == 38400
|
||||
|| baudRate == 57600 || baudRate == 76800 || baudRate == 115200) )
|
||||
{
|
||||
throw std::invalid_argument(std::string(__FUNCTION__)
|
||||
+ ": baudRate must be 9600, 19200, 38400, "
|
||||
+ " 57600, 76800, or 115200");
|
||||
}
|
||||
|
||||
// maxMaster
|
||||
// maxMaster must be less than or equal to 127
|
||||
if (maxMaster < 0 || maxMaster > DEFAULT_MAX_MASTER)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__)
|
||||
+ ": maxMaster must be between 0 and "
|
||||
+ std::to_string(DEFAULT_MAX_MASTER));
|
||||
}
|
||||
|
||||
// As a master ourselves, we must have a MAC address also within the
|
||||
// constraints of maxMaster
|
||||
if (macAddr < 0 || macAddr > DEFAULT_MAX_MASTER)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__)
|
||||
+ ": macAddr must be between 0 and "
|
||||
+ std::to_string(DEFAULT_MAX_MASTER));
|
||||
}
|
||||
|
||||
// this should be unique on the network
|
||||
if (deviceInstanceID >= BACNET_MAX_INSTANCE)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__)
|
||||
+ ": deviceInstanceID must be less than "
|
||||
+ std::to_string(BACNET_MAX_INSTANCE)
|
||||
+ ", and must be unique on the network");
|
||||
}
|
||||
|
||||
m_port = port;
|
||||
m_baudRate = baudRate;
|
||||
m_maxInfoFrames = maxInfoFrames;
|
||||
m_macAddr = macAddr;
|
||||
m_maxMaster = maxMaster;
|
||||
m_deviceInstanceID = deviceInstanceID;
|
||||
|
||||
// Let the fun begin...
|
||||
|
||||
// setup our info
|
||||
Device_Set_Object_Instance_Number(m_deviceInstanceID);
|
||||
address_init();
|
||||
|
||||
initServiceHandlers();
|
||||
|
||||
dlmstp_set_max_info_frames(m_maxInfoFrames);
|
||||
dlmstp_set_max_master(m_maxMaster);
|
||||
dlmstp_set_baud_rate(m_baudRate);
|
||||
dlmstp_set_mac_address(m_macAddr);
|
||||
|
||||
// FIXME - allow to change?
|
||||
apdu_timeout_set(m_adpuTimeoutMS);
|
||||
|
||||
// Ordinarily, I'd like to check the return value of this function,
|
||||
// but even in the face of errors, it always returns true :( This
|
||||
// function starts the ball rolling, and initializes the Master FSM
|
||||
// thread. Unfortunately, it doesn't appear this can be turned back
|
||||
// off without exiting the application.
|
||||
datalink_init((char *)port.c_str());
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
bool BACNETMSTP::dispatchRequest()
|
||||
{
|
||||
uint16_t pdu_len = 0;
|
||||
unsigned timeout = 100; // milliseconds
|
||||
unsigned max_apdu = 0;
|
||||
time_t elapsed_seconds = 0;
|
||||
time_t last_seconds = 0;
|
||||
time_t current_seconds = 0;
|
||||
time_t timeout_seconds = 0;
|
||||
bool found = false;
|
||||
|
||||
// address where message came from
|
||||
BACNET_ADDRESS src = {0};
|
||||
|
||||
clearErrors();
|
||||
m_errorDetected = false;
|
||||
|
||||
uint32_t targetDeviceInstanceID = BACNET_MAX_INSTANCE;
|
||||
|
||||
switch (m_command.cmd)
|
||||
{
|
||||
case BACCMD_READ_PROPERTY:
|
||||
targetDeviceInstanceID = m_command.readPropArgs.targetDeviceInstanceID;
|
||||
break;
|
||||
|
||||
case BACCMD_WRITE_PROPERTY:
|
||||
targetDeviceInstanceID = m_command.writePropArgs.targetDeviceInstanceID;
|
||||
break;
|
||||
|
||||
case BACCMD_NONE:
|
||||
{
|
||||
m_errorType = BACERR_TYPE_UPM;
|
||||
m_upmErrorString = string(__FUNCTION__) +
|
||||
": called with BACCMD_NONE, ignoring";
|
||||
|
||||
return true; // error
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
// should this throw?
|
||||
m_errorType = BACERR_TYPE_UPM;
|
||||
m_upmErrorString = string(__FUNCTION__) +
|
||||
": internal error, called with unknown command, ignoring";
|
||||
|
||||
return true; // error
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// timeouts
|
||||
last_seconds = time(NULL);
|
||||
timeout_seconds = (apdu_timeout() / 1000) * apdu_retries();
|
||||
|
||||
// we use 0 to indicate that request hasn't been made yet, so that
|
||||
// it will be made once the address is bound.
|
||||
m_invokeID = 0;
|
||||
|
||||
// bind to the device first.
|
||||
found = address_bind_request(targetDeviceInstanceID, &max_apdu,
|
||||
&(instance()->m_targetAddress));
|
||||
|
||||
if (!found)
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": Address not found, Sending WhoIs..." << endl;
|
||||
|
||||
Send_WhoIs(targetDeviceInstanceID, targetDeviceInstanceID);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": Address was found" << endl;
|
||||
}
|
||||
|
||||
// loop until either we get our data, an error occurs, or we timeout
|
||||
while (true)
|
||||
{
|
||||
current_seconds = time(NULL);
|
||||
|
||||
// at least one second has passed
|
||||
if (current_seconds != last_seconds)
|
||||
tsm_timer_milliseconds((uint16_t) ((current_seconds -
|
||||
last_seconds) * 1000));
|
||||
if (m_errorDetected)
|
||||
break;
|
||||
|
||||
// we have to wait until the address is bound before proceeding
|
||||
if (!found)
|
||||
{
|
||||
found =
|
||||
address_bind_request(targetDeviceInstanceID, &max_apdu,
|
||||
&(instance()->m_targetAddress));
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
// address is bound, and we have not sent our request yet. Make it so.
|
||||
if (m_invokeID == 0)
|
||||
{
|
||||
switch (m_command.cmd)
|
||||
{
|
||||
case BACCMD_READ_PROPERTY:
|
||||
m_invokeID =
|
||||
Send_Read_Property_Request(targetDeviceInstanceID,
|
||||
m_command.readPropArgs.objType,
|
||||
m_command.readPropArgs.objInstance,
|
||||
m_command.readPropArgs.objProperty,
|
||||
m_command.readPropArgs.arrayIndex);
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__
|
||||
<< ": Called Send_Read_Property_Request(), m_invokeID = "
|
||||
<< (int)m_invokeID << endl;
|
||||
|
||||
break;
|
||||
|
||||
case BACCMD_WRITE_PROPERTY:
|
||||
m_invokeID =
|
||||
Send_Write_Property_Request(targetDeviceInstanceID,
|
||||
m_command.writePropArgs.objType,
|
||||
m_command.writePropArgs.objInstance,
|
||||
m_command.writePropArgs.objProperty,
|
||||
m_command.writePropArgs.propValue,
|
||||
m_command.writePropArgs.propPriority,
|
||||
m_command.writePropArgs.arrayIndex);
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__
|
||||
<< ": Called Send_Write_Property_Request(), m_invokeID = "
|
||||
<< (int)m_invokeID << endl;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
else if (tsm_invoke_id_free(m_invokeID))
|
||||
{
|
||||
// transaction completed successfully
|
||||
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": Success, m_invokeID = "
|
||||
<< (int)m_invokeID << endl;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (tsm_invoke_id_failed(m_invokeID))
|
||||
{
|
||||
// transaction state machine failed, most likely timeout
|
||||
tsm_free_invoke_id(m_invokeID);
|
||||
|
||||
m_errorType = BACERR_TYPE_UPM;
|
||||
m_upmErrorString = string(__FUNCTION__) +
|
||||
": TSM Timed Out.";
|
||||
|
||||
if (m_debugging)
|
||||
cerr << m_upmErrorString << endl;
|
||||
|
||||
m_errorDetected = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// still waiting to bind. timeout if we've waited too long.
|
||||
elapsed_seconds += (current_seconds - last_seconds);
|
||||
if (elapsed_seconds > timeout_seconds)
|
||||
{
|
||||
m_errorType = BACERR_TYPE_UPM;
|
||||
m_upmErrorString = string(__FUNCTION__) +
|
||||
": Timed out waiting to bind address.";
|
||||
|
||||
// We output this error unconditionally as this is an
|
||||
// error you will get if you supply a non-existant
|
||||
// Device Obeject Instance ID.
|
||||
|
||||
cerr << m_upmErrorString << endl;
|
||||
cerr << __FUNCTION__
|
||||
<< ": Did you supply the correct Device Object Instance ID "
|
||||
<< "for your device?"
|
||||
<< endl;
|
||||
|
||||
m_errorDetected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// returns 0 bytes on timeout
|
||||
pdu_len = datalink_receive(&src, m_rxBuffer, MAX_MPDU, timeout);
|
||||
|
||||
// process the packet if valid. This will call our handlers as needed.
|
||||
if (pdu_len)
|
||||
npdu_handler(&src, m_rxBuffer, pdu_len);
|
||||
|
||||
// keep track of time for next check
|
||||
last_seconds = current_seconds;
|
||||
}
|
||||
|
||||
return m_errorDetected;
|
||||
}
|
||||
|
||||
bool BACNETMSTP::readProperty(uint32_t targetDeviceInstanceID,
|
||||
BACNET_OBJECT_TYPE objType,
|
||||
uint32_t objInstance,
|
||||
BACNET_PROPERTY_ID objProperty,
|
||||
uint32_t arrayIndex)
|
||||
{
|
||||
// some sanity checking...
|
||||
if (objInstance >= BACNET_MAX_INSTANCE)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__)
|
||||
+ ": objInstance must be less than "
|
||||
+ std::to_string(BACNET_MAX_INSTANCE));
|
||||
}
|
||||
|
||||
// fill in the command structure and dispatch
|
||||
m_command.cmd = BACCMD_READ_PROPERTY;
|
||||
m_command.readPropArgs.targetDeviceInstanceID = targetDeviceInstanceID;
|
||||
m_command.readPropArgs.objType = objType;
|
||||
m_command.readPropArgs.objInstance = objInstance;
|
||||
m_command.readPropArgs.objProperty = objProperty;
|
||||
m_command.readPropArgs.arrayIndex = arrayIndex; // not implemented in the ack handler!
|
||||
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": calling dispatchRequest()..." << endl;
|
||||
|
||||
// send it off
|
||||
bool error = dispatchRequest();
|
||||
|
||||
// clear the command to avoid accidental re-calls
|
||||
m_command.cmd = BACCMD_NONE;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
bool BACNETMSTP::writeProperty(uint32_t targetDeviceInstanceID,
|
||||
BACNET_OBJECT_TYPE objType,
|
||||
uint32_t objInstance,
|
||||
BACNET_PROPERTY_ID objProperty,
|
||||
BACNET_APPLICATION_DATA_VALUE* propValue,
|
||||
uint8_t propPriority,
|
||||
int32_t arrayIndex)
|
||||
{
|
||||
// some sanity checking...
|
||||
if (objInstance >= BACNET_MAX_INSTANCE)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__)
|
||||
+ ": objInstance must be less than "
|
||||
+ std::to_string(BACNET_MAX_INSTANCE));
|
||||
}
|
||||
|
||||
// fill in the command structure and dispatch
|
||||
m_command.cmd = BACCMD_WRITE_PROPERTY;
|
||||
m_command.writePropArgs.targetDeviceInstanceID = targetDeviceInstanceID;
|
||||
m_command.writePropArgs.objType = objType;
|
||||
m_command.writePropArgs.objInstance = objInstance;
|
||||
m_command.writePropArgs.objProperty = objProperty;
|
||||
m_command.writePropArgs.propValue = propValue;
|
||||
m_command.writePropArgs.propPriority = propPriority;
|
||||
m_command.writePropArgs.arrayIndex = arrayIndex; // not implemented!
|
||||
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": calling dispatchRequest()..." << endl;
|
||||
|
||||
// send it off
|
||||
bool error = dispatchRequest();
|
||||
|
||||
// clear the command to avoid accidental re-calls
|
||||
m_command.cmd = BACCMD_NONE;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
BACNET_APPLICATION_DATA_VALUE BACNETMSTP::getData()
|
||||
{
|
||||
return m_returnedValue;
|
||||
}
|
||||
|
||||
uint8_t BACNETMSTP::getDataType()
|
||||
{
|
||||
return m_returnedValue.tag;
|
||||
}
|
||||
|
||||
float BACNETMSTP::getDataTypeReal()
|
||||
{
|
||||
if (getDataType() == BACNET_APPLICATION_TAG_REAL)
|
||||
return m_returnedValue.type.Real;
|
||||
else
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": Not of Real type, trying to convert..." << endl;
|
||||
|
||||
// try to convert or throw
|
||||
switch (getDataType())
|
||||
{
|
||||
case BACNET_APPLICATION_TAG_BOOLEAN:
|
||||
return (getDataTypeBoolean() ? 1.0 : 0.0);
|
||||
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
|
||||
return float(getDataTypeUnsignedInt());
|
||||
case BACNET_APPLICATION_TAG_SIGNED_INT:
|
||||
return float(getDataTypeSignedInt());
|
||||
default:
|
||||
throw std::invalid_argument(std::string(__FUNCTION__)
|
||||
+ ": data type ("
|
||||
+ std::to_string(int(getDataType()))
|
||||
+ ") is not convertible to Real");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BACNETMSTP::getDataTypeBoolean()
|
||||
{
|
||||
if (getDataType() == BACNET_APPLICATION_TAG_BOOLEAN)
|
||||
return ((m_returnedValue.type.Boolean) ? true : false);
|
||||
else
|
||||
throw std::invalid_argument(std::string(__FUNCTION__)
|
||||
+ ": data type ("
|
||||
+ std::to_string(int(getDataType()))
|
||||
+ ") is not convertible to Bool");
|
||||
}
|
||||
|
||||
unsigned int BACNETMSTP::getDataTypeUnsignedInt()
|
||||
{
|
||||
if (getDataType() == BACNET_APPLICATION_TAG_UNSIGNED_INT)
|
||||
return m_returnedValue.type.Unsigned_Int;
|
||||
else
|
||||
throw std::invalid_argument(std::string(__FUNCTION__)
|
||||
+ ": data type ("
|
||||
+ std::to_string(int(getDataType()))
|
||||
+ ") is not convertible to UnsignedInt");
|
||||
}
|
||||
|
||||
int BACNETMSTP::getDataTypeSignedInt()
|
||||
{
|
||||
if (getDataType() == BACNET_APPLICATION_TAG_SIGNED_INT)
|
||||
return m_returnedValue.type.Signed_Int;
|
||||
else
|
||||
throw std::invalid_argument(std::string(__FUNCTION__)
|
||||
+ ": data type ("
|
||||
+ std::to_string(int(getDataType()))
|
||||
+ ") is not convertible to SignedInt");
|
||||
}
|
||||
|
||||
#if defined(BACAPP_DOUBLE)
|
||||
double BACNETMSTP::getDataTypeDouble()
|
||||
{
|
||||
if (getDataType() == BACNET_APPLICATION_TAG_DOUBLE)
|
||||
return m_returnedValue.type.Double;
|
||||
else
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": Not of Double type, trying to convert..." << endl;
|
||||
|
||||
// try to convert or throw
|
||||
switch (getDataType())
|
||||
{
|
||||
case BACNET_APPLICATION_TAG_REAL:
|
||||
return double(getDataTypeReal());
|
||||
case BACNET_APPLICATION_TAG_BOOLEAN:
|
||||
return (getDataTypeBoolean() ? 1.0 : 0.0);
|
||||
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
|
||||
return double(getDataTypeUnsignedInt());
|
||||
case BACNET_APPLICATION_TAG_SIGNED_INT:
|
||||
return double(getDataTypeSignedInt());
|
||||
default:
|
||||
throw std::invalid_argument(std::string(__FUNCTION__)
|
||||
+ ": data type ("
|
||||
+ std::to_string(int(getDataType()))
|
||||
+ ") is not convertible to Double");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // BACAPP_DOUBLE
|
||||
|
||||
unsigned int BACNETMSTP::getDataTypeEnum()
|
||||
{
|
||||
if (getDataType() == BACNET_APPLICATION_TAG_ENUMERATED)
|
||||
return m_returnedValue.type.Enumerated;
|
||||
else
|
||||
throw std::invalid_argument(std::string(__FUNCTION__)
|
||||
+ ": data type ("
|
||||
+ std::to_string(int(getDataType()))
|
||||
+ ") is not convertible to Enum");
|
||||
}
|
||||
|
||||
std::string BACNETMSTP::getDataTypeString()
|
||||
{
|
||||
string retval;
|
||||
|
||||
// Here, we can try to accomodate all the types
|
||||
switch(getDataType())
|
||||
{
|
||||
case BACNET_APPLICATION_TAG_REAL:
|
||||
retval = std::to_string(getDataTypeReal());
|
||||
break;
|
||||
|
||||
#if defined(BACAPP_DOUBLE)
|
||||
case BACNET_APPLICATION_TAG_DOUBLE:
|
||||
retval = std::to_string(getDataTypeDouble());
|
||||
break;
|
||||
#endif // BACAPP_DOUBLE
|
||||
|
||||
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
|
||||
retval = std::to_string(getDataTypeUnsignedInt());
|
||||
break;
|
||||
|
||||
case BACNET_APPLICATION_TAG_SIGNED_INT:
|
||||
retval = std::to_string(getDataTypeSignedInt());
|
||||
break;
|
||||
|
||||
case BACNET_APPLICATION_TAG_BOOLEAN:
|
||||
retval = (getDataTypeBoolean() ? string("true") : string("false"));
|
||||
break;
|
||||
|
||||
case BACNET_APPLICATION_TAG_CHARACTER_STRING:
|
||||
retval = string(characterstring_value(&m_returnedValue.type.Character_String),
|
||||
|
||||
characterstring_length(&m_returnedValue.type.Character_String));
|
||||
break;
|
||||
|
||||
case BACNET_APPLICATION_TAG_OCTET_STRING:
|
||||
{
|
||||
string tmpstr((char *)octetstring_value(&m_returnedValue.type.Octet_String),
|
||||
|
||||
octetstring_length(&m_returnedValue.type.Octet_String));
|
||||
retval = string2HexString(tmpstr);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case BACNET_APPLICATION_TAG_BIT_STRING:
|
||||
{
|
||||
int len = bitstring_bits_used(&m_returnedValue.type.Bit_String);
|
||||
|
||||
for (int i=0; i<len; i++)
|
||||
{
|
||||
if (bitstring_bit(&m_returnedValue.type.Bit_String, uint8_t(i)))
|
||||
retval += "1";
|
||||
else
|
||||
retval += "0";
|
||||
|
||||
if (i != 0 && ((i % 8) == 0))
|
||||
retval += " ";
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw std::invalid_argument(std::string(__FUNCTION__)
|
||||
+ ": data type ("
|
||||
+ std::to_string(int(getDataType()))
|
||||
+ ") is not convertible to String");
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
BACNET_APPLICATION_DATA_VALUE BACNETMSTP::createDataReal(float value)
|
||||
{
|
||||
BACNET_APPLICATION_DATA_VALUE data;
|
||||
|
||||
memset(&data, 0, sizeof(BACNET_APPLICATION_DATA_VALUE));
|
||||
|
||||
data.tag = BACNET_APPLICATION_TAG_REAL;
|
||||
data.type.Real = value;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
BACNET_APPLICATION_DATA_VALUE BACNETMSTP::createDataBool(bool value)
|
||||
{
|
||||
BACNET_APPLICATION_DATA_VALUE data;
|
||||
|
||||
memset(&data, 0, sizeof(BACNET_APPLICATION_DATA_VALUE));
|
||||
|
||||
data.tag = BACNET_APPLICATION_TAG_BOOLEAN;
|
||||
data.type.Boolean = value;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
BACNET_APPLICATION_DATA_VALUE BACNETMSTP::createDataSignedInt(int value)
|
||||
{
|
||||
BACNET_APPLICATION_DATA_VALUE data;
|
||||
|
||||
memset(&data, 0, sizeof(BACNET_APPLICATION_DATA_VALUE));
|
||||
|
||||
data.tag = BACNET_APPLICATION_TAG_SIGNED_INT;
|
||||
data.type.Signed_Int = value;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
BACNET_APPLICATION_DATA_VALUE BACNETMSTP::createDataUnsignedInt(unsigned int value)
|
||||
{
|
||||
BACNET_APPLICATION_DATA_VALUE data;
|
||||
|
||||
memset(&data, 0, sizeof(BACNET_APPLICATION_DATA_VALUE));
|
||||
|
||||
data.tag = BACNET_APPLICATION_TAG_UNSIGNED_INT;
|
||||
data.type.Unsigned_Int = value;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
BACNET_APPLICATION_DATA_VALUE BACNETMSTP::createDataString(string value)
|
||||
{
|
||||
if (value.size() > (MAX_CHARACTER_STRING_BYTES - 1))
|
||||
{
|
||||
throw std::invalid_argument(std::string(__FUNCTION__)
|
||||
+ ": value must be less than or equal to "
|
||||
+ std::to_string(MAX_CHARACTER_STRING_BYTES - 1)
|
||||
+ " characters long");
|
||||
}
|
||||
|
||||
BACNET_APPLICATION_DATA_VALUE data;
|
||||
|
||||
memset(&data, 0, sizeof(BACNET_APPLICATION_DATA_VALUE));
|
||||
|
||||
data.tag = BACNET_APPLICATION_TAG_CHARACTER_STRING;
|
||||
|
||||
characterstring_init_ansi(&data.type.Character_String, value.c_str());
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
string BACNETMSTP::string2HexString(string input)
|
||||
{
|
||||
static const char* const lut = "0123456789abcdef";
|
||||
size_t len = input.size();
|
||||
|
||||
string output;
|
||||
output.reserve(3 * len);
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
{
|
||||
const unsigned char c = input[i];
|
||||
output.push_back(lut[c >> 4]);
|
||||
output.push_back(lut[c & 15]);
|
||||
output.push_back(' ');
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
716
src/bacnetmstp/bacnetmstp.h
Normal file
716
src/bacnetmstp/bacnetmstp.h
Normal file
@ -0,0 +1,716 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
// we only support a BACnet RS-485 MS/TP datalink
|
||||
#define BACDL_MSTP 1
|
||||
#undef BACDL_ALL
|
||||
|
||||
// get a variety of bacnet-stack includes...
|
||||
#include "bacdef.h"
|
||||
#include "config.h"
|
||||
#include "bactext.h"
|
||||
#include "bacerror.h"
|
||||
#include "iam.h"
|
||||
#include "arf.h"
|
||||
#include "tsm.h"
|
||||
#include "address.h"
|
||||
#include "npdu.h"
|
||||
#include "apdu.h"
|
||||
#include "device.h"
|
||||
#include "datalink.h"
|
||||
#include "whois.h"
|
||||
#include "mstpdef.h"
|
||||
#include "dlmstp.h"
|
||||
|
||||
|
||||
namespace upm {
|
||||
|
||||
/**
|
||||
* @brief BACNETMSTP base class
|
||||
* @defgroup bacnetmstp libupm-bacnetmstp
|
||||
* @ingroup uart
|
||||
*/
|
||||
|
||||
/**
|
||||
* @library bacnetmstp
|
||||
* @sensor bacnetmstp
|
||||
* @comname UPM API for BACNET MS/TP communications
|
||||
* @con uart
|
||||
* @web http://bacnet.sourceforge.net/
|
||||
* @brief UPM API for BACNETMSTP
|
||||
*
|
||||
* This is a singleton class that provides services to UPM BACnet
|
||||
* drivers (like E50HX) based on the bacnet-stack at
|
||||
* http://bacnet.sourceforge.net . This class is implemented as a
|
||||
* singleton due to the fact that the bacnet-stack implementation
|
||||
* does not currently allow multiple simultaneous datalinks. We are
|
||||
* using 0.8.3 of bacnet-stack. In the future this restriction may
|
||||
* be lifted depending on bacnet-stack, but for now, you are
|
||||
* stuck with only a single BACnet MS/TP datalink.
|
||||
*
|
||||
* This driver is not intended to be used by end users. It is
|
||||
* intended for use with other UPM drivers that require access to a
|
||||
* BACnet MS/TP (Master Slave/Token Passing) network over RS-485.
|
||||
*
|
||||
* For this reason, no examples are provided. If you wish to
|
||||
* implement your own BACnet MS/TP driver, please look at the E50HX
|
||||
* driver to see how this class can be used.
|
||||
*
|
||||
* Currently, only readProperty and writeProperty BACnet requests
|
||||
* are supported. In the future, any other BACnet requests could be
|
||||
* supported as well. readProperty and writeProperty should provide
|
||||
* most of what you will need when communicating with BACnet
|
||||
* devices. Since the source code is open, feel free to add other
|
||||
* services as you see fit :)
|
||||
*
|
||||
* In order to make requests over an MS/TP network, you must be a
|
||||
* BACnet master. initMaster() is responsible for configuring your
|
||||
* underlying RS-485 network and starting a Master FSM (finite state
|
||||
* machine) thread that will be responsible for identifying other
|
||||
* Masters on the network and negotiating token passing. Your
|
||||
* master can only transmit when it has the token.
|
||||
*
|
||||
* Fortunately, all of these messy details are handled for you by
|
||||
* this class, or the underlying bacnet-stack library this class
|
||||
* relies on.
|
||||
|
||||
*/
|
||||
|
||||
class BACNETMSTP {
|
||||
// Constructor and destructor are protected
|
||||
|
||||
public:
|
||||
|
||||
// error types
|
||||
typedef enum {
|
||||
BACERR_TYPE_NONE = 0,
|
||||
BACERR_TYPE_REJECT,
|
||||
BACERR_TYPE_ABORT,
|
||||
BACERR_TYPE_ERROR,
|
||||
BACERR_TYPE_UPM
|
||||
} BACERR_TYPE_T;
|
||||
|
||||
// command types we currently support
|
||||
typedef enum {
|
||||
BACCMD_NONE = 0,
|
||||
BACCMD_READ_PROPERTY,
|
||||
BACCMD_WRITE_PROPERTY
|
||||
} BACCMD_TYPE_T;
|
||||
|
||||
/**
|
||||
* Get our singleton instance, initializing it if neccessary. All
|
||||
* requests to this class should be done through this instance
|
||||
* accessor.
|
||||
*
|
||||
* @return static pointer to our class instance
|
||||
*/
|
||||
static BACNETMSTP* instance();
|
||||
|
||||
/**
|
||||
* This function initializes the underlying BACNETMSTP Master
|
||||
* singleton in the event it has not already been initialized. If
|
||||
* the BACNETMSTP Master singleton has already been initialized,
|
||||
* then this call will be ignored. There can be only one.
|
||||
*
|
||||
* @param port The serial port that the RS-485 interface is
|
||||
* connected to.
|
||||
* @param baudRate The baudrate of the RS-485 interface. All
|
||||
* devices on a BACnet RS-485 bus must run at the same baudrate.
|
||||
* Valid values are 9600, 19200, 38400, 57600, 76800, and 115200.
|
||||
* @param deviceInstanceNumber This is the unique Device Object
|
||||
* Instance number that will be used for our BACnet Master in
|
||||
* order to communicate over the BACnet interface. This number
|
||||
* must be between 1-4194302 and must be unique on the BACnet
|
||||
* network.
|
||||
* @param macAddr This is the MAC address of our BACnet Master.
|
||||
* It must be unique on the BACnet segment, and must be between
|
||||
* 1-127.
|
||||
* @param maxMaster This specifies to our Master the maximum MAC
|
||||
* address used by any other Masters on the BACnet network. This
|
||||
* must be between 1-127, the default is 127. Do not change this
|
||||
* unless you know what you are doing or you could introduce
|
||||
* token passing errors on the BACnet network.
|
||||
* @param maxInfoFrames This number specifies the maximum number
|
||||
* of transmissions (like requests for data) our Master is allowed
|
||||
* to make before passing the token to the next Master. The
|
||||
* default is 1.
|
||||
*/
|
||||
void initMaster(std::string port, int baudRate, int deviceInstanceNumber,
|
||||
int macAddr, int maxMaster=DEFAULT_MAX_MASTER,
|
||||
int maxInfoFrames=1);
|
||||
|
||||
|
||||
/**
|
||||
* Perform a BACnet readProperty transaction. This function will
|
||||
* return when either the transaction has completed, or an error
|
||||
* has occurred. It requests the value of a property, belonging
|
||||
* to a specific object instance on a specific device.
|
||||
*
|
||||
* @param targetDeviceInstanceID This is the Device Object
|
||||
* Instance ID of the device to send the request to. This number
|
||||
* will be unique for every device on the network. An address
|
||||
* lookup will be performed the first time a request is made to a
|
||||
* device using the WhoHas BACnet service. The result will be
|
||||
* cached for further use.
|
||||
* @param objType This is the BACnet object type of the object you
|
||||
* wish to query. It should be one of the BACNET_OBJECT_TYPE
|
||||
* values.
|
||||
* @param objInstance This is the instance number of the Object
|
||||
* you wish to access. It is an integer starting from 1.
|
||||
* @param objProperty This is the property of the Object and
|
||||
* instance you wish to access. It should be one of the
|
||||
* BACNET_PROPERTY_ID values.
|
||||
* @param arrayIndex This specifies the index number of an array
|
||||
* property. This is not currently supported. Until it is, leave
|
||||
* the default at BACNET_ARRAY_ALL.
|
||||
* @return true if an error occurred, false otherwise.
|
||||
*/
|
||||
bool readProperty(uint32_t targetDeviceInstanceID,
|
||||
BACNET_OBJECT_TYPE objType,
|
||||
uint32_t objInstance,
|
||||
BACNET_PROPERTY_ID objProperty,
|
||||
uint32_t arrayIndex=BACNET_ARRAY_ALL);
|
||||
|
||||
/**
|
||||
* Perform a BACnet writeProperty transaction. This function will
|
||||
* return when either the transaction has completed, or an error
|
||||
* has occurred. It writes the supplied value to a property,
|
||||
* belonging to a specific object instance on a specific device.
|
||||
*
|
||||
* @param targetDeviceInstanceID This is the Device Object
|
||||
* Instance ID of the device to send the request to. This number
|
||||
* will be unique for every device on the network. An address
|
||||
* lookup will be performed the first time a request is made to a
|
||||
* device using the WhoHas BACnet service. The result will be
|
||||
* cached for further use.
|
||||
* @param objType This is the BACnet object type of the object you
|
||||
* wish to query. It should be one of the BACNET_OBJECT_TYPE
|
||||
* values.
|
||||
* @param objInstance This is the instance number of the Object
|
||||
* you wish to access. It is an integer starting from 1.
|
||||
* @param objProperty This is the property of the Object and
|
||||
* instance you wish to access. It should be one of the
|
||||
* BACNET_PROPERTY_ID values.
|
||||
* @param propValue This is a pointer to a
|
||||
* BACNET_APPLICATION_DATA_VALUE structure containg the data value
|
||||
* to write to the property. Use the createData*() methods to
|
||||
* properly create these structures.
|
||||
* @param propPriority This specifies the priority of a
|
||||
* commandable property. Leave it at the default unless you know
|
||||
* what you are doing. In addition, there is conflicting
|
||||
* information in the bacnet-stack documentation as to whether
|
||||
* this is even supported.
|
||||
* @param arrayIndex This specifies the index number of an array
|
||||
* property. This is not currently supported. Until it is, leave
|
||||
* the default at BACNET_ARRAY_ALL.
|
||||
* @return true if an error occurred, false otherwise.
|
||||
*/
|
||||
bool writeProperty(uint32_t targetDeviceInstanceID,
|
||||
BACNET_OBJECT_TYPE objType,
|
||||
uint32_t objInstance,
|
||||
BACNET_PROPERTY_ID objProperty,
|
||||
BACNET_APPLICATION_DATA_VALUE* propValue,
|
||||
uint8_t propPriority=BACNET_NO_PRIORITY,
|
||||
int32_t arrayIndex=BACNET_ARRAY_ALL);
|
||||
|
||||
/**
|
||||
* After a successful readProperty request, this method can be used
|
||||
* to return a BACNET_APPLICATION_DATA_VALUE structure containing
|
||||
* the returned data.
|
||||
*
|
||||
* @return a BACNET_APPLICATION_DATA_VALUE structure containing
|
||||
* the returned data.
|
||||
*/
|
||||
BACNET_APPLICATION_DATA_VALUE getData();
|
||||
|
||||
/**
|
||||
* After a successful readProperty request, this method can be
|
||||
* used to return the BACnet data type of the returned data. It
|
||||
* will be one of the BACNET_APPLICATION_TAG_* values.
|
||||
*
|
||||
* @return A BACNET_APPLICATION_TAG_* value
|
||||
*/
|
||||
uint8_t getDataType();
|
||||
|
||||
/**
|
||||
* After a successful readProperty request, this method can be
|
||||
* used to return the BACnet dataype of the returned data as a
|
||||
* Real. If the data type (getDataType()) is not a
|
||||
* BACNET_APPLICATION_TAG_REAL, and the value returned cannot be
|
||||
* safely converted, an exception is thrown.
|
||||
*
|
||||
* @return A floating point value representing the returned data
|
||||
*/
|
||||
float getDataTypeReal();
|
||||
|
||||
/**
|
||||
* After a successful readProperty request, this method can be
|
||||
* used to return the BACnet dataype of the returned data as a
|
||||
* Boolean. If the data type (getDataType()) is not a
|
||||
* BACNET_APPLICATION_TAG_BOOLEAN, and the value returned cannot
|
||||
* be safely converted, an exception is thrown.
|
||||
*
|
||||
* @return A boolean value representing the returned data
|
||||
*/
|
||||
bool getDataTypeBoolean();
|
||||
|
||||
/**
|
||||
* After a successful readProperty request, this method can be
|
||||
* used to return the BACnet dataype of the returned data as a
|
||||
* unsigned int. If the data type (getDataType()) is not a
|
||||
* BACNET_APPLICATION_TAG_UNSIGNED_INT, and the value returned
|
||||
* cannot be safely converted, an exception is thrown.
|
||||
*
|
||||
* @return An unsigned int value representing the returned data
|
||||
*/
|
||||
unsigned int getDataTypeUnsignedInt();
|
||||
|
||||
/**
|
||||
* After a successful readProperty request, this method can be
|
||||
* used to return the BACnet dataype of the returned data as a
|
||||
* signed int. If the data type (getDataType()) is not a
|
||||
* BACNET_APPLICATION_TAG_SIGNED_INT, and the value returned
|
||||
* cannot be safely converted, an exception is thrown.
|
||||
*
|
||||
* @return A signed int value representing the returned data
|
||||
*/
|
||||
int getDataTypeSignedInt();
|
||||
|
||||
/**
|
||||
* After a successful readProperty request, this method can be
|
||||
* used to return the BACnet dataype of the returned data as a
|
||||
* string. Most of the data types except Enum can be converted to
|
||||
* a string. If the data type (getDataType()) is not a
|
||||
* BACNET_APPLICATION_TAG_CHARACTER_STRING, and the value returned
|
||||
* cannot be safely converted, an exception is thrown.
|
||||
*
|
||||
* @return A string value representing the returned data
|
||||
*/
|
||||
std::string getDataTypeString();
|
||||
|
||||
/**
|
||||
* After a successful readProperty request, this method can be
|
||||
* used to return the BACnet dataype of the returned data as an
|
||||
* enumeration. If the data type (getDataType()) is not a
|
||||
* BACNET_APPLICATION_TAG_ENUMERATED an exception is thrown.
|
||||
*
|
||||
* @return An unsigned int representing a BACnet enumerant
|
||||
*/
|
||||
unsigned int getDataTypeEnum();
|
||||
|
||||
#if defined(BACAPP_DOUBLE)
|
||||
/**
|
||||
* After a successful readProperty request, this method can be
|
||||
* used to return the BACnet dataype of the returned data as a
|
||||
* double. If the data type (getDataType()) is not a
|
||||
* BACNET_APPLICATION_TAG_DOUBLE, and the value returned cannot be
|
||||
* safely converted, an exception is thrown.
|
||||
*
|
||||
* @return A double floating point value representing the returned data
|
||||
*/
|
||||
double getDataTypeDouble();
|
||||
#endif // BACAPP_DOUBLE
|
||||
|
||||
/**
|
||||
* This method is used to create and return an initialized
|
||||
* BACNET_APPLICATION_DATA_VALUE containing a real (floating point
|
||||
* value). A pointer to this returned structure can then be used
|
||||
* with writeProperty().
|
||||
*
|
||||
* @param value The floating point value to initialize the structure to.
|
||||
* @return An initialized structure containing the value
|
||||
*/
|
||||
BACNET_APPLICATION_DATA_VALUE createDataReal(float Real);
|
||||
|
||||
/**
|
||||
* This method is used to create and return an initialized
|
||||
* BACNET_APPLICATION_DATA_VALUE containing a boolean. A pointer
|
||||
* to this returned structure can then be used with
|
||||
* writeProperty().
|
||||
*
|
||||
* @param value The boolean value to initialize the structure to.
|
||||
* @return An initialized structure containing the value
|
||||
*/
|
||||
BACNET_APPLICATION_DATA_VALUE createDataBool(bool value);
|
||||
|
||||
/**
|
||||
* This method is used to create and return an initialized
|
||||
* BACNET_APPLICATION_DATA_VALUE containing a signed integer. A
|
||||
* pointer to this returned structure can then be used with
|
||||
* writeProperty().
|
||||
*
|
||||
* @param value The signed integer value to initialize the structure to.
|
||||
* @return An initialized structure containing the value
|
||||
*/
|
||||
BACNET_APPLICATION_DATA_VALUE createDataSignedInt(int value);
|
||||
|
||||
/**
|
||||
* This method is used to create and return an initialized
|
||||
* BACNET_APPLICATION_DATA_VALUE containing a unsigned integer. A
|
||||
* pointer to this returned structure can then be used with
|
||||
* writeProperty().
|
||||
*
|
||||
* @param value The unsigned integer value to initialize the
|
||||
* structure to.
|
||||
* @return An initialized structure containing the value
|
||||
*/
|
||||
BACNET_APPLICATION_DATA_VALUE createDataUnsignedInt(unsigned int value);
|
||||
|
||||
/**
|
||||
* This method is used to create and return an initialized
|
||||
* BACNET_APPLICATION_DATA_VALUE containing a character string. A
|
||||
* pointer to this returned structure can then be used with
|
||||
* writeProperty(). Strings are typically limited to 63 characters.
|
||||
*
|
||||
* @param value The character string value to initialize the
|
||||
* structure to.
|
||||
* @return An initialized structure containing the value
|
||||
*/
|
||||
BACNET_APPLICATION_DATA_VALUE createDataString(std::string value);
|
||||
|
||||
/**
|
||||
* Return an enumration of the last error type to occur. The
|
||||
* value returned will be one of the BACERR_TYPE_T values.
|
||||
*
|
||||
* @return The last error type to occur, one of the BACERR_TYPE_T
|
||||
* values.
|
||||
*/
|
||||
BACERR_TYPE_T getErrorType()
|
||||
{
|
||||
return m_errorType;
|
||||
};
|
||||
|
||||
/**
|
||||
* In the event of a BACnet Reject error, return the error code.
|
||||
*
|
||||
* @return The Reject error code.
|
||||
*/
|
||||
uint8_t getRejectReason()
|
||||
{
|
||||
return m_rejectReason;
|
||||
};
|
||||
|
||||
/**
|
||||
* In the event of a BACnet Reject error, return the error string.
|
||||
*
|
||||
* @return The Reject error string.
|
||||
*/
|
||||
std::string getRejectString()
|
||||
{
|
||||
return m_rejectString;
|
||||
};
|
||||
|
||||
/**
|
||||
* In the event of a BACnet Abort error, return the Abort reason code.
|
||||
*
|
||||
* @return The Abort reason code.
|
||||
*/
|
||||
uint8_t getAbortReason()
|
||||
{
|
||||
return m_abortReason;
|
||||
};
|
||||
|
||||
/**
|
||||
* In the event of a BACnet Abort error, return the Abort string.
|
||||
*
|
||||
* @return The Abort error string.
|
||||
*/
|
||||
std::string getAbortString()
|
||||
{
|
||||
return m_abortString;
|
||||
};
|
||||
|
||||
/**
|
||||
* In the event of a general BACnet error, return the BACnet error class.
|
||||
*
|
||||
* @return One of the BACNET_ERROR_CLASS error class codes
|
||||
*/
|
||||
BACNET_ERROR_CLASS getErrorClass()
|
||||
{
|
||||
return m_errorClass;
|
||||
};
|
||||
|
||||
/**
|
||||
* In the event of a general BACnet error, return the BACnet error code.
|
||||
*
|
||||
* @return One of the BACNET_ERROR_CODE error codes
|
||||
*/
|
||||
BACNET_ERROR_CODE getErrorCode()
|
||||
{
|
||||
return m_errorCode;
|
||||
};
|
||||
|
||||
/**
|
||||
* In the event of a general BACnet error, return the BACnet error
|
||||
* string.
|
||||
*
|
||||
* @return A string representing the BACnet error class and code.
|
||||
*/
|
||||
std::string getErrorString()
|
||||
{
|
||||
return m_errorString;
|
||||
};
|
||||
|
||||
/**
|
||||
* In the event of a non-BACnet UPM error, return a string
|
||||
* describing the error.
|
||||
*
|
||||
* @return A string representing the UPM error.
|
||||
*/
|
||||
std::string getUPMErrorString()
|
||||
{
|
||||
return m_upmErrorString;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check to see if initMaster) has already been called, and out
|
||||
* master is initialized.
|
||||
*
|
||||
* @return true if the master is initialized, false otherwise
|
||||
*/
|
||||
bool isInitialized()
|
||||
{
|
||||
return m_initialized;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the port that was specified to initMaster().
|
||||
*
|
||||
* @return The port specified to initMaster().
|
||||
*/
|
||||
std::string getPort()
|
||||
{
|
||||
return m_port;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the Object Device Instance ID for our Master was
|
||||
* specified to initMaster().
|
||||
*
|
||||
* @return The Object Device Instance ID for our Master.
|
||||
*/
|
||||
uint32_t getDeviceInstanceID()
|
||||
{
|
||||
return m_deviceInstanceID;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the maxInfoFrames parameter that was specified to initMaster().
|
||||
*
|
||||
* @return The maxInfoFrames parameter specified to initMaster().
|
||||
*/
|
||||
int getMaxInfoFrames()
|
||||
{
|
||||
return m_maxInfoFrames;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the maxMaster parameter that was specified to initMaster().
|
||||
*
|
||||
* @return The maxMaster parameter specified to initMaster().
|
||||
*/
|
||||
int getMaxMaster()
|
||||
{
|
||||
return m_maxMaster;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the baud rate parameter that was specified to initMaster().
|
||||
*
|
||||
* @return The baud rate parameter specified to initMaster().
|
||||
*/
|
||||
int getBaudRate()
|
||||
{
|
||||
return m_baudRate;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the MAC address parameter that was specified to initMaster().
|
||||
*
|
||||
* @return The MAC address parameter specified to initMaster().
|
||||
*/
|
||||
int getMACAddress()
|
||||
{
|
||||
return m_macAddr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable or disable debugging output.
|
||||
*
|
||||
* @param enable true to enable debugging, false otherwise
|
||||
*/
|
||||
void setDebug(bool enable);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* BACNETMSTP constructor
|
||||
*/
|
||||
BACNETMSTP();
|
||||
|
||||
/**
|
||||
* BACNETMSTP Destructor
|
||||
*/
|
||||
~BACNETMSTP();
|
||||
|
||||
// clear/reset error states
|
||||
void clearErrors();
|
||||
|
||||
// error handler
|
||||
static void handlerError(BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id,
|
||||
BACNET_ERROR_CLASS error_class,
|
||||
BACNET_ERROR_CODE error_code);
|
||||
|
||||
// abort handler
|
||||
static void handlerAbort(BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id,
|
||||
uint8_t abort_reason,
|
||||
bool server);
|
||||
|
||||
// reject handler
|
||||
static void handlerReject(BACNET_ADDRESS * src,
|
||||
uint8_t invoke_id,
|
||||
uint8_t reject_reason);
|
||||
|
||||
|
||||
// our handler for dealing with return data from a ReadProperty call
|
||||
static void handlerReadPropertyAck(uint8_t* service_request,
|
||||
uint16_t service_len,
|
||||
BACNET_ADDRESS* src,
|
||||
BACNET_CONFIRMED_SERVICE_ACK_DATA* service_data);
|
||||
|
||||
// our handler for writeProp acks
|
||||
static void handlerWritePropertyAck(BACNET_ADDRESS* src,
|
||||
uint8_t invoke_id);
|
||||
|
||||
// initialize our service handlers
|
||||
void initServiceHandlers();
|
||||
|
||||
// utility function
|
||||
std::string string2HexString(std::string input);
|
||||
|
||||
// responsible for dispatching a request to the BACnet network
|
||||
bool dispatchRequest();
|
||||
|
||||
private:
|
||||
// prevent copying and assignment
|
||||
BACNETMSTP(BACNETMSTP const &) {};
|
||||
BACNETMSTP& operator=(BACNETMSTP const&) {};
|
||||
|
||||
// our class instance
|
||||
static BACNETMSTP* m_instance;
|
||||
|
||||
// has the class been created yet?
|
||||
bool m_initialized;
|
||||
|
||||
// Some items we can set for our master
|
||||
std::string m_port;
|
||||
int m_maxInfoFrames;
|
||||
int m_maxMaster;
|
||||
int m_baudRate;
|
||||
int m_macAddr;
|
||||
|
||||
// the unique Instance Number of our Master Device Object
|
||||
uint32_t m_deviceInstanceID;
|
||||
|
||||
// adpu timeout in milliseconds
|
||||
uint16_t m_adpuTimeoutMS;
|
||||
|
||||
// buffer used for receiving data
|
||||
uint8_t m_rxBuffer[MAX_MPDU];
|
||||
|
||||
// our error classfication
|
||||
BACERR_TYPE_T m_errorType;
|
||||
|
||||
// BACnet reject info
|
||||
uint8_t m_rejectReason;
|
||||
std::string m_rejectString;
|
||||
|
||||
// BACnet abort info
|
||||
uint8_t m_abortReason;
|
||||
std::string m_abortString;
|
||||
|
||||
// BACnet error info
|
||||
BACNET_ERROR_CLASS m_errorClass;
|
||||
BACNET_ERROR_CODE m_errorCode;
|
||||
std::string m_errorString;
|
||||
|
||||
// generic UPM related errors - we just set the error text to
|
||||
// something informative.
|
||||
std::string m_upmErrorString;
|
||||
|
||||
// our returned data from readProperty()
|
||||
BACNET_APPLICATION_DATA_VALUE m_returnedValue;
|
||||
|
||||
// current bound target address of dispatched service request
|
||||
// (read/write prop, etc)
|
||||
BACNET_ADDRESS m_targetAddress;
|
||||
|
||||
// current invokeID (for transaction handling)
|
||||
uint8_t m_invokeID;
|
||||
|
||||
// error detected flag
|
||||
bool m_errorDetected;
|
||||
|
||||
// Commands - we create a struct to hold the arguments for each
|
||||
// command type we support. Then, we create a command struct
|
||||
// which contains the command type and a union containing the
|
||||
// relevant arguments. This is used by dispatchRequest() to issue
|
||||
// the correct request.
|
||||
|
||||
// these may generate SWIG warnings, but they can be ignored as we
|
||||
// do not expose these outside the class
|
||||
typedef struct {
|
||||
uint32_t targetDeviceInstanceID;
|
||||
BACNET_OBJECT_TYPE objType;
|
||||
uint32_t objInstance;
|
||||
BACNET_PROPERTY_ID objProperty;
|
||||
uint32_t arrayIndex;
|
||||
} READ_PROPERTY_ARGS_T;
|
||||
|
||||
typedef struct {
|
||||
uint32_t targetDeviceInstanceID;
|
||||
BACNET_OBJECT_TYPE objType;
|
||||
uint32_t objInstance;
|
||||
BACNET_PROPERTY_ID objProperty;
|
||||
BACNET_APPLICATION_DATA_VALUE* propValue;
|
||||
uint8_t propPriority;
|
||||
int32_t arrayIndex;
|
||||
} WRITE_PROPERTY_ARGS_T;
|
||||
|
||||
struct {
|
||||
BACCMD_TYPE_T cmd;
|
||||
|
||||
union {
|
||||
READ_PROPERTY_ARGS_T readPropArgs;
|
||||
WRITE_PROPERTY_ARGS_T writePropArgs;
|
||||
};
|
||||
} m_command;
|
||||
|
||||
bool m_debugging;
|
||||
};
|
||||
}
|
1026
src/bacnetmstp/device-client.c
Normal file
1026
src/bacnetmstp/device-client.c
Normal file
File diff suppressed because it is too large
Load Diff
465
src/bacnetmstp/device.h
Normal file
465
src/bacnetmstp/device.h
Normal file
@ -0,0 +1,465 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2005 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*********************************************************************/
|
||||
|
||||
/** @file device.h Defines functions for handling all BACnet objects belonging
|
||||
* to a BACnet device, as well as Device-specific properties. */
|
||||
|
||||
#ifndef DEVICE_H
|
||||
#define DEVICE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "bacdef.h"
|
||||
#include "bacenum.h"
|
||||
#include "wp.h"
|
||||
#include "rd.h"
|
||||
#include "rp.h"
|
||||
#include "rpm.h"
|
||||
#include "readrange.h"
|
||||
|
||||
/** Called so a BACnet object can perform any necessary initialization.
|
||||
* @ingroup ObjHelpers
|
||||
*/
|
||||
typedef void (
|
||||
*object_init_function) (
|
||||
void);
|
||||
|
||||
/** Counts the number of objects of this type.
|
||||
* @ingroup ObjHelpers
|
||||
* @return Count of implemented objects of this type.
|
||||
*/
|
||||
typedef unsigned (
|
||||
*object_count_function) (
|
||||
void);
|
||||
|
||||
/** Maps an object index position to its corresponding BACnet object instance number.
|
||||
* @ingroup ObjHelpers
|
||||
* @param index [in] The index of the object, in the array of objects of its type.
|
||||
* @return The BACnet object instance number to be used in a BACNET_OBJECT_ID.
|
||||
*/
|
||||
typedef uint32_t(
|
||||
*object_index_to_instance_function)
|
||||
(
|
||||
unsigned index);
|
||||
|
||||
/** Provides the BACnet Object_Name for a given object instance of this type.
|
||||
* @ingroup ObjHelpers
|
||||
* @param object_instance [in] The object instance number to be looked up.
|
||||
* @param object_name [in,out] Pointer to a character_string structure that
|
||||
* will hold a copy of the object name if this is a valid object_instance.
|
||||
* @return True if the object_instance is valid and object_name has been
|
||||
* filled with a copy of the Object's name.
|
||||
*/
|
||||
typedef bool(
|
||||
*object_name_function)
|
||||
(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
|
||||
/** Look in the table of objects of this type, and see if this is a valid
|
||||
* instance number.
|
||||
* @ingroup ObjHelpers
|
||||
* @param [in] The object instance number to be looked up.
|
||||
* @return True if the object instance refers to a valid object of this type.
|
||||
*/
|
||||
typedef bool(
|
||||
*object_valid_instance_function) (
|
||||
uint32_t object_instance);
|
||||
|
||||
/** Helper function to step through an array of objects and find either the
|
||||
* first one or the next one of a given type. Used to step through an array
|
||||
* of objects which is not necessarily contiguious for each type i.e. the
|
||||
* index for the 'n'th object of a given type is not necessarily 'n'.
|
||||
* @ingroup ObjHelpers
|
||||
* @param [in] The index of the current object or a value of ~0 to indicate
|
||||
* start at the beginning.
|
||||
* @return The index of the next object of the required type or ~0 (all bits
|
||||
* == 1) to indicate no more objects found.
|
||||
*/
|
||||
typedef unsigned (
|
||||
*object_iterate_function) (
|
||||
unsigned current_index);
|
||||
|
||||
/** Look in the table of objects of this type, and get the COV Value List.
|
||||
* @ingroup ObjHelpers
|
||||
* @param [in] The object instance number to be looked up.
|
||||
* @param [out] The value list
|
||||
* @return True if the object instance supports this feature, and has changed.
|
||||
*/
|
||||
typedef bool(
|
||||
*object_value_list_function) (
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_VALUE * value_list);
|
||||
|
||||
/** Look in the table of objects for this instance to see if value changed.
|
||||
* @ingroup ObjHelpers
|
||||
* @param [in] The object instance number to be looked up.
|
||||
* @return True if the object instance has changed.
|
||||
*/
|
||||
typedef bool(
|
||||
*object_cov_function) (
|
||||
uint32_t object_instance);
|
||||
|
||||
/** Look in the table of objects for this instance to clear the changed flag.
|
||||
* @ingroup ObjHelpers
|
||||
* @param [in] The object instance number to be looked up.
|
||||
*/
|
||||
typedef void (
|
||||
*object_cov_clear_function) (
|
||||
uint32_t object_instance);
|
||||
|
||||
/** Intrinsic Reporting funcionality.
|
||||
* @ingroup ObjHelpers
|
||||
* @param [in] Object instance.
|
||||
*/
|
||||
typedef void (
|
||||
*object_intrinsic_reporting_function) (
|
||||
uint32_t object_instance);
|
||||
|
||||
|
||||
/** Defines the group of object helper functions for any supported Object.
|
||||
* @ingroup ObjHelpers
|
||||
* Each Object must provide some implementation of each of these helpers
|
||||
* in order to properly support the handlers. Eg, the ReadProperty handler
|
||||
* handler_read_property() relies on the instance of Object_Read_Property
|
||||
* for each Object type, or configure the function as NULL.
|
||||
* In both appearance and operation, this group of functions acts like
|
||||
* they are member functions of a C++ Object base class.
|
||||
*/
|
||||
typedef struct object_functions {
|
||||
BACNET_OBJECT_TYPE Object_Type;
|
||||
object_init_function Object_Init;
|
||||
object_count_function Object_Count;
|
||||
object_index_to_instance_function Object_Index_To_Instance;
|
||||
object_valid_instance_function Object_Valid_Instance;
|
||||
object_name_function Object_Name;
|
||||
read_property_function Object_Read_Property;
|
||||
write_property_function Object_Write_Property;
|
||||
rpm_property_lists_function Object_RPM_List;
|
||||
rr_info_function Object_RR_Info;
|
||||
object_iterate_function Object_Iterator;
|
||||
object_value_list_function Object_Value_List;
|
||||
object_cov_function Object_COV;
|
||||
object_cov_clear_function Object_COV_Clear;
|
||||
object_intrinsic_reporting_function Object_Intrinsic_Reporting;
|
||||
} object_functions_t;
|
||||
|
||||
/* String Lengths - excluding any nul terminator */
|
||||
#define MAX_DEV_NAME_LEN 32
|
||||
#define MAX_DEV_LOC_LEN 64
|
||||
#define MAX_DEV_MOD_LEN 32
|
||||
#define MAX_DEV_VER_LEN 16
|
||||
#define MAX_DEV_DESC_LEN 64
|
||||
|
||||
/** Structure to define the Object Properties common to all Objects. */
|
||||
typedef struct commonBacObj_s {
|
||||
|
||||
/** The BACnet type of this object (ie, what class is this object from?).
|
||||
* This property, of type BACnetObjectType, indicates membership in a
|
||||
* particular object type class. Each inherited class will be of one type.
|
||||
*/
|
||||
BACNET_OBJECT_TYPE mObject_Type;
|
||||
|
||||
/** The instance number for this class instance. */
|
||||
uint32_t Object_Instance_Number;
|
||||
|
||||
/** Object Name; must be unique.
|
||||
* This property, of type CharacterString, shall represent a name for
|
||||
* the object that is unique within the BACnet Device that maintains it.
|
||||
*/
|
||||
char Object_Name[MAX_DEV_NAME_LEN];
|
||||
|
||||
} COMMON_BAC_OBJECT;
|
||||
|
||||
|
||||
/** Structure to define the Properties of Device Objects which distinguish
|
||||
* one instance from another.
|
||||
* This structure only defines fields for properties that are unique to
|
||||
* a given Device object. The rest may be fixed in device.c or hard-coded
|
||||
* into the read-property encoding.
|
||||
* This may be useful for implementations which manage multiple Devices,
|
||||
* eg, a Gateway.
|
||||
*/
|
||||
typedef struct devObj_s {
|
||||
/** The BACnet Device Address for this device; ->len depends on DLL type. */
|
||||
BACNET_ADDRESS bacDevAddr;
|
||||
|
||||
/** Structure for the Object Properties common to all Objects. */
|
||||
COMMON_BAC_OBJECT bacObj;
|
||||
|
||||
/** Device Description. */
|
||||
char Description[MAX_DEV_DESC_LEN];
|
||||
|
||||
/** The upcounter that shows if the Device ID or object structure has changed. */
|
||||
uint32_t Database_Revision;
|
||||
} DEVICE_OBJECT_DATA;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
void Device_Init(
|
||||
object_functions_t * object_table);
|
||||
|
||||
bool Device_Reinitialize(
|
||||
BACNET_REINITIALIZE_DEVICE_DATA * rd_data);
|
||||
|
||||
BACNET_REINITIALIZED_STATE Device_Reinitialized_State(
|
||||
void);
|
||||
|
||||
rr_info_function Device_Objects_RR_Info(
|
||||
BACNET_OBJECT_TYPE object_type);
|
||||
|
||||
void Device_getCurrentDateTime(
|
||||
BACNET_DATE_TIME * DateTime);
|
||||
int32_t Device_UTC_Offset(void);
|
||||
bool Device_Daylight_Savings_Status(void);
|
||||
|
||||
void Device_Property_Lists(
|
||||
const int **pRequired,
|
||||
const int **pOptional,
|
||||
const int **pProprietary);
|
||||
void Device_Objects_Property_List(
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
struct special_property_list_t *pPropertyList);
|
||||
/* functions to support COV */
|
||||
bool Device_Encode_Value_List(
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance,
|
||||
BACNET_PROPERTY_VALUE * value_list);
|
||||
bool Device_Value_List_Supported(
|
||||
BACNET_OBJECT_TYPE object_type);
|
||||
bool Device_COV(
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance);
|
||||
void Device_COV_Clear(
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance);
|
||||
|
||||
uint32_t Device_Object_Instance_Number(
|
||||
void);
|
||||
bool Device_Set_Object_Instance_Number(
|
||||
uint32_t object_id);
|
||||
bool Device_Valid_Object_Instance_Number(
|
||||
uint32_t object_id);
|
||||
unsigned Device_Object_List_Count(
|
||||
void);
|
||||
bool Device_Object_List_Identifier(
|
||||
unsigned array_index,
|
||||
int *object_type,
|
||||
uint32_t * instance);
|
||||
|
||||
unsigned Device_Count(
|
||||
void);
|
||||
uint32_t Device_Index_To_Instance(
|
||||
unsigned index);
|
||||
|
||||
bool Device_Object_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Device_Set_Object_Name(
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
/* Copy a child object name, given its ID. */
|
||||
bool Device_Object_Name_Copy(
|
||||
BACNET_OBJECT_TYPE object_type,
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
bool Device_Object_Name_ANSI_Init(const char * value);
|
||||
|
||||
BACNET_DEVICE_STATUS Device_System_Status(
|
||||
void);
|
||||
int Device_Set_System_Status(
|
||||
BACNET_DEVICE_STATUS status,
|
||||
bool local);
|
||||
|
||||
const char *Device_Vendor_Name(
|
||||
void);
|
||||
|
||||
uint16_t Device_Vendor_Identifier(
|
||||
void);
|
||||
void Device_Set_Vendor_Identifier(
|
||||
uint16_t vendor_id);
|
||||
|
||||
const char *Device_Model_Name(
|
||||
void);
|
||||
bool Device_Set_Model_Name(
|
||||
const char *name,
|
||||
size_t length);
|
||||
|
||||
const char *Device_Firmware_Revision(
|
||||
void);
|
||||
|
||||
const char *Device_Application_Software_Version(
|
||||
void);
|
||||
bool Device_Set_Application_Software_Version(
|
||||
const char *name,
|
||||
size_t length);
|
||||
|
||||
const char *Device_Description(
|
||||
void);
|
||||
bool Device_Set_Description(
|
||||
const char *name,
|
||||
size_t length);
|
||||
|
||||
const char *Device_Location(
|
||||
void);
|
||||
bool Device_Set_Location(
|
||||
const char *name,
|
||||
size_t length);
|
||||
|
||||
/* some stack-centric constant values - no set methods */
|
||||
uint8_t Device_Protocol_Version(
|
||||
void);
|
||||
uint8_t Device_Protocol_Revision(
|
||||
void);
|
||||
BACNET_SEGMENTATION Device_Segmentation_Supported(
|
||||
void);
|
||||
|
||||
uint32_t Device_Database_Revision(
|
||||
void);
|
||||
void Device_Set_Database_Revision(
|
||||
uint32_t revision);
|
||||
void Device_Inc_Database_Revision(
|
||||
void);
|
||||
|
||||
bool Device_Valid_Object_Name(
|
||||
BACNET_CHARACTER_STRING * object_name,
|
||||
int *object_type,
|
||||
uint32_t * object_instance);
|
||||
bool Device_Valid_Object_Id(
|
||||
int object_type,
|
||||
uint32_t object_instance);
|
||||
|
||||
int Device_Read_Property(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Device_Write_Property(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
bool DeviceGetRRInfo(
|
||||
BACNET_READ_RANGE_DATA * pRequest, /* Info on the request */
|
||||
RR_PROP_INFO * pInfo); /* Where to put the information */
|
||||
|
||||
int Device_Read_Property_Local(
|
||||
BACNET_READ_PROPERTY_DATA * rpdata);
|
||||
bool Device_Write_Property_Local(
|
||||
BACNET_WRITE_PROPERTY_DATA * wp_data);
|
||||
|
||||
#if defined(INTRINSIC_REPORTING)
|
||||
void Device_local_reporting(
|
||||
void);
|
||||
#endif
|
||||
|
||||
/* Prototypes for Routing functionality in the Device Object.
|
||||
* Enable by defining BAC_ROUTING in config.h and including gw_device.c
|
||||
* in the build (lib/Makefile).
|
||||
*/
|
||||
void Routing_Device_Init(
|
||||
uint32_t first_object_instance);
|
||||
|
||||
uint16_t Add_Routed_Device(
|
||||
uint32_t Object_Instance,
|
||||
BACNET_CHARACTER_STRING * Object_Name,
|
||||
const char *Description);
|
||||
DEVICE_OBJECT_DATA *Get_Routed_Device_Object(
|
||||
int idx);
|
||||
BACNET_ADDRESS *Get_Routed_Device_Address(
|
||||
int idx);
|
||||
|
||||
void routed_get_my_address(
|
||||
BACNET_ADDRESS * my_address);
|
||||
|
||||
bool Routed_Device_Address_Lookup(
|
||||
int idx,
|
||||
uint8_t address_len,
|
||||
uint8_t * mac_adress);
|
||||
bool Routed_Device_GetNext(
|
||||
BACNET_ADDRESS * dest,
|
||||
int *DNET_list,
|
||||
int *cursor);
|
||||
bool Routed_Device_Is_Valid_Network(
|
||||
uint16_t dest_net,
|
||||
int *DNET_list);
|
||||
|
||||
uint32_t Routed_Device_Index_To_Instance(
|
||||
unsigned index);
|
||||
bool Routed_Device_Valid_Object_Instance_Number(
|
||||
uint32_t object_id);
|
||||
bool Routed_Device_Name(
|
||||
uint32_t object_instance,
|
||||
BACNET_CHARACTER_STRING * object_name);
|
||||
uint32_t Routed_Device_Object_Instance_Number(
|
||||
void);
|
||||
bool Routed_Device_Set_Object_Instance_Number(
|
||||
uint32_t object_id);
|
||||
bool Routed_Device_Set_Object_Name(
|
||||
uint8_t encoding,
|
||||
const char *value,
|
||||
size_t length);
|
||||
bool Routed_Device_Set_Description(
|
||||
const char *name,
|
||||
size_t length);
|
||||
void Routed_Device_Inc_Database_Revision(
|
||||
void);
|
||||
int Routed_Device_Service_Approval(
|
||||
BACNET_CONFIRMED_SERVICE service,
|
||||
int service_argument,
|
||||
uint8_t * apdu_buff,
|
||||
uint8_t invoke_id);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
/** @defgroup ObjFrmwk Object Framework
|
||||
* The modules in this section describe the BACnet-stack's framework for
|
||||
* BACnet-defined Objects (Device, Analog Input, etc). There are two submodules
|
||||
* to describe this arrangement:
|
||||
* - The "object helper functions" which provide C++-like common functionality
|
||||
* to all supported object types.
|
||||
* - The interface between the implemented Objects and the BAC-stack services,
|
||||
* specifically the handlers, which are mediated through function calls to
|
||||
* the Device object.
|
||||
*//** @defgroup ObjHelpers Object Helper Functions
|
||||
* @ingroup ObjFrmwk
|
||||
* This section describes the function templates for the helper functions that
|
||||
* provide common object support.
|
||||
*//** @defgroup ObjIntf Handler-to-Object Interface Functions
|
||||
* @ingroup ObjFrmwk
|
||||
* This section describes the fairly limited set of functions that link the
|
||||
* BAC-stack handlers to the BACnet Object instances. All of these calls are
|
||||
* situated in the Device Object, which "knows" how to reach its child Objects.
|
||||
*
|
||||
* Most of these calls have a common operation:
|
||||
* -# Call Device_Objects_Find_Functions( for the desired Object_Type )
|
||||
* - Gets a pointer to the object_functions for this Type of Object.
|
||||
* -# Call the Object's Object_Valid_Instance( for the desired object_instance )
|
||||
* to make sure there is such an instance.
|
||||
* -# Call the Object helper function needed by the handler,
|
||||
* eg Object_Read_Property() for the RP handler.
|
||||
*
|
||||
*/
|
||||
#endif
|
23
src/bacnetmstp/javaupm_bacnetmstp.i
Normal file
23
src/bacnetmstp/javaupm_bacnetmstp.i
Normal file
@ -0,0 +1,23 @@
|
||||
%module javaupm_bacnetmstp
|
||||
%include "../upm.i"
|
||||
%include "typemaps.i"
|
||||
%include "cpointer.i"
|
||||
%include "arrays_java.i";
|
||||
%include "../java_buffer.i"
|
||||
|
||||
%{
|
||||
#include "bacnetmstp.h"
|
||||
%}
|
||||
|
||||
%include "bacnetmstp.h"
|
||||
|
||||
%pragma(java) jniclasscode=%{
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("javaupm_bacnetmstp");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
System.err.println("Native code library failed to load. \n" + e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
%}
|
11
src/bacnetmstp/jsupm_bacnetmstp.i
Normal file
11
src/bacnetmstp/jsupm_bacnetmstp.i
Normal file
@ -0,0 +1,11 @@
|
||||
%module jsupm_bacnetmstp
|
||||
%include "../upm.i"
|
||||
%include "stdint.i"
|
||||
%include "cpointer.i"
|
||||
|
||||
%pointer_functions(float, floatp);
|
||||
|
||||
%include "bacnetmstp.h"
|
||||
%{
|
||||
#include "bacnetmstp.h"
|
||||
%}
|
15
src/bacnetmstp/pyupm_bacnetmstp.i
Normal file
15
src/bacnetmstp/pyupm_bacnetmstp.i
Normal file
@ -0,0 +1,15 @@
|
||||
// Include doxygen-generated documentation
|
||||
%include "pyupm_doxy2swig.i"
|
||||
%module pyupm_bacnetmstp
|
||||
%include "../upm.i"
|
||||
%include "stdint.i"
|
||||
%include "cpointer.i"
|
||||
|
||||
%feature("autodoc", "3");
|
||||
|
||||
%pointer_functions(float, floatp);
|
||||
|
||||
%include "bacnetmstp.h"
|
||||
%{
|
||||
#include "bacnetmstp.h"
|
||||
%}
|
65
src/bacnetmstp/timer.h
Normal file
65
src/bacnetmstp/timer.h
Normal file
@ -0,0 +1,65 @@
|
||||
/**************************************************************************
|
||||
*
|
||||
* Copyright (C) 2009 Steve Karg <skarg@users.sourceforge.net>
|
||||
*
|
||||
* 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.
|
||||
*********************************************************************/
|
||||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/time.h> /* for timeval */
|
||||
|
||||
/* Timer Module */
|
||||
#ifndef MAX_MILLISECOND_TIMERS
|
||||
#define TIMER_SILENCE 0
|
||||
#define MAX_MILLISECOND_TIMERS 1
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
uint32_t timeGetTime(
|
||||
void);
|
||||
|
||||
void timer_init(
|
||||
void);
|
||||
uint32_t timer_milliseconds(
|
||||
unsigned index);
|
||||
bool timer_elapsed_milliseconds(
|
||||
unsigned index,
|
||||
uint32_t value);
|
||||
bool timer_elapsed_seconds(
|
||||
unsigned index,
|
||||
uint32_t value);
|
||||
bool timer_elapsed_minutes(
|
||||
unsigned index,
|
||||
uint32_t seconds);
|
||||
uint32_t timer_milliseconds_set(
|
||||
unsigned index,
|
||||
uint32_t value);
|
||||
uint32_t timer_reset(
|
||||
unsigned index);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif
|
@ -31,7 +31,7 @@
|
||||
#include "bme280.h"
|
||||
#include "bme280driver.h"
|
||||
/************** I2C buffer length ******/
|
||||
#define I2C_BUFFER_LEN 26
|
||||
#define I2C_BUFFER_LEN 26
|
||||
|
||||
|
||||
|
||||
@ -41,13 +41,13 @@ using namespace upm;
|
||||
|
||||
|
||||
/*----------------------------------------------------------------------------*
|
||||
* struct bme280_t parameters can be accessed by using bme280
|
||||
* bme280_t having the following parameters
|
||||
* Bus write function pointer: BME280_WR_FUNC_PTR
|
||||
Bus read function pointer: BME280_RD_FUNC_PTR
|
||||
* Delay function pointer: delay_msec
|
||||
* I2C address: dev_addr
|
||||
* Chip id of the sensor: chip_id
|
||||
* struct bme280_t parameters can be accessed by using bme280
|
||||
* bme280_t having the following parameters
|
||||
* Bus write function pointer: BME280_WR_FUNC_PTR
|
||||
Bus read function pointer: BME280_RD_FUNC_PTR
|
||||
* Delay function pointer: delay_msec
|
||||
* I2C address: dev_addr
|
||||
* Chip id of the sensor: chip_id
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
struct bme280_t bme280;
|
||||
@ -57,23 +57,23 @@ mraa::I2c* BME280::m_i2c = NULL;
|
||||
int BME280::m_bus = 0;
|
||||
|
||||
BME280::BME280 (int bus, int devAddr) {
|
||||
m_bus = bus;
|
||||
if( m_i2c == NULL)
|
||||
{
|
||||
m_i2c = new mraa::I2c(m_bus);
|
||||
m_i2c->address(BME280_I2C_ADDRESS1);
|
||||
//Based on the requirement, configure I2C interface.
|
||||
I2C_routine();
|
||||
/*--------------------------------------------------------------------------*
|
||||
* This function used to assign the value/reference of
|
||||
* the following parameters
|
||||
* I2C address
|
||||
* Bus Write
|
||||
* Bus read
|
||||
* Chip id
|
||||
*-------------------------------------------------------------------------*/
|
||||
bme280_init(&bme280);
|
||||
}
|
||||
m_bus = bus;
|
||||
if( m_i2c == NULL)
|
||||
{
|
||||
m_i2c = new mraa::I2c(m_bus);
|
||||
m_i2c->address(BME280_I2C_ADDRESS1);
|
||||
//Based on the requirement, configure I2C interface.
|
||||
I2C_routine();
|
||||
/*--------------------------------------------------------------------------*
|
||||
* This function used to assign the value/reference of
|
||||
* the following parameters
|
||||
* I2C address
|
||||
* Bus Write
|
||||
* Bus read
|
||||
* Chip id
|
||||
*-------------------------------------------------------------------------*/
|
||||
bme280_init(&bme280);
|
||||
}
|
||||
}
|
||||
|
||||
BME280::~BME280() {
|
||||
@ -81,21 +81,21 @@ BME280::~BME280() {
|
||||
}
|
||||
|
||||
/* This function is an example for reading sensor temperature
|
||||
* \param: None
|
||||
* \return: compensated temperature
|
||||
* \param: None
|
||||
* \return: compensated temperature
|
||||
*/
|
||||
|
||||
int32_t BME280::getTemperatureInternal(void)
|
||||
{
|
||||
/* The variable used to read uncompensated temperature*/
|
||||
int32_t v_data_uncomp_tem_int32 = getTemperatureRawInternal();
|
||||
/* The variable used to read uncompensated temperature*/
|
||||
int32_t v_data_uncomp_tem_int32 = getTemperatureRawInternal();
|
||||
|
||||
/*------------------------------------------------------------------*
|
||||
************ START READ TRUE PRESSURE, TEMPERATURE AND HUMIDITY DATA ********
|
||||
*---------------------------------------------------------------------*/
|
||||
/* API is used to read the true temperature*/
|
||||
/* Input value as uncompensated temperature and output format*/
|
||||
int32_t v_actual_temp_int32 = bme280_compensate_temperature_int32(v_data_uncomp_tem_int32);
|
||||
/* API is used to read the true temperature*/
|
||||
/* Input value as uncompensated temperature and output format*/
|
||||
int32_t v_actual_temp_int32 = bme280_compensate_temperature_int32(v_data_uncomp_tem_int32);
|
||||
/*--------------------------------------------------------------------*
|
||||
************ END READ TRUE TEMPERATURE ********
|
||||
*-------------------------------------------------------------------------*/
|
||||
@ -104,22 +104,22 @@ return v_actual_temp_int32;
|
||||
}
|
||||
|
||||
/* This function is an example for reading sensor pressure
|
||||
* \param: None
|
||||
* \return: compensated pressure
|
||||
* \param: None
|
||||
* \return: compensated pressure
|
||||
*/
|
||||
|
||||
int32_t BME280::getPressureInternal(void)
|
||||
{
|
||||
/* The variable used to read uncompensated pressure*/
|
||||
int32_t v_data_uncomp_pres_int32 = getPressureRawInternal();
|
||||
/* The variable used to read uncompensated pressure*/
|
||||
int32_t v_data_uncomp_pres_int32 = getPressureRawInternal();
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*
|
||||
************ START READ TRUE PRESSURE DATA ********
|
||||
*---------------------------------------------------------------------*/
|
||||
/* API is used to read the true pressure*/
|
||||
/* Input value as uncompensated pressure */
|
||||
uint32_t v_actual_press_uint32 = bme280_compensate_pressure_int32(v_data_uncomp_pres_int32);
|
||||
/* API is used to read the true pressure*/
|
||||
/* Input value as uncompensated pressure */
|
||||
uint32_t v_actual_press_uint32 = bme280_compensate_pressure_int32(v_data_uncomp_pres_int32);
|
||||
|
||||
/*--------------------------------------------------------------------*
|
||||
************ END READ TRUE PRESSURE ********
|
||||
@ -130,21 +130,21 @@ return v_actual_press_uint32;
|
||||
|
||||
|
||||
/* This function is an example for reading sensor humidity
|
||||
* \param: None
|
||||
* \return: compensated humidity
|
||||
* \param: None
|
||||
* \return: compensated humidity
|
||||
*/
|
||||
|
||||
int32_t BME280::getHumidityInternal(void)
|
||||
{
|
||||
/* The variable used to read uncompensated pressure*/
|
||||
int32_t v_data_uncomp_hum_int32 = getHumidityRawInternal();
|
||||
/* The variable used to read uncompensated pressure*/
|
||||
int32_t v_data_uncomp_hum_int32 = getHumidityRawInternal();
|
||||
|
||||
/*------------------------------------------------------------------*
|
||||
************ START READ TRUE HUMIDITY DATA ********
|
||||
*---------------------------------------------------------------------*/
|
||||
/* API is used to read the true humidity*/
|
||||
/* Input value as uncompensated humidity and output format*/
|
||||
uint32_t v_actual_humity_uint32 = bme280_compensate_humidity_int32(v_data_uncomp_hum_int32);
|
||||
/* API is used to read the true humidity*/
|
||||
/* Input value as uncompensated humidity and output format*/
|
||||
uint32_t v_actual_humity_uint32 = bme280_compensate_humidity_int32(v_data_uncomp_hum_int32);
|
||||
|
||||
/*--------------------------------------------------------------------*
|
||||
************ END READ TRUE HUMIDITY ********
|
||||
@ -156,37 +156,37 @@ return v_actual_humity_uint32;
|
||||
|
||||
|
||||
/* This function is an example for reading sensor temperature
|
||||
* \param: None
|
||||
* \return: uncompensated temperature
|
||||
* \param: None
|
||||
* \return: uncompensated temperature
|
||||
*/
|
||||
|
||||
int32_t BME280::getTemperatureRawInternal(void)
|
||||
{
|
||||
/* The variable used to read uncompensated temperature*/
|
||||
int32_t v_data_uncomp_tem_int32 = BME280_INIT_VALUE;
|
||||
/* The variable used to read uncompensated temperature*/
|
||||
int32_t v_data_uncomp_tem_int32 = BME280_INIT_VALUE;
|
||||
|
||||
/* For initialization it is required to set the mode of
|
||||
* the sensor as "NORMAL"
|
||||
* data acquisition/read/write is possible in this mode
|
||||
* by using the below API able to set the power mode as NORMAL*/
|
||||
/* Set the power mode as NORMAL*/
|
||||
bme280_set_power_mode(BME280_NORMAL_MODE);
|
||||
/* For reading the temperature data it is required to
|
||||
* set the OSS setting of temperature
|
||||
* In the code automated reading and writing of "BME280_CTRLHUM_REG_OSRSH"
|
||||
* register first set the "BME280_CTRLHUM_REG_OSRSH" and then read and write
|
||||
* the "BME280_CTRLMEAS_REG" register in the function*/
|
||||
/* For initialization it is required to set the mode of
|
||||
* the sensor as "NORMAL"
|
||||
* data acquisition/read/write is possible in this mode
|
||||
* by using the below API able to set the power mode as NORMAL*/
|
||||
/* Set the power mode as NORMAL*/
|
||||
bme280_set_power_mode(BME280_NORMAL_MODE);
|
||||
/* For reading the temperature data it is required to
|
||||
* set the OSS setting of temperature
|
||||
* In the code automated reading and writing of "BME280_CTRLHUM_REG_OSRSH"
|
||||
* register first set the "BME280_CTRLHUM_REG_OSRSH" and then read and write
|
||||
* the "BME280_CTRLMEAS_REG" register in the function*/
|
||||
|
||||
/* set the temperature oversampling*/
|
||||
bme280_set_oversamp_temperature(BME280_OVERSAMP_4X);
|
||||
/* set the temperature oversampling*/
|
||||
bme280_set_oversamp_temperature(BME280_OVERSAMP_4X);
|
||||
|
||||
/************************* END INITIALIZATION *************************/
|
||||
|
||||
/*------------------------------------------------------------------*
|
||||
************ START READ UNCOMPENSATED TEMPERATURE DATA ********
|
||||
*---------------------------------------------------------------------*/
|
||||
/* API is used to read the uncompensated temperature*/
|
||||
bme280_read_uncomp_temperature(&v_data_uncomp_tem_int32);
|
||||
/* API is used to read the uncompensated temperature*/
|
||||
bme280_read_uncomp_temperature(&v_data_uncomp_tem_int32);
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------*
|
||||
@ -196,14 +196,14 @@ int32_t BME280::getTemperatureRawInternal(void)
|
||||
/*-----------------------------------------------------------------------*
|
||||
************************* START DE-INITIALIZATION ***********************
|
||||
*-------------------------------------------------------------------------*/
|
||||
/* For de-initialization it is required to set the mode of
|
||||
* the sensor as "SLEEP"
|
||||
* the device reaches the lowest power consumption only
|
||||
* In SLEEP mode no measurements are performed
|
||||
* All registers are accessible
|
||||
* by using the below API able to set the power mode as SLEEP*/
|
||||
/* Set the power mode as SLEEP*/
|
||||
bme280_set_power_mode(BME280_SLEEP_MODE);
|
||||
/* For de-initialization it is required to set the mode of
|
||||
* the sensor as "SLEEP"
|
||||
* the device reaches the lowest power consumption only
|
||||
* In SLEEP mode no measurements are performed
|
||||
* All registers are accessible
|
||||
* by using the below API able to set the power mode as SLEEP*/
|
||||
/* Set the power mode as SLEEP*/
|
||||
bme280_set_power_mode(BME280_SLEEP_MODE);
|
||||
/*---------------------------------------------------------------------*
|
||||
************************* END DE-INITIALIZATION **********************
|
||||
*---------------------------------------------------------------------*/
|
||||
@ -211,34 +211,34 @@ return v_data_uncomp_tem_int32;
|
||||
}
|
||||
|
||||
/* This function is an example for reading sensor pressure
|
||||
* \param: None
|
||||
* \return: uncompensated pressure
|
||||
* \param: None
|
||||
* \return: uncompensated pressure
|
||||
*/
|
||||
|
||||
int32_t BME280::getPressureRawInternal(void)
|
||||
{
|
||||
/* The variable used to read uncompensated pressure*/
|
||||
int32_t v_data_uncomp_pres_int32 = BME280_INIT_VALUE;
|
||||
/* The variable used to read uncompensated pressure*/
|
||||
int32_t v_data_uncomp_pres_int32 = BME280_INIT_VALUE;
|
||||
|
||||
|
||||
/* For initialization it is required to set the mode of
|
||||
* the sensor as "NORMAL"
|
||||
* data acquisition/read/write is possible in this mode
|
||||
* by using the below API able to set the power mode as NORMAL*/
|
||||
/* Set the power mode as NORMAL*/
|
||||
bme280_set_power_mode(BME280_NORMAL_MODE);
|
||||
/* For reading the pressure data it is required to
|
||||
* set the OSS setting of humidity, pressure and temperature
|
||||
* The "BME280_CTRLHUM_REG_OSRSH" register sets the humidity
|
||||
* data acquisition options of the device.
|
||||
* changes to this registers only become effective after a write operation to
|
||||
* "BME280_CTRLMEAS_REG" register.
|
||||
* In the code automated reading and writing of "BME280_CTRLHUM_REG_OSRSH"
|
||||
* register first set the "BME280_CTRLHUM_REG_OSRSH" and then read and write
|
||||
* the "BME280_CTRLMEAS_REG" register in the function*/
|
||||
/* For initialization it is required to set the mode of
|
||||
* the sensor as "NORMAL"
|
||||
* data acquisition/read/write is possible in this mode
|
||||
* by using the below API able to set the power mode as NORMAL*/
|
||||
/* Set the power mode as NORMAL*/
|
||||
bme280_set_power_mode(BME280_NORMAL_MODE);
|
||||
/* For reading the pressure data it is required to
|
||||
* set the OSS setting of humidity, pressure and temperature
|
||||
* The "BME280_CTRLHUM_REG_OSRSH" register sets the humidity
|
||||
* data acquisition options of the device.
|
||||
* changes to this registers only become effective after a write operation to
|
||||
* "BME280_CTRLMEAS_REG" register.
|
||||
* In the code automated reading and writing of "BME280_CTRLHUM_REG_OSRSH"
|
||||
* register first set the "BME280_CTRLHUM_REG_OSRSH" and then read and write
|
||||
* the "BME280_CTRLMEAS_REG" register in the function*/
|
||||
|
||||
/* set the pressure oversampling*/
|
||||
bme280_set_oversamp_pressure(BME280_OVERSAMP_2X);
|
||||
/* set the pressure oversampling*/
|
||||
bme280_set_oversamp_pressure(BME280_OVERSAMP_2X);
|
||||
|
||||
/************************* END INITIALIZATION *************************/
|
||||
|
||||
@ -246,8 +246,8 @@ int32_t BME280::getPressureRawInternal(void)
|
||||
************ START READ UNCOMPENSATED PRESSURE DATA ********
|
||||
*---------------------------------------------------------------------*/
|
||||
|
||||
/* API is used to read the uncompensated pressure*/
|
||||
bme280_read_uncomp_pressure(&v_data_uncomp_pres_int32);
|
||||
/* API is used to read the uncompensated pressure*/
|
||||
bme280_read_uncomp_pressure(&v_data_uncomp_pres_int32);
|
||||
|
||||
/*--------------------------------------------------------------------*
|
||||
************ END READ UNCOMPENSATED PRESSURE ********
|
||||
@ -257,14 +257,14 @@ int32_t BME280::getPressureRawInternal(void)
|
||||
/*-----------------------------------------------------------------------*
|
||||
************************* START DE-INITIALIZATION ***********************
|
||||
*-------------------------------------------------------------------------*/
|
||||
/* For de-initialization it is required to set the mode of
|
||||
* the sensor as "SLEEP"
|
||||
* the device reaches the lowest power consumption only
|
||||
* In SLEEP mode no measurements are performed
|
||||
* All registers are accessible
|
||||
* by using the below API able to set the power mode as SLEEP*/
|
||||
/* Set the power mode as SLEEP*/
|
||||
bme280_set_power_mode(BME280_SLEEP_MODE);
|
||||
/* For de-initialization it is required to set the mode of
|
||||
* the sensor as "SLEEP"
|
||||
* the device reaches the lowest power consumption only
|
||||
* In SLEEP mode no measurements are performed
|
||||
* All registers are accessible
|
||||
* by using the below API able to set the power mode as SLEEP*/
|
||||
/* Set the power mode as SLEEP*/
|
||||
bme280_set_power_mode(BME280_SLEEP_MODE);
|
||||
/*---------------------------------------------------------------------*
|
||||
************************* END DE-INITIALIZATION **********************
|
||||
*---------------------------------------------------------------------*/
|
||||
@ -273,31 +273,31 @@ return v_data_uncomp_pres_int32;
|
||||
|
||||
|
||||
/* This function is an example for reading sensor humidity
|
||||
* \param: None
|
||||
* \return: uncompensated humidity
|
||||
* \param: None
|
||||
* \return: uncompensated humidity
|
||||
*/
|
||||
|
||||
int32_t BME280::getHumidityRawInternal(void)
|
||||
{
|
||||
/* The variable used to read uncompensated pressure*/
|
||||
int32_t v_data_uncomp_hum_int32 = BME280_INIT_VALUE;
|
||||
/* The variable used to read uncompensated pressure*/
|
||||
int32_t v_data_uncomp_hum_int32 = BME280_INIT_VALUE;
|
||||
|
||||
/* For initialization it is required to set the mode of
|
||||
* the sensor as "NORMAL"
|
||||
* data acquisition/read/write is possible in this mode
|
||||
* by using the below API able to set the power mode as NORMAL*/
|
||||
/* Set the power mode as NORMAL*/
|
||||
bme280_set_power_mode(BME280_NORMAL_MODE);
|
||||
/* For reading humidity data it is required to
|
||||
* set the OSS setting of humidity
|
||||
* The "BME280_CTRLHUM_REG_OSRSH" register sets the humidity
|
||||
* data acquisition options of the device.
|
||||
* changes to this registers only become effective after a write operation to
|
||||
* "BME280_CTRLMEAS_REG" register.
|
||||
* In the code automated reading and writing of "BME280_CTRLHUM_REG_OSRSH"
|
||||
* register first set the "BME280_CTRLHUM_REG_OSRSH" and then read and write
|
||||
* the "BME280_CTRLMEAS_REG" register in the function*/
|
||||
bme280_set_oversamp_humidity(BME280_OVERSAMP_1X);
|
||||
/* For initialization it is required to set the mode of
|
||||
* the sensor as "NORMAL"
|
||||
* data acquisition/read/write is possible in this mode
|
||||
* by using the below API able to set the power mode as NORMAL*/
|
||||
/* Set the power mode as NORMAL*/
|
||||
bme280_set_power_mode(BME280_NORMAL_MODE);
|
||||
/* For reading humidity data it is required to
|
||||
* set the OSS setting of humidity
|
||||
* The "BME280_CTRLHUM_REG_OSRSH" register sets the humidity
|
||||
* data acquisition options of the device.
|
||||
* changes to this registers only become effective after a write operation to
|
||||
* "BME280_CTRLMEAS_REG" register.
|
||||
* In the code automated reading and writing of "BME280_CTRLHUM_REG_OSRSH"
|
||||
* register first set the "BME280_CTRLHUM_REG_OSRSH" and then read and write
|
||||
* the "BME280_CTRLMEAS_REG" register in the function*/
|
||||
bme280_set_oversamp_humidity(BME280_OVERSAMP_1X);
|
||||
|
||||
|
||||
/************************* END INITIALIZATION *************************/
|
||||
@ -305,7 +305,7 @@ int32_t BME280::getHumidityRawInternal(void)
|
||||
/*------------------------------------------------------------------*
|
||||
************ START READ HUMIDITY DATA ********
|
||||
*---------------------------------------------------------------------*/
|
||||
/* API is used to read the uncompensated humidity*/
|
||||
/* API is used to read the uncompensated humidity*/
|
||||
bme280_read_uncomp_humidity(&v_data_uncomp_hum_int32);
|
||||
|
||||
/*--------------------------------------------------------------------*
|
||||
@ -316,14 +316,14 @@ int32_t BME280::getHumidityRawInternal(void)
|
||||
/*-----------------------------------------------------------------------*
|
||||
************************* START DE-INITIALIZATION ***********************
|
||||
*-------------------------------------------------------------------------*/
|
||||
/* For de-initialization it is required to set the mode of
|
||||
* the sensor as "SLEEP"
|
||||
* the device reaches the lowest power consumption only
|
||||
* In SLEEP mode no measurements are performed
|
||||
* All registers are accessible
|
||||
* by using the below API able to set the power mode as SLEEP*/
|
||||
/* Set the power mode as SLEEP*/
|
||||
bme280_set_power_mode(BME280_SLEEP_MODE);
|
||||
/* For de-initialization it is required to set the mode of
|
||||
* the sensor as "SLEEP"
|
||||
* the device reaches the lowest power consumption only
|
||||
* In SLEEP mode no measurements are performed
|
||||
* All registers are accessible
|
||||
* by using the below API able to set the power mode as SLEEP*/
|
||||
/* Set the power mode as SLEEP*/
|
||||
bme280_set_power_mode(BME280_SLEEP_MODE);
|
||||
/*---------------------------------------------------------------------*
|
||||
************************* END DE-INITIALIZATION **********************
|
||||
*---------------------------------------------------------------------*/
|
||||
@ -335,120 +335,118 @@ return v_data_uncomp_hum_int32;
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*
|
||||
* The following function is used to map the I2C bus read, write, delay and
|
||||
* device address with global structure bme280
|
||||
* The following function is used to map the I2C bus read, write, delay and
|
||||
* device address with global structure bme280
|
||||
*-------------------------------------------------------------------------*/
|
||||
int8_t BME280::I2C_routine()
|
||||
{
|
||||
{
|
||||
/*--------------------------------------------------------------------------*
|
||||
* By using bme280 the following structure parameter can be accessed
|
||||
* Bus write function pointer: BME280_WR_FUNC_PTR
|
||||
* Bus read function pointer: BME280_RD_FUNC_PTR
|
||||
* Delay function pointer: delay_msec
|
||||
* I2C address: dev_addr
|
||||
* Bus write function pointer: BME280_WR_FUNC_PTR
|
||||
* Bus read function pointer: BME280_RD_FUNC_PTR
|
||||
* Delay function pointer: delay_msec
|
||||
* I2C address: dev_addr
|
||||
*--------------------------------------------------------------------------*/
|
||||
// bme280.bus_write = &BME280::BME280_I2C_bus_write;
|
||||
bme280.bus_write = BME280_I2C_bus_write;
|
||||
// bme280.bus_write = &BME280::BME280_I2C_bus_write;
|
||||
bme280.bus_write = BME280_I2C_bus_write;
|
||||
|
||||
//bme280.bus_write = BME280_I2C_bus_write_dummy;
|
||||
bme280.bus_read = BME280_I2C_bus_read;
|
||||
bme280.dev_addr = BME280_I2C_ADDRESS1;
|
||||
bme280.delay_msec = BME280_delay_msek;
|
||||
//bme280.bus_write = BME280_I2C_bus_write_dummy;
|
||||
bme280.bus_read = BME280_I2C_bus_read;
|
||||
bme280.dev_addr = BME280_I2C_ADDRESS1;
|
||||
bme280.delay_msec = BME280_delay_msek;
|
||||
|
||||
return BME280_INIT_VALUE;
|
||||
return BME280_INIT_VALUE;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------*
|
||||
* The device address defined in the bme280.h file
|
||||
* The device address defined in the bme280.h file
|
||||
*-----------------------------------------------------------------------*/
|
||||
int32_t BME280::i2c_write_string(uint8_t dev_addr,uint8_t* ptr, uint8_t cnt)
|
||||
{
|
||||
mraa::Result ret;
|
||||
m_i2c->address(dev_addr);
|
||||
|
||||
if((ret = m_i2c->write((const uint8_t*) (ptr), cnt)) != 0)
|
||||
{
|
||||
UPM_THROW("I2C write error");
|
||||
|
||||
}
|
||||
mraa::Result ret;
|
||||
m_i2c->address(dev_addr);
|
||||
|
||||
if((ret = m_i2c->write((const uint8_t*) (ptr), cnt)) != 0)
|
||||
{
|
||||
UPM_THROW("I2C write error");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* \Brief: The function is used as I2C bus write
|
||||
* \Return : Status of the I2C write
|
||||
* \param dev_addr : The device address of the sensor
|
||||
* \param reg_addr : Address of the first register, will data is going to be written
|
||||
* \param reg_data : It is a value hold in the array,
|
||||
* will be used for write the value into the register
|
||||
* \param cnt : The no of byte of data to be write
|
||||
/* \Brief: The function is used as I2C bus write
|
||||
* \Return : Status of the I2C write
|
||||
* \param dev_addr : The device address of the sensor
|
||||
* \param reg_addr : Address of the first register, will data is going to be written
|
||||
* \param reg_data : It is a value hold in the array,
|
||||
* will be used for write the value into the register
|
||||
* \param cnt : The no of byte of data to be write
|
||||
*/
|
||||
|
||||
int8_t BME280::BME280_I2C_bus_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t cnt)
|
||||
|
||||
{
|
||||
int32_t iError = BME280_INIT_VALUE;
|
||||
static uint8_t array[I2C_BUFFER_LEN];
|
||||
int32_t iError = BME280_INIT_VALUE;
|
||||
static uint8_t array[I2C_BUFFER_LEN];
|
||||
for (int i=0; i<I2C_BUFFER_LEN; i++) array[i]=0;
|
||||
|
||||
uint8_t stringpos = BME280_INIT_VALUE;
|
||||
array[BME280_INIT_VALUE] = reg_addr;
|
||||
for (stringpos = BME280_INIT_VALUE; stringpos < cnt; stringpos++) {
|
||||
array[stringpos + BME280_ONE_U8X] = *(reg_data + stringpos);
|
||||
}
|
||||
iError = i2c_write_string(dev_addr,array, cnt+1);
|
||||
return (int8_t)iError;
|
||||
uint8_t stringpos = BME280_INIT_VALUE;
|
||||
array[BME280_INIT_VALUE] = reg_addr;
|
||||
for (stringpos = BME280_INIT_VALUE; stringpos < cnt; stringpos++) {
|
||||
array[stringpos + BME280_ONE_U8X] = *(reg_data + stringpos);
|
||||
}
|
||||
iError = i2c_write_string(dev_addr,array, cnt+1);
|
||||
return (int8_t)iError;
|
||||
}
|
||||
|
||||
int32_t BME280::i2c_write_read_string(uint8_t dev_addr,uint8_t reg_addr , uint8_t * ptr, uint8_t cnt)
|
||||
{
|
||||
mraa::Result ret;
|
||||
mraa::Result ret;
|
||||
|
||||
m_i2c->address(dev_addr);
|
||||
m_i2c->address(dev_addr);
|
||||
|
||||
if( m_i2c->readBytesReg(reg_addr, ptr, cnt) != cnt)
|
||||
{
|
||||
UPM_THROW("bme280 register read failed");
|
||||
if( m_i2c->readBytesReg(reg_addr, ptr, cnt) != cnt)
|
||||
{
|
||||
UPM_THROW("bme280 register read failed");
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* \Brief: The function is used as I2C bus read
|
||||
* \Return : Status of the I2C read
|
||||
* \param dev_addr : The device address of the sensor
|
||||
* \param reg_addr : Address of the first register, will data is going to be read
|
||||
* \param reg_data : This data read from the sensor, which is hold in an array
|
||||
* \param cnt : The no of data byte of to be read
|
||||
/* \Brief: The function is used as I2C bus read
|
||||
* \Return : Status of the I2C read
|
||||
* \param dev_addr : The device address of the sensor
|
||||
* \param reg_addr : Address of the first register, will data is going to be read
|
||||
* \param reg_data : This data read from the sensor, which is hold in an array
|
||||
* \param cnt : The no of data byte of to be read
|
||||
*/
|
||||
int8_t BME280::BME280_I2C_bus_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t cnt)
|
||||
{
|
||||
int32_t iError = BME280_INIT_VALUE;
|
||||
uint8_t array[I2C_BUFFER_LEN] = {BME280_INIT_VALUE};
|
||||
uint8_t stringpos = BME280_INIT_VALUE;
|
||||
array[BME280_INIT_VALUE] = reg_addr;
|
||||
i2c_write_read_string(dev_addr,reg_addr,array,cnt);
|
||||
for (stringpos = BME280_INIT_VALUE; stringpos < cnt; stringpos++) {
|
||||
*(reg_data + stringpos) = array[stringpos];
|
||||
}
|
||||
return (int8_t)iError;
|
||||
int32_t iError = BME280_INIT_VALUE;
|
||||
uint8_t array[I2C_BUFFER_LEN] = {BME280_INIT_VALUE};
|
||||
uint8_t stringpos = BME280_INIT_VALUE;
|
||||
array[BME280_INIT_VALUE] = reg_addr;
|
||||
i2c_write_read_string(dev_addr,reg_addr,array,cnt);
|
||||
for (stringpos = BME280_INIT_VALUE; stringpos < cnt; stringpos++) {
|
||||
*(reg_data + stringpos) = array[stringpos];
|
||||
}
|
||||
return (int8_t)iError;
|
||||
}
|
||||
|
||||
/* Brief : The delay routine
|
||||
* \param : delay in ms
|
||||
/* Brief : The delay routine
|
||||
* \param : delay in ms
|
||||
*/
|
||||
void BME280::BME280_delay_msek(uint16_t mseconds)
|
||||
{
|
||||
struct timespec sleepTime;
|
||||
struct timespec sleepTime;
|
||||
|
||||
sleepTime.tv_sec = mseconds / 1000; // Number of seconds
|
||||
sleepTime.tv_nsec = ( mseconds % 1000 ) * 1000000; // Convert fractional seconds to nanoseconds
|
||||
|
||||
// Iterate nanosleep in a loop until the total sleep time is the original
|
||||
// value of the seconds parameter
|
||||
while ( ( nanosleep( &sleepTime, &sleepTime ) != 0 ) && ( errno == EINTR ) );
|
||||
sleepTime.tv_sec = mseconds / 1000; // Number of seconds
|
||||
sleepTime.tv_nsec = ( mseconds % 1000 ) * 1000000; // Convert fractional seconds to nanoseconds
|
||||
|
||||
// Iterate nanosleep in a loop until the total sleep time is the original
|
||||
// value of the seconds parameter
|
||||
while ( ( nanosleep( &sleepTime, &sleepTime ) != 0 ) && ( errno == EINTR ) );
|
||||
}
|
||||
|
||||
|
||||
|
28
src/e50hx/CMakeLists.txt
Normal file
28
src/e50hx/CMakeLists.txt
Normal file
@ -0,0 +1,28 @@
|
||||
set (libname "e50hx")
|
||||
set (libdescription "upm module for the Veris E50HX (E50H2/E50H5)Energy Meters")
|
||||
set (module_src ${libname}.cxx)
|
||||
set (module_h ${libname}.h)
|
||||
|
||||
pkg_search_module(BACNET libbacnet)
|
||||
if (BACNET_FOUND)
|
||||
# upm-libbacnetmstp will bring in libbacnet, I hope
|
||||
set (reqlibname "upm-bacnetmstp")
|
||||
include_directories(${BACNET_INCLUDE_DIRS})
|
||||
include_directories("../bacnetmstp")
|
||||
upm_module_init()
|
||||
target_link_libraries(${libname} bacnetmstp)
|
||||
if (BUILDSWIG)
|
||||
if (BUILDSWIGNODE)
|
||||
set_target_properties(${SWIG_MODULE_jsupm_${libname}_REAL_NAME} PROPERTIES SKIP_BUILD_RPATH TRUE)
|
||||
swig_link_libraries (jsupm_${libname} bacnetmstp ${MRAA_LIBRARIES} ${NODE_LIBRARIES})
|
||||
endif()
|
||||
if (BUILDSWIGPYTHON)
|
||||
set_target_properties(${SWIG_MODULE_pyupm_${libname}_REAL_NAME} PROPERTIES SKIP_BUILD_RPATH TRUE)
|
||||
swig_link_libraries (pyupm_${libname} bacnetmstp ${PYTHON_LIBRARIES} ${MRAA_LIBRARIES})
|
||||
endif()
|
||||
if (BUILDSWIGJAVA)
|
||||
set_target_properties(${SWIG_MODULE_javaupm_${libname}_REAL_NAME} PROPERTIES SKIP_BUILD_RPATH TRUE)
|
||||
swig_link_libraries (javaupm_${libname} bacnetmstp ${MRAAJAVA_LDFLAGS} ${JAVA_LDFLAGS})
|
||||
endif()
|
||||
endif()
|
||||
endif ()
|
566
src/e50hx/e50hx.cxx
Normal file
566
src/e50hx/e50hx.cxx
Normal file
@ -0,0 +1,566 @@
|
||||
/*
|
||||
* 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 <assert.h>
|
||||
#include <errno.h>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "e50hx.h"
|
||||
|
||||
using namespace upm;
|
||||
using namespace std;
|
||||
|
||||
|
||||
E50HX::E50HX(uint32_t targetDeviceObjectID) :
|
||||
m_instance(0)
|
||||
{
|
||||
// Save our device's ID
|
||||
m_targetDeviceObjectID = targetDeviceObjectID;
|
||||
|
||||
// create the BACNETMSTP instance here if it does not already exist,
|
||||
// and store the pointer in our class to save on some typing.
|
||||
|
||||
m_instance = BACNETMSTP::instance();
|
||||
|
||||
// now see if it has been initialized yet for init()
|
||||
m_initialized = m_instance->isInitialized();
|
||||
|
||||
setDebug(false);
|
||||
|
||||
// we disable this by default for performance reasons
|
||||
checkReliability(false);
|
||||
|
||||
// empty our unit caches
|
||||
m_avUnitCache.clear();
|
||||
m_aiUnitCache.clear();
|
||||
}
|
||||
|
||||
E50HX::~E50HX()
|
||||
{
|
||||
}
|
||||
|
||||
void E50HX::initMaster(std::string port, int baudRate,
|
||||
int deviceInstanceID, int macAddr, int maxMaster,
|
||||
int maxInfoFrames)
|
||||
{
|
||||
// first we check to see if the bacnetmstp instance has already been
|
||||
// initialized (determined in the ctor). If not, we will do so here
|
||||
// with the arguments specified. If it has already been
|
||||
// initialized, then we do not bother calling bacnetmstp's init
|
||||
// again as it will just be ignored.
|
||||
|
||||
if (!m_initialized)
|
||||
m_instance->initMaster(port, baudRate, deviceInstanceID,
|
||||
macAddr, maxMaster, maxInfoFrames);
|
||||
|
||||
// either it threw an exception, was already initialized or it's
|
||||
// initialized now...
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
void E50HX::setDebug(bool enable)
|
||||
{
|
||||
m_debugging = enable;
|
||||
|
||||
// we also enable/disable debugging in BACNETMSTP
|
||||
m_instance->setDebug(enable);
|
||||
}
|
||||
|
||||
float E50HX::getAnalogValue(ANALOG_VALUES_T objInstance)
|
||||
{
|
||||
// check reliability first, if enabled
|
||||
if (m_checkReliability)
|
||||
{
|
||||
if (m_instance->readProperty(m_targetDeviceObjectID, OBJECT_ANALOG_VALUE,
|
||||
objInstance, PROP_RELIABILITY))
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": (reliability): " << getAllErrorString()
|
||||
<< endl;
|
||||
|
||||
return RETURN_ERROR;
|
||||
}
|
||||
|
||||
BACNET_RELIABILITY reliable =
|
||||
static_cast<BACNET_RELIABILITY>(m_instance->getDataTypeEnum());
|
||||
|
||||
if (reliable != RELIABILITY_NO_FAULT_DETECTED)
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": Reliability check failed" << endl;
|
||||
|
||||
return RETURN_UNRELIABLE;
|
||||
}
|
||||
}
|
||||
|
||||
// now get the value
|
||||
if (m_instance->readProperty(m_targetDeviceObjectID, OBJECT_ANALOG_VALUE,
|
||||
objInstance, PROP_PRESENT_VALUE))
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": (value): " << getAllErrorString()
|
||||
<< endl;
|
||||
|
||||
return RETURN_ERROR;
|
||||
}
|
||||
|
||||
return m_instance->getDataTypeReal();
|
||||
}
|
||||
|
||||
string E50HX::getAnalogValueUnits(ANALOG_VALUES_T objInstance)
|
||||
{
|
||||
// see if it exists
|
||||
if (m_avUnitCache.count(objInstance) == 0)
|
||||
{
|
||||
// then we need to fetch it
|
||||
if (m_instance->readProperty(m_targetDeviceObjectID, OBJECT_ANALOG_VALUE,
|
||||
objInstance, PROP_UNITS))
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": " << getAllErrorString() << endl;
|
||||
// set to empty string
|
||||
m_avUnitCache[objInstance] = string("");
|
||||
}
|
||||
else
|
||||
{
|
||||
// cache it for future calls
|
||||
m_avUnitCache[objInstance] =
|
||||
string(bactext_engineering_unit_name(m_instance->getDataTypeEnum()));
|
||||
}
|
||||
}
|
||||
|
||||
return m_avUnitCache[objInstance];
|
||||
}
|
||||
|
||||
float E50HX::getAnalogInput(ANALOG_INPUTS_T objInstance)
|
||||
{
|
||||
// check reliability first, if enabled
|
||||
if (m_checkReliability)
|
||||
{
|
||||
if (m_instance->readProperty(m_targetDeviceObjectID, OBJECT_ANALOG_INPUT,
|
||||
objInstance, PROP_RELIABILITY))
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": (reliability): "
|
||||
<< getAllErrorString() << endl;
|
||||
|
||||
return RETURN_ERROR;
|
||||
}
|
||||
|
||||
BACNET_RELIABILITY reliable =
|
||||
static_cast<BACNET_RELIABILITY>(m_instance->getDataTypeEnum());
|
||||
|
||||
if (reliable != RELIABILITY_NO_FAULT_DETECTED)
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": Reliability check failed" << endl;
|
||||
|
||||
return RETURN_UNRELIABLE;
|
||||
}
|
||||
}
|
||||
|
||||
// now get the value
|
||||
if (m_instance->readProperty(m_targetDeviceObjectID, OBJECT_ANALOG_INPUT,
|
||||
objInstance, PROP_PRESENT_VALUE))
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": (value): " << getAllErrorString() << endl;
|
||||
|
||||
return RETURN_ERROR;
|
||||
}
|
||||
|
||||
return m_instance->getDataTypeReal();
|
||||
}
|
||||
|
||||
string E50HX::getAnalogInputUnits(ANALOG_INPUTS_T objInstance)
|
||||
{
|
||||
// see if it exists
|
||||
if (m_aiUnitCache.count(objInstance) == 0)
|
||||
{
|
||||
// then we need to fetch it
|
||||
if (m_instance->readProperty(m_targetDeviceObjectID, OBJECT_ANALOG_INPUT,
|
||||
objInstance, PROP_UNITS))
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": " << getAllErrorString() << endl;
|
||||
// set to empty string
|
||||
m_aiUnitCache[objInstance] = string("");
|
||||
}
|
||||
else
|
||||
{
|
||||
// cache it for future calls
|
||||
m_aiUnitCache[objInstance] =
|
||||
string(bactext_engineering_unit_name(m_instance->getDataTypeEnum()));
|
||||
}
|
||||
}
|
||||
|
||||
return m_aiUnitCache[objInstance];
|
||||
}
|
||||
|
||||
uint16_t E50HX::getAlarmBits()
|
||||
{
|
||||
return uint16_t(getAnalogInput(AI_Alarm_Bitmap));
|
||||
}
|
||||
|
||||
BACNETMSTP::BACERR_TYPE_T E50HX::getErrorType()
|
||||
{
|
||||
return m_instance->getErrorType();
|
||||
}
|
||||
|
||||
uint8_t E50HX::getRejectReason()
|
||||
{
|
||||
return m_instance->getRejectReason();
|
||||
}
|
||||
|
||||
std::string E50HX::getRejectString()
|
||||
{
|
||||
return m_instance->getRejectString();
|
||||
}
|
||||
|
||||
uint8_t E50HX::getAbortReason()
|
||||
{
|
||||
return m_instance->getAbortReason();
|
||||
}
|
||||
|
||||
std::string E50HX::getAbortString()
|
||||
{
|
||||
return m_instance->getAbortString();
|
||||
}
|
||||
|
||||
BACNET_ERROR_CLASS E50HX::getErrorClass()
|
||||
{
|
||||
return m_instance->getErrorClass();
|
||||
}
|
||||
|
||||
BACNET_ERROR_CODE E50HX::getErrorCode()
|
||||
{
|
||||
return m_instance->getErrorCode();
|
||||
}
|
||||
|
||||
std::string E50HX::getUPMErrorString()
|
||||
{
|
||||
return m_instance->getUPMErrorString();
|
||||
}
|
||||
|
||||
std::string E50HX::getErrorString()
|
||||
{
|
||||
return m_instance->getErrorString();
|
||||
};
|
||||
|
||||
|
||||
string E50HX::getAllErrorString()
|
||||
{
|
||||
switch (m_instance->getErrorType())
|
||||
{
|
||||
case BACNETMSTP::BACERR_TYPE_NONE:
|
||||
return string("No Error");
|
||||
break;
|
||||
|
||||
case BACNETMSTP::BACERR_TYPE_REJECT:
|
||||
return string("Reject: ") + getRejectString();
|
||||
break;
|
||||
|
||||
case BACNETMSTP::BACERR_TYPE_ABORT:
|
||||
return string("Abort: ") + getAbortString();
|
||||
break;
|
||||
|
||||
case BACNETMSTP::BACERR_TYPE_ERROR:
|
||||
return string("Error: ") + getErrorString();
|
||||
break;
|
||||
|
||||
case BACNETMSTP::BACERR_TYPE_UPM:
|
||||
return string("UPM Error: ") + getUPMErrorString();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string E50HX::getDescription()
|
||||
{
|
||||
if (m_instance->readProperty(m_targetDeviceObjectID, OBJECT_DEVICE,
|
||||
m_targetDeviceObjectID, PROP_DESCRIPTION))
|
||||
{
|
||||
// error occurred
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": " << getAllErrorString() << endl;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
return m_instance->getDataTypeString();
|
||||
}
|
||||
|
||||
string E50HX::getLocation()
|
||||
{
|
||||
if (m_instance->readProperty(m_targetDeviceObjectID, OBJECT_DEVICE,
|
||||
m_targetDeviceObjectID, PROP_LOCATION))
|
||||
{
|
||||
// error occurred
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": " << getAllErrorString() << endl;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
return m_instance->getDataTypeString();
|
||||
}
|
||||
|
||||
bool E50HX::setLocation(string location)
|
||||
{
|
||||
BACNET_APPLICATION_DATA_VALUE myLocation =
|
||||
m_instance->createDataString(location);
|
||||
|
||||
// write the Device Object Location
|
||||
if (m_instance->writeProperty(m_targetDeviceObjectID, OBJECT_DEVICE,
|
||||
m_targetDeviceObjectID, PROP_LOCATION,
|
||||
&myLocation))
|
||||
{
|
||||
// error occurred
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": " << getAllErrorString() << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool E50HX::writeConfig(CFG_VALUES_T config)
|
||||
{
|
||||
// Write the value
|
||||
BACNET_APPLICATION_DATA_VALUE myData =
|
||||
m_instance->createDataReal(float(config));
|
||||
|
||||
// write it
|
||||
if (m_instance->writeProperty(m_targetDeviceObjectID, OBJECT_ANALOG_VALUE,
|
||||
AV_Config, PROP_PRESENT_VALUE, &myData))
|
||||
{
|
||||
// error occurred
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": " << getAllErrorString() << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool E50HX::writeSystemType(SYSTEM_TYPES_T systype)
|
||||
{
|
||||
// Write the value
|
||||
BACNET_APPLICATION_DATA_VALUE myData =
|
||||
m_instance->createDataReal(float(systype));
|
||||
|
||||
// write it
|
||||
if (m_instance->writeProperty(m_targetDeviceObjectID, OBJECT_ANALOG_VALUE,
|
||||
AV_System_Type, PROP_PRESENT_VALUE, &myData))
|
||||
{
|
||||
// error occurred
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": " << getAllErrorString() << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool E50HX::writeCTRatioPrimary(float ctRatio)
|
||||
{
|
||||
if (ctRatio < 5 || ctRatio > 32000)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__)
|
||||
+ ": ctRatio must be between 5-32000");
|
||||
}
|
||||
|
||||
// Write the value
|
||||
BACNET_APPLICATION_DATA_VALUE myData =
|
||||
m_instance->createDataReal(ctRatio);
|
||||
|
||||
// write it
|
||||
if (m_instance->writeProperty(m_targetDeviceObjectID, OBJECT_ANALOG_VALUE,
|
||||
AV_CT_Ratio_Primary, PROP_PRESENT_VALUE,
|
||||
&myData))
|
||||
{
|
||||
// error occurred
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": " << getAllErrorString() << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool E50HX::writeCTRatioSecondary(CT_SECONDARY_T ctRatio)
|
||||
{
|
||||
// Write the value
|
||||
BACNET_APPLICATION_DATA_VALUE myData =
|
||||
m_instance->createDataReal(float(ctRatio));
|
||||
|
||||
// write it
|
||||
if (m_instance->writeProperty(m_targetDeviceObjectID, OBJECT_ANALOG_VALUE,
|
||||
AV_CT_Ratio_Secondary, PROP_PRESENT_VALUE,
|
||||
&myData))
|
||||
{
|
||||
// error occurred
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": " << getAllErrorString() << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool E50HX::writePTRatio(float ptRatio)
|
||||
{
|
||||
if (ptRatio < 0.01 || ptRatio > 320.0)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__)
|
||||
+ ": ptRatio must be between 0.01-320.0");
|
||||
}
|
||||
|
||||
// Write the value
|
||||
BACNET_APPLICATION_DATA_VALUE myData =
|
||||
m_instance->createDataReal(ptRatio);
|
||||
|
||||
// write it
|
||||
if (m_instance->writeProperty(m_targetDeviceObjectID, OBJECT_ANALOG_VALUE,
|
||||
AV_PT_Ratio, PROP_PRESENT_VALUE,
|
||||
&myData))
|
||||
{
|
||||
// error occurred
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": " << getAllErrorString() << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool E50HX::writeSystemVoltage(float sysVolts)
|
||||
{
|
||||
if (sysVolts < 82.0 || sysVolts > 32000.0)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__)
|
||||
+ ": sysVolts must be between 82.0-32000.0");
|
||||
}
|
||||
|
||||
// Write the value
|
||||
BACNET_APPLICATION_DATA_VALUE myData =
|
||||
m_instance->createDataReal(sysVolts);
|
||||
|
||||
// write it
|
||||
if (m_instance->writeProperty(m_targetDeviceObjectID, OBJECT_ANALOG_VALUE,
|
||||
AV_System_Voltage, PROP_PRESENT_VALUE,
|
||||
&myData))
|
||||
{
|
||||
// error occurred
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": " << getAllErrorString() << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool E50HX::writeDisplayUnits(DISP_UNITS_T dispUnits)
|
||||
{
|
||||
// Write the value
|
||||
BACNET_APPLICATION_DATA_VALUE myData =
|
||||
m_instance->createDataReal(float(dispUnits));
|
||||
|
||||
// write it
|
||||
if (m_instance->writeProperty(m_targetDeviceObjectID, OBJECT_ANALOG_VALUE,
|
||||
AV_Display_Units, PROP_PRESENT_VALUE,
|
||||
&myData))
|
||||
{
|
||||
// error occurred
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": " << getAllErrorString() << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool E50HX::writePhaseLossVT(float phaseLoss)
|
||||
{
|
||||
if (phaseLoss < 1.0 || phaseLoss > 99.0)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__)
|
||||
+ ": phaseLoss must be between 1.0-99.0");
|
||||
}
|
||||
|
||||
// Write the value
|
||||
BACNET_APPLICATION_DATA_VALUE myData =
|
||||
m_instance->createDataReal(phaseLoss);
|
||||
|
||||
// write it
|
||||
if (m_instance->writeProperty(m_targetDeviceObjectID, OBJECT_ANALOG_VALUE,
|
||||
AV_Phase_Loss_Voltage_Threshold,
|
||||
PROP_PRESENT_VALUE, &myData))
|
||||
{
|
||||
// error occurred
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": " << getAllErrorString() << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool E50HX::writePhaseLossIT(float phaseLoss)
|
||||
{
|
||||
if (phaseLoss < 1.0 || phaseLoss > 99.0)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__)
|
||||
+ ": phaseLoss must be between 1.0-99.0");
|
||||
}
|
||||
|
||||
// Write the value
|
||||
BACNET_APPLICATION_DATA_VALUE myData =
|
||||
m_instance->createDataReal(phaseLoss);
|
||||
|
||||
// write it
|
||||
if (m_instance->writeProperty(m_targetDeviceObjectID, OBJECT_ANALOG_VALUE,
|
||||
AV_Phase_Loss_Imbalance_Threshold,
|
||||
PROP_PRESENT_VALUE, &myData))
|
||||
{
|
||||
// error occurred
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": " << getAllErrorString() << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
588
src/e50hx/e50hx.h
Normal file
588
src/e50hx/e50hx.h
Normal file
@ -0,0 +1,588 @@
|
||||
/*
|
||||
* 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 <map>
|
||||
|
||||
#include "bacnetmstp.h"
|
||||
|
||||
namespace upm {
|
||||
|
||||
/**
|
||||
* @brief E50HX Energy Meter
|
||||
* @defgroup e50hx libupm-e50hx
|
||||
* @ingroup uart electric
|
||||
*/
|
||||
|
||||
/**
|
||||
* @library e50hx
|
||||
* @sensor e50hx
|
||||
* @comname UPM API for the Veris E50HX Energy Meters
|
||||
* @type electic
|
||||
* @man veris
|
||||
* @con uart
|
||||
* @web http://www.veris.com/Item/E50H5.aspx
|
||||
*
|
||||
* @brief UPM API for the Veris E50HX Energy Meter
|
||||
*
|
||||
* This module implements support for the Veris E50H2 and E50H5
|
||||
* BACnet Energy Meters.
|
||||
*
|
||||
* From the datasheet: The E50H5 BACnet MS/TP DIN Rail Meter with
|
||||
* Data Logging combines exceptional performance and easy
|
||||
* installation to deliver a cost-effective solution for power
|
||||
* monitoring applications. Native serial communication via BACnet
|
||||
* MS/TP provides complete accessibility of all measurements to your
|
||||
* Building Automation System The data logging capability protects
|
||||
* data in the event of a power failure. The E50H5 can be easily
|
||||
* installed on standard DIN rail, surface mounted or contained in
|
||||
* an optional NEMA 4 enclosure, as needed. The front-panel LCD
|
||||
* display makes device installation and setup easy and provides
|
||||
* local access to the full set of detailed measurements.
|
||||
*
|
||||
* This module was developed using the upm::BACNETMSTP module, based
|
||||
* on libbacnet-stack 0.8.3. Both libbacnet 0.8.3 and the
|
||||
* upm::BACNETMSTP libraries must be present in order to build this
|
||||
* module. This driver was developed on the E50H5. The Trend Log
|
||||
* functionality is not currently supported.
|
||||
*
|
||||
* The Binary Input Objects are also not supported as these are only
|
||||
* used for the Alarm bits which are already available from Analog
|
||||
* Input Object 52 as an alarm bitfield incorporating all of the
|
||||
* supported alarm indicators.
|
||||
*
|
||||
* It was connected using an RS232->RS485 interface. You cannot use
|
||||
* the built in MCU TTL UART pins for accessing this device -- you
|
||||
* must use a full Serial RS232->RS485 or USB-RS485 interface
|
||||
* connected via USB.
|
||||
*
|
||||
* @snippet e50hx.cxx Interesting
|
||||
*/
|
||||
|
||||
class E50HX {
|
||||
public:
|
||||
|
||||
// Supported Analog Value Objects. These are readable and writable.
|
||||
typedef enum : uint32_t {
|
||||
AV_Config = 1, // always returns 0 on read
|
||||
AV_System_Type = 2,
|
||||
AV_CT_Ratio_Primary = 3,
|
||||
AV_CT_Ratio_Secondary = 4,
|
||||
AV_PT_Ratio = 5,
|
||||
AV_System_Voltage = 6,
|
||||
AV_Display_Units = 7,
|
||||
AV_Phase_Loss_Voltage_Threshold = 8,
|
||||
AV_Phase_Loss_Imbalance_Threshold = 9,
|
||||
AV_Subintervals = 10,
|
||||
AV_Subinterval_Length = 11
|
||||
} ANALOG_VALUES_T;
|
||||
|
||||
// Supported Analog Input Objects. These are read only.
|
||||
typedef enum : uint32_t {
|
||||
AI_Energy = 1,
|
||||
AI_kW_Total = 2,
|
||||
AI_kVAR_Total = 3,
|
||||
AI_kVA_Total = 4,
|
||||
AI_PF_Total = 5,
|
||||
AI_Volts_LL_Avg = 6,
|
||||
AI_Volts_LN_Avg = 7,
|
||||
AI_Current_Avg = 8,
|
||||
AI_kW_A = 9,
|
||||
AI_kW_B = 10,
|
||||
AI_kW_C = 11,
|
||||
AI_PF_A = 12,
|
||||
AI_PF_B = 13,
|
||||
AI_PF_C = 14,
|
||||
AI_Volts_AB = 15,
|
||||
AI_Volts_BC = 16,
|
||||
AI_Volts_AC = 17,
|
||||
AI_Volts_AN = 18,
|
||||
AI_Volts_BN = 19,
|
||||
AI_Volts_CN = 20,
|
||||
AI_Current_A = 21,
|
||||
AI_Current_B = 22,
|
||||
AI_Current_C = 23,
|
||||
// AI24 is reserved
|
||||
AI_Frequency = 25,
|
||||
AI_kVAh = 26, // units = kVAh, not kWH
|
||||
AI_kVARh = 27, // units = kVAh, not kWH
|
||||
AI_kVA_A = 28,
|
||||
AI_kVA_B = 29,
|
||||
AI_kVA_C = 30,
|
||||
AI_kVAR_A = 31,
|
||||
AI_kVAR_B = 32,
|
||||
AI_kVAR_C = 33,
|
||||
AI_KW_Present_Demand = 34,
|
||||
AI_KVAR_Present_Demand = 35,
|
||||
AI_KWA_Present_Demand = 36,
|
||||
AI_KW_Max_Demand = 37,
|
||||
AI_KVAR_Max_Demand = 38,
|
||||
AI_KVA_Max_Demand = 39,
|
||||
AI_Pulse_Count_1 = 40, // H2 & H5
|
||||
// AI41 is reserved on H2 variant
|
||||
AI_Pulse_Count_2 = 41, // only on H5 variant
|
||||
AI_KWH_A = 42,
|
||||
AI_KWH_B = 43,
|
||||
AI_KWH_C = 44,
|
||||
AI_Max_Power = 45, // theoretical max power
|
||||
// AI46 reserved
|
||||
AI_Energy_Resets = 47,
|
||||
// AI48 and AI49 reserved
|
||||
AI_Power_Up_Count = 50,
|
||||
AI_Output_Config = 51, // H2 = 11, H5 = 10
|
||||
AI_Alarm_Bitmap = 52
|
||||
} ANALOG_INPUTS_T;
|
||||
|
||||
// Alarm bits (AI52)
|
||||
typedef enum : uint16_t {
|
||||
ALARM_Volts_Error_A = 0x0001,
|
||||
ALARM_Volts_Error_B = 0x0002,
|
||||
ALARM_Volts_Error_C = 0x0004,
|
||||
|
||||
ALARM_Current_Error_A = 0x0008,
|
||||
ALARM_Current_Error_B = 0x0010,
|
||||
ALARM_Current_Error_C = 0x0020,
|
||||
|
||||
ALARM_Frequency_Error = 0x0040,
|
||||
|
||||
ALARM_Reserved_0 = 0x0080, // reserved
|
||||
|
||||
ALARM_Phase_Loss_A = 0x0100,
|
||||
ALARM_Phase_Loss_B = 0x0200,
|
||||
ALARM_Phase_Loss_C = 0x0400,
|
||||
|
||||
ALARM_Power_Factor_A = 0x0800,
|
||||
ALARM_Power_Factor_B = 0x1000,
|
||||
ALARM_Power_Factor_C = 0x2000,
|
||||
|
||||
ALARM_RTC_RESET = 0x4000 // H5 only
|
||||
} ALARM_BITS_T;
|
||||
|
||||
// valid config values to write to AV1
|
||||
typedef enum {
|
||||
CFG_CLR_ENERGY_ACCUM = 30078, // clear energy accumulators
|
||||
CFG_NEW_DSI = 21211, // begin new demand subinterval
|
||||
CFG_RESET_MAX_TO_PRESENT = 21212, // reset max vals to present vals
|
||||
CFG_CLEAR_PULSE_COUNTERS = 16498 // clear the pulse counters
|
||||
} CFG_VALUES_T;
|
||||
|
||||
// system type configuration
|
||||
typedef enum {
|
||||
SYSTYPE_SINGLE_PHASE_AN = 10,
|
||||
SYSTYPE_SINGLE_PHASE_AB = 11,
|
||||
SYSTYPE_SPLIT_PHASE_ABN = 12,
|
||||
SYSTYPE_3PHASE_ABC = 31,
|
||||
SYSTYPE_3PHASE_ABCN = 40
|
||||
} SYSTEM_TYPES_T;
|
||||
|
||||
// CT input ratio
|
||||
typedef enum {
|
||||
CT_RATIO_SECONDARY_1 = 1, // CT's w/ 1v outputs
|
||||
CT_RATIO_SECONDARY_3 = 3 // CT's w/ 0.3v outputs
|
||||
} CT_SECONDARY_T;
|
||||
|
||||
// LCD display units
|
||||
typedef enum {
|
||||
DISP_UNITS_IEC = 0, // IEC display units
|
||||
DISP_UNITS_IEEE = 1 // IEEE display units
|
||||
} DISP_UNITS_T;
|
||||
|
||||
// Since none of the legal values returned by getAnalogValue() or
|
||||
// getAnalogInput() will ever be negative, we use these two values
|
||||
// to indicate either an error (BACnet or UPM), or to indicate
|
||||
// that the value is unreliable if checkReliability() has been
|
||||
// enabled.
|
||||
const float RETURN_ERROR = -1.0;
|
||||
const float RETURN_UNRELIABLE = -2.0;
|
||||
|
||||
/**
|
||||
* E50HX constructor
|
||||
*
|
||||
* @param targetDeviceObjectID the unique Instance ID of the
|
||||
* Device Object. This number is used to uniquely identify
|
||||
* devices on the BACnet network, and ranges from 1 to 4194302.
|
||||
* This is not the device's MAC address, though on some devices,
|
||||
* the MAC address may be used as part of this number. On the
|
||||
* E50HX, this number is randomly generated per device, and you
|
||||
* can see this number (or change it) on the BACnet config screens
|
||||
* on the LCD.
|
||||
*/
|
||||
E50HX(uint32_t targetDeviceObjectID);
|
||||
|
||||
/**
|
||||
* E50HX Destructor
|
||||
*/
|
||||
~E50HX();
|
||||
|
||||
/**
|
||||
* This function initializes the underlying BACNETMSTP Master
|
||||
* singleton in the event it has not already been initialized. If
|
||||
* the BACNETMSTP Master singleton has already been initialized,
|
||||
* then this call will be ignored.
|
||||
*
|
||||
* @param port The serial port that the RS-485 interface is
|
||||
* connected to.
|
||||
* @param baudRate The baudrate of the RS-485 interface. All
|
||||
* devices on a BACnet RS-485 bus must run at the same baudrate.
|
||||
* Valid values are 9600, 19200, 38400, 57600, 76800, and 115200.
|
||||
* @param deviceInstanceNumber This is the unique Device Object
|
||||
* Instance number that will be used for our BACnet Master in
|
||||
* order to communicate over the BACnet interface. This number
|
||||
* must be between 1-4194302 and must be unique on the BACnet
|
||||
* network.
|
||||
* @param macAddr This is the MAC address of our BACnet Master.
|
||||
* It must be unique on the BACnet segment, and must be between
|
||||
* 1-127.
|
||||
* @param maxMaster This specifies to our Master the maximum MAC
|
||||
* address used by any other Masters on the BACnet network. This
|
||||
* must be between 1-127, the default is 127. Do not change this
|
||||
* unless you know what you are doing or you could introduce
|
||||
* token passing errors on the BACnet network.
|
||||
* @param maxInfoFrames This number specifies the maximum number
|
||||
* of transmissions (like requests for data) our Master is allowed
|
||||
* to make before passing the token to the next Master. The
|
||||
* default is 1.
|
||||
*/
|
||||
void initMaster(std::string port, int baudRate, int deviceInstanceNumber,
|
||||
int macAddr, int maxMaster=DEFAULT_MAX_MASTER,
|
||||
int maxInfoFrames=1);
|
||||
|
||||
/**
|
||||
* Enable some debugging output in this module as well as the
|
||||
* BACNETMSTP module. Debugging is disabled by default.
|
||||
*
|
||||
* @param enable true to enable, false to disable.
|
||||
*/
|
||||
void setDebug(bool enable);
|
||||
|
||||
/**
|
||||
* Retrieve the Present_Value property of an Analog Value object.
|
||||
* If checkReliability() has been enabled, then the Reliability
|
||||
* property of the object will be retrieved first. If the
|
||||
* Reliability property is anything other than
|
||||
* RELIABILITY_NO_FAULT_DETECTED, then the RETURN_UNRELIABLE value
|
||||
* will be returned. Reliability checking is disabled by default
|
||||
* for performance reasons.
|
||||
*
|
||||
* @param objInstance One of the ANALOG_VALUES_T values.
|
||||
* @return the floating point value requested
|
||||
*/
|
||||
float getAnalogValue(ANALOG_VALUES_T objInstance);
|
||||
|
||||
/**
|
||||
* Retrieve the Present_Value property of an Analog Input object.
|
||||
* If checkReliability() has been enabled, then the Reliability
|
||||
* property of the object will be retrieved first. If the
|
||||
* Reliability property is anything other than
|
||||
* RELIABILITY_NO_FAULT_DETECTED, then the RETURN_UNRELIABLE value
|
||||
* will be returned. Reliability checking is disabled by default
|
||||
* for performance reasons.
|
||||
*
|
||||
* @param objInstance One of the ANALOG_INPUTS_T values.
|
||||
* @return the floating point value requested
|
||||
*/
|
||||
float getAnalogInput(ANALOG_INPUTS_T objInstance);
|
||||
|
||||
/**
|
||||
* Write one of several 'magic' numbers to the configuration
|
||||
* object (AV1). This is used to clear certain counters, reset
|
||||
* the accumulated Energy consumption values, etc.
|
||||
*
|
||||
* @param config One of the CFG_VALUES_T values
|
||||
* @return true if the operation suceeded, false if there was an
|
||||
* error.
|
||||
*/
|
||||
bool writeConfig(CFG_VALUES_T config);
|
||||
|
||||
/**
|
||||
* Set the System Type of the device. This defines the voltage
|
||||
* lines you have connected.
|
||||
*
|
||||
* @param systype One of the SYSTEM_TYPES_T values.
|
||||
* @return true if the operation suceeded, false if there was an
|
||||
* error.
|
||||
*/
|
||||
bool writeSystemType(SYSTEM_TYPES_T systype);
|
||||
|
||||
/**
|
||||
* Set the Primary CT ratio. See the datasheet for details.
|
||||
*
|
||||
* @param ctRatio A floating point value between 5-32000
|
||||
* @return true if the operation suceeded, false if there was an
|
||||
* error.
|
||||
*/
|
||||
bool writeCTRatioPrimary(float ctRatio);
|
||||
|
||||
/**
|
||||
* Set the Secondary CT ratio. See the datasheet for details.
|
||||
*
|
||||
* @param ctRatio One of the CT_SECONDARY_T values.
|
||||
* @return true if the operation suceeded, false if there was an
|
||||
* error.
|
||||
*/
|
||||
bool writeCTRatioSecondary(CT_SECONDARY_T ctRatio);
|
||||
|
||||
/**
|
||||
* Set the PT ratio. See the datasheet for details.
|
||||
*
|
||||
* @param ptRatio A floating point value between 0.01-320.0
|
||||
* @return true if the operation suceeded, false if there was an
|
||||
* error.
|
||||
*/
|
||||
bool writePTRatio(float ptRatio);
|
||||
|
||||
/**
|
||||
* Set the System Voltage parmeter. See the datasheet for details.
|
||||
*
|
||||
* @param sysVolts A floating point value between 82.0-32000.0
|
||||
* @return true if the operation suceeded, false if there was an
|
||||
* error.
|
||||
*/
|
||||
bool writeSystemVoltage(float sysVolts);
|
||||
|
||||
/**
|
||||
* Set the LCD Display Units in IEC or IEEE format.
|
||||
*
|
||||
* @param dispUnits One of the DISP_UNITS_T values.
|
||||
* @return true if the operation suceeded, false if there was an
|
||||
* error.
|
||||
*/
|
||||
bool writeDisplayUnits(DISP_UNITS_T dispUnits);
|
||||
|
||||
/**
|
||||
* Set the Phase Loss Voltage Threshold. See the datasheet for
|
||||
* details.
|
||||
*
|
||||
* @param dispUnits A floating point value between 1.0-99.0
|
||||
* @return true if the operation suceeded, false if there was an
|
||||
* error.
|
||||
*/
|
||||
bool writePhaseLossVT(float phaseLoss);
|
||||
|
||||
/**
|
||||
* Set the Phase Loss Imbalance Threshold. See the datasheet for
|
||||
* details.
|
||||
*
|
||||
* @param dispUnits A floating point value between 1.0-99.0
|
||||
* @return true if the operation suceeded, false if there was an
|
||||
* error.
|
||||
*/
|
||||
bool writePhaseLossIT(float phaseLoss);
|
||||
|
||||
/**
|
||||
* Query an Analog Value object for the unit code, translate it
|
||||
* into a string and cache the result for future use. Return the
|
||||
* BACnet text for the Unit enumeration. Unit enumerations are
|
||||
* things like 'kilowatt-hours', 'volts', etc. For Objects which
|
||||
* do not have a Units property defined for them, or for which
|
||||
* Units has no meaning, 'no-units' will typically be returned and
|
||||
* cached.
|
||||
*
|
||||
* @param objInstance One of the ANALOG_VALUES_T values.
|
||||
* @return A string representing the Object's Unit property.
|
||||
*/
|
||||
std::string getAnalogValueUnits(ANALOG_VALUES_T objInstance);
|
||||
|
||||
/**
|
||||
* Query an Analog Input object for the unit code, translate it
|
||||
* into a string and cache the result for future use. Return the
|
||||
* BACnet text for the Unit enumeration. Unit enumerations are
|
||||
* things like 'kilowatt-hours', 'volts', etc. For Objects which
|
||||
* do not have a Units property defined for them, or for which
|
||||
* Units has no meaning, 'no-units' will typically be returned and
|
||||
* cached.
|
||||
*
|
||||
* @param objInstance One of the ANALOG_INPUTS_T values.
|
||||
* @return A string representing the Object's Unit property.
|
||||
*/
|
||||
std::string getAnalogInputUnits(ANALOG_INPUTS_T objInstance);
|
||||
|
||||
/**
|
||||
* Query the AI52 Object and return a bitmask of current Alarms.
|
||||
* Compare against ALARM_BITS_T to determine what conditions are
|
||||
* signaling an alarm. Alarm conditions will clear on their own
|
||||
* as soon as the cause is rectified.
|
||||
*
|
||||
* @return A bitmask of values from ALARM_BITS_T indicating
|
||||
* current alarm conditions.
|
||||
*/
|
||||
uint16_t getAlarmBits();
|
||||
|
||||
/**
|
||||
* Enable or disable reliability checking. By default, when using
|
||||
* getAnalogValue() or getAnalogInput() the Present_Value property
|
||||
* is returned. There is also a property called Reliability that
|
||||
* can be checked to ensure that the Present_Value property is
|
||||
* currently valid.
|
||||
*
|
||||
* Enabling Reliability Checking has these functions check for a
|
||||
* RELIABILITY_NO_FAULT_DETECTED value for the Reliability
|
||||
* property before querying the Present_Value property. If
|
||||
* anything other than RELIABILITY_NO_FAULT_DETECTED is set, then
|
||||
* these functions will return RETURN_UNRELIABLE rather than the
|
||||
* Present_Value.
|
||||
*
|
||||
* This checking is disabled by default since it will double the
|
||||
* number of queries needed to retrieve a given value. However,
|
||||
* if you need to ensure that the values returned are always
|
||||
* completely valid as determined by the device firmware, you
|
||||
* should enable this.
|
||||
*
|
||||
* @param enable true to check Reliability before returning a
|
||||
* value, false otherwise.
|
||||
*/
|
||||
void checkReliability(bool enable)
|
||||
{
|
||||
m_checkReliability = enable;
|
||||
};
|
||||
|
||||
/**
|
||||
* Query the Device Object of the device and return it's
|
||||
* Description property. This typically contains information like
|
||||
* the Vendor, model and serial number of a device.
|
||||
*
|
||||
* @return A string containing the Device Object's Description property.
|
||||
*/
|
||||
std::string getDescription();
|
||||
|
||||
/**
|
||||
* Query the Device Object of the device and return it's Location
|
||||
* property. This typically contains a string indication a
|
||||
* customer specific value. Use setLocation() to change.
|
||||
*
|
||||
* @return A string containing the Device Object's Location property.
|
||||
*/
|
||||
std::string getLocation();
|
||||
|
||||
/**
|
||||
* Set the Device Object's Location property. This must be a
|
||||
* string containing no more than 63 characters.
|
||||
*
|
||||
* @return true if the operation succeeded, false otherwise
|
||||
*/
|
||||
bool setLocation(std::string location);
|
||||
|
||||
/**
|
||||
* This is a utility function that will return a string reporting
|
||||
* on the various types of errors that can occur in BACnet
|
||||
* operation.
|
||||
*
|
||||
* @return A string containing the last error message.
|
||||
*/
|
||||
std::string getAllErrorString();
|
||||
|
||||
/**
|
||||
* Return an enumration of the last error type to occur. The
|
||||
* value returned will be one of the BACNETMSTP::BACERR_TYPE_T
|
||||
* values.
|
||||
*
|
||||
* @return The last error type to occur, one of the
|
||||
* BACNETMSTP::BACERR_TYPE_T values.
|
||||
*/
|
||||
BACNETMSTP::BACERR_TYPE_T getErrorType();
|
||||
|
||||
/**
|
||||
* In the event of a BACnet Reject error, return the error code.
|
||||
*
|
||||
* @return The Reject error code.
|
||||
*/
|
||||
uint8_t getRejectReason();
|
||||
|
||||
/**
|
||||
* In the event of a BACnet Reject error, return the error string.
|
||||
*
|
||||
* @return The Reject error string.
|
||||
*/
|
||||
std::string getRejectString();
|
||||
|
||||
/**
|
||||
* In the event of a BACnet Abort error, return the Abort reason code.
|
||||
*
|
||||
* @return The Abort reason code.
|
||||
*/
|
||||
uint8_t getAbortReason();
|
||||
|
||||
/**
|
||||
* In the event of a BACnet Abort error, return the Abort string.
|
||||
*
|
||||
* @return The Abort error string.
|
||||
*/
|
||||
std::string getAbortString();
|
||||
|
||||
/**
|
||||
* In the event of a general BACnet error, return the BACnet error class.
|
||||
*
|
||||
* @return One of the BACNET_ERROR_CLASS error class codes
|
||||
*/
|
||||
BACNET_ERROR_CLASS getErrorClass();
|
||||
|
||||
/**
|
||||
* In the event of a general BACnet error, return the BACnet error code.
|
||||
*
|
||||
* @return One of the BACNET_ERROR_CODE error codes
|
||||
*/
|
||||
BACNET_ERROR_CODE getErrorCode();
|
||||
|
||||
/**
|
||||
* In the event of a general BACnet error, return the BACnet error
|
||||
* string.
|
||||
*
|
||||
* @return A string representing the BACnet error class and code.
|
||||
*/
|
||||
std::string getErrorString();
|
||||
|
||||
/**
|
||||
* In the event of a non-BACnet UPM error, return a string
|
||||
* describing the error.
|
||||
*
|
||||
* @return A string representing the UPM error.
|
||||
*/
|
||||
std::string getUPMErrorString();
|
||||
|
||||
protected:
|
||||
// a copy of the BACNETMSTP singleton instance pointer
|
||||
BACNETMSTP* m_instance;
|
||||
|
||||
// unique device object ID of e50hx
|
||||
uint32_t m_targetDeviceObjectID;
|
||||
|
||||
// are we initialized?
|
||||
bool m_initialized;
|
||||
|
||||
private:
|
||||
bool m_debugging;
|
||||
|
||||
// whether or not to verify reliability before reading a value.
|
||||
bool m_checkReliability;
|
||||
|
||||
// Unit cache for AV
|
||||
typedef std::map<ANALOG_VALUES_T, std::string> avCacheMap_t;
|
||||
avCacheMap_t m_avUnitCache;
|
||||
|
||||
// Unit cache for AI
|
||||
typedef std::map<ANALOG_INPUTS_T, std::string> aiCacheMap_t;
|
||||
aiCacheMap_t m_aiUnitCache;
|
||||
};
|
||||
}
|
21
src/e50hx/javaupm_e50hx.i
Normal file
21
src/e50hx/javaupm_e50hx.i
Normal file
@ -0,0 +1,21 @@
|
||||
%module javaupm_e50hx
|
||||
%include "../upm.i"
|
||||
%include "typemaps.i"
|
||||
|
||||
%include "bacnetmstp.h"
|
||||
%include "e50hx.h"
|
||||
%{
|
||||
#include "e50hx.h"
|
||||
%}
|
||||
|
||||
|
||||
%pragma(java) jniclasscode=%{
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("javaupm_e50hx");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
System.err.println("Native code library failed to load. \n" + e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
%}
|
9
src/e50hx/jsupm_e50hx.i
Normal file
9
src/e50hx/jsupm_e50hx.i
Normal file
@ -0,0 +1,9 @@
|
||||
%module jsupm_e50hx
|
||||
%include "../upm.i"
|
||||
%include "stdint.i"
|
||||
|
||||
%include "bacnetmstp.h"
|
||||
%include "e50hx.h"
|
||||
%{
|
||||
#include "e50hx.h"
|
||||
%}
|
13
src/e50hx/pyupm_e50hx.i
Normal file
13
src/e50hx/pyupm_e50hx.i
Normal file
@ -0,0 +1,13 @@
|
||||
// Include doxygen-generated documentation
|
||||
%include "pyupm_doxy2swig.i"
|
||||
%module pyupm_e50hx
|
||||
%include "../upm.i"
|
||||
%include "stdint.i"
|
||||
|
||||
%feature("autodoc", "3");
|
||||
|
||||
%include "bacnetmstp.h"
|
||||
%include "e50hx.h"
|
||||
%{
|
||||
#include "e50hx.h"
|
||||
%}
|
@ -522,7 +522,7 @@ namespace upm {
|
||||
/**
|
||||
* Sets up the interrupt 1 threshold register
|
||||
*
|
||||
* @param val Threshhold to set
|
||||
* @param val Threshold to set
|
||||
* @return True if successful
|
||||
*/
|
||||
bool setInterrupt1Threshold(uint8_t val);
|
||||
@ -530,7 +530,7 @@ namespace upm {
|
||||
/**
|
||||
* Sets up the interrupt 2 threshold register
|
||||
*
|
||||
* @param val Threshhold to set
|
||||
* @param val Threshold to set
|
||||
* @return True if successful
|
||||
*/
|
||||
bool setInterrupt2Threshold(uint8_t val);
|
||||
|
@ -8,7 +8,6 @@ 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)
|
||||
|
@ -8,7 +8,6 @@ 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)
|
||||
|
@ -1,5 +1,5 @@
|
||||
set (libname "ili9341")
|
||||
set (libdescription "libupm ILI9341 SPI LCD")
|
||||
set (module_src gfx.cxx ili9341.cxx)
|
||||
set (module_h gfx.h ili9341.h)
|
||||
set (module_src ili9341_gfx.cxx ili9341.cxx)
|
||||
set (module_h ili9341_gfx.h ili9341.h)
|
||||
upm_module_init()
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include <mraa/common.hpp>
|
||||
#include <mraa/gpio.hpp>
|
||||
#include <mraa/spi.hpp>
|
||||
#include "gfx.h"
|
||||
#include "ili9341_gfx.h"
|
||||
|
||||
// Defines
|
||||
#define ILI9341_TFTWIDTH 240
|
||||
|
@ -24,7 +24,7 @@
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "gfx.h"
|
||||
#include "ili9341_gfx.h"
|
||||
|
||||
using namespace upm;
|
||||
|
@ -5,9 +5,9 @@
|
||||
|
||||
%apply uint8_t *INPUT { uint8_t *addr }
|
||||
|
||||
%include "gfx.h"
|
||||
%include "ili9341_gfx.h"
|
||||
%{
|
||||
#include "gfx.h"
|
||||
#include "ili9341_gfx.h"
|
||||
%}
|
||||
|
||||
%{
|
||||
|
@ -1,9 +1,9 @@
|
||||
%module jsupm_ili9341
|
||||
%include "../upm.i"
|
||||
|
||||
%include "gfx.h"
|
||||
%include "ili9341_gfx.h"
|
||||
%{
|
||||
#include "gfx.h"
|
||||
#include "ili9341_gfx.h"
|
||||
%}
|
||||
|
||||
%include "ili9341.h"
|
||||
|
@ -6,9 +6,9 @@
|
||||
%feature("autodoc", "3");
|
||||
%rename("printString") print(std::string msg);
|
||||
|
||||
%include "gfx.h"
|
||||
%include "ili9341_gfx.h"
|
||||
%{
|
||||
#include "gfx.h"
|
||||
#include "ili9341_gfx.h"
|
||||
%}
|
||||
|
||||
%include "ili9341.h"
|
||||
|
@ -851,7 +851,7 @@ namespace upm {
|
||||
|
||||
/**
|
||||
* enable I2C Bypass. Enabling this feature allows devices on the
|
||||
* MPU60X0 auxillary I2C bus to be visible on the MCU's I2C bus.
|
||||
* MPU60X0 auxiliary I2C bus to be visible on the MCU's I2C bus.
|
||||
*
|
||||
* @param enable true to I2C bypass
|
||||
* @return true if successful, false otherwise
|
||||
|
@ -177,8 +177,8 @@ namespace upm {
|
||||
|
||||
/**
|
||||
* Set the driection mode (input or output) for all gpios enabled
|
||||
* by gpioSetIOMask(). A 0 in a given bit postion (LSB = gpio0)
|
||||
* configures the gpio as an ouput, and a 1 bit configures the
|
||||
* by gpioSetIOMask(). A 0 in a given bit position (LSB = gpio0)
|
||||
* configures the gpio as an output, and a 1 bit configures the
|
||||
* gpio as an input. Only the gpios enabled by gpioSetMask() are
|
||||
* affected by this call.
|
||||
*
|
||||
@ -211,7 +211,7 @@ namespace upm {
|
||||
|
||||
/**
|
||||
* Read the raw analog input value present at the given gpio and
|
||||
* return the coresponding voltage value at the pin. The gpio is
|
||||
* return the corresponding voltage value at the pin. The gpio is
|
||||
* switched to analog input mode by this call, regardless of any
|
||||
* previous mode. The returned value will be a number between
|
||||
* 0.0-3.3, depending on the voltage present at the pin. Only the
|
||||
|
@ -1,5 +1,6 @@
|
||||
%module jsupm_nrf24l01
|
||||
%include "../upm.i"
|
||||
%include "../carrays_uint8_t.i"
|
||||
|
||||
%{
|
||||
#include "nrf24l01.h"
|
||||
|
@ -2,6 +2,7 @@
|
||||
%include "pyupm_doxy2swig.i"
|
||||
%module pyupm_nrf24l01
|
||||
%include "../upm.i"
|
||||
%include "../carrays_uint8_t.i"
|
||||
|
||||
%feature("autodoc", "3");
|
||||
|
||||
|
@ -371,17 +371,17 @@ void hal_aci_tl_init(aci_pins_t *a_pins, bool debug)
|
||||
|
||||
error = mraa_gpio_dir (a_pins->m_rdy_ctx, MRAA_GPIO_IN);
|
||||
if (error != MRAA_SUCCESS) {
|
||||
printf ("[ERROR] GPIO failed to initilize \n");
|
||||
printf ("[ERROR] GPIO failed to initialize \n");
|
||||
}
|
||||
|
||||
error = mraa_gpio_dir (a_pins->m_req_ctx, MRAA_GPIO_OUT);
|
||||
if (error != MRAA_SUCCESS) {
|
||||
printf ("[ERROR] GPIO failed to initilize \n");
|
||||
printf ("[ERROR] GPIO failed to initialize \n");
|
||||
}
|
||||
|
||||
error = mraa_gpio_dir (a_pins->m_rst_ctx, MRAA_GPIO_OUT);
|
||||
if (error != MRAA_SUCCESS) {
|
||||
printf ("[ERROR] GPIO failed to initilize \n");
|
||||
printf ("[ERROR] GPIO failed to initialize \n");
|
||||
}
|
||||
|
||||
if (UNUSED != a_pins->active_pin) {
|
||||
|
@ -8,7 +8,6 @@ if (OPENZWAVE_FOUND)
|
||||
set (reqlibname "libopenzwave")
|
||||
include_directories(${OPENZWAVE_INCLUDE_DIRS})
|
||||
upm_module_init()
|
||||
add_dependencies(${libname} ${OPENZWAVE_LIBRARIES})
|
||||
target_link_libraries(${libname} ${OPENZWAVE_LIBRARIES})
|
||||
if (BUILDSWIG)
|
||||
if (BUILDSWIGNODE)
|
||||
|
@ -398,7 +398,7 @@ namespace upm {
|
||||
* library. Most modern devices are never polled, rather they are
|
||||
* configured to report changing values to the controller on their
|
||||
* own at device specific intervals or when appropriate events
|
||||
* (depending the device) have occured.
|
||||
* (depending the device) have occurred.
|
||||
*
|
||||
* @param nodeId The node ID
|
||||
* @param index The value index (see dumpNodes()) of the value to query.
|
||||
|
@ -192,8 +192,8 @@ uint32_t PN532::getFirmwareVersion()
|
||||
@param cmdlen The size of the command in bytes
|
||||
@param timeout timeout before giving up
|
||||
|
||||
@returns 1 if everything is OK, 0 if timeout occured before an
|
||||
ACK was recieved
|
||||
@returns 1 if everything is OK, 0 if timeout occurred before an
|
||||
ACK was received
|
||||
*/
|
||||
/**************************************************************************/
|
||||
// default timeout of one second
|
||||
|
@ -232,8 +232,8 @@ namespace upm {
|
||||
* @param cmdlen the size of the command in bytes
|
||||
* @param timeout timeout before giving up (in ms)
|
||||
*
|
||||
* @return true if everything is OK, false if timeout occured
|
||||
* before an ACK was recieved
|
||||
* @return true if everything is OK, false if timeout occurred
|
||||
* before an ACK was received
|
||||
*/
|
||||
bool sendCommandCheckAck(uint8_t *cmd, uint8_t cmdlen,
|
||||
uint16_t timeout=1000);
|
||||
|
@ -189,7 +189,7 @@ mraa::Result SI1132::runCommand(uint8_t command)
|
||||
}
|
||||
if (response == 0) {
|
||||
status = mraa::ERROR_UNSPECIFIED;
|
||||
fprintf(stderr, "Comand %d failed\n", command);
|
||||
fprintf(stderr, "Command %d failed\n", command);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
@ -397,7 +397,7 @@ SmartDrive::GetMotorStatus(int motor_id) {
|
||||
if (motor_id == SmartDrive_Motor_ID_2)
|
||||
status = readByte(SmartDrive_STATUS_M1);
|
||||
if (motor_id == SmartDrive_Motor_ID_BOTH) {
|
||||
std::cout << "Please specifiy which motor's status you want to fetch !" << std::endl;
|
||||
std::cout << "Please specify which motor's status you want to fetch !" << std::endl;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@ -425,6 +425,6 @@ SmartDrive::PrintMotorStatus(int motor_id) {
|
||||
std::cout << "Motor " << motor_id+1 << " is " << ((is_stalled == 0) ? "NOT" : "") << " stalled" << std::endl;
|
||||
|
||||
} else {
|
||||
std::cout << "Please specifiy which motor's status you want to fetch !" << std::endl;
|
||||
std::cout << "Please specify which motor's status you want to fetch !" << std::endl;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
set (libname "ssd1351")
|
||||
set (libdescription "libupm SSD1351 SPI LCD")
|
||||
set (module_src gfx.cxx ssd1351.cxx)
|
||||
set (module_h gfx.h ssd1351.h)
|
||||
set (module_src ssd1351_gfx.cxx ssd1351.cxx)
|
||||
set (module_h ssd1351_gfx.h ssd1351.h)
|
||||
upm_module_init()
|
||||
|
@ -6,9 +6,9 @@
|
||||
%ignore m_map;
|
||||
%ignore font;
|
||||
|
||||
%include "gfx.h"
|
||||
%include "ssd1351_gfx.h"
|
||||
%{
|
||||
#include "gfx.h"
|
||||
#include "ssd1351_gfx.h"
|
||||
%}
|
||||
|
||||
%include "ssd1351.h"
|
||||
|
@ -1,9 +1,9 @@
|
||||
%module jsupm_ssd1351
|
||||
%include "../upm.i"
|
||||
|
||||
%include "gfx.h"
|
||||
%include "ssd1351_gfx.h"
|
||||
%{
|
||||
#include "gfx.h"
|
||||
#include "ssd1351_gfx.h"
|
||||
%}
|
||||
|
||||
%include "ssd1351.h"
|
||||
|
@ -6,9 +6,9 @@
|
||||
%feature("autodoc", "3");
|
||||
%rename("printString") print(std::string msg);
|
||||
|
||||
%include "gfx.h"
|
||||
%include "ssd1351_gfx.h"
|
||||
%{
|
||||
#include "gfx.h"
|
||||
#include "ssd1351_gfx.h"
|
||||
%}
|
||||
|
||||
%include "ssd1351.h"
|
||||
|
@ -44,7 +44,7 @@ SSD1351::SSD1351 (uint8_t oc, uint8_t dc, uint8_t rst) :
|
||||
|
||||
// Setup SPI bus
|
||||
m_spi.frequency(8 * 1000000);
|
||||
m_spi.mode(mraa::SPI_MODE3);
|
||||
m_spi.mode(mraa::SPI_MODE0);
|
||||
m_spi.writeByte(0x00); // Need to bring clk high before init
|
||||
|
||||
// Init pins
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include <mraa/common.hpp>
|
||||
#include <mraa/gpio.hpp>
|
||||
#include <mraa/spi.hpp>
|
||||
#include "gfx.h"
|
||||
#include "ssd1351_gfx.h"
|
||||
|
||||
// Display Size
|
||||
#define SSD1351WIDTH 128
|
||||
@ -92,7 +92,13 @@ namespace upm {
|
||||
*
|
||||
* @brief API for SSD1351 OLED displays
|
||||
*
|
||||
* This module defines the interface for the SSD1351 display library
|
||||
* This module defines the interface for the SSD1351 display library. It was
|
||||
* tested with the Adafruit 1.5" OLED Display, but should work with any SSD1351
|
||||
* display running in SPI mode.
|
||||
*
|
||||
* On the Intel Edison don't forget to disable SPI Power Management (PM) for
|
||||
* this driver to work, you can find more details on this topic here:
|
||||
* http://iotdk.intel.com/docs/master/mraa/edison.html
|
||||
*
|
||||
* @image html ssd1351.jpg
|
||||
* @snippet ssd1351.cxx Interesting
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gfx.h"
|
||||
#include "ssd1351_gfx.h"
|
||||
|
||||
using namespace upm;
|
||||
|
@ -1,5 +1,5 @@
|
||||
set (libname "st7735")
|
||||
set (libdescription "libupm SPI LCD")
|
||||
set (module_src gfx.cxx st7735.cxx)
|
||||
set (module_h gfx.h st7735.h)
|
||||
set (module_src st7735_gfx.cxx st7735.cxx)
|
||||
set (module_h st7735_gfx.h st7735.h)
|
||||
upm_module_init()
|
||||
|
@ -35,9 +35,9 @@
|
||||
$1 = (unsigned char *)JCALL2(GetByteArrayElements, jenv, $input, NULL);
|
||||
}
|
||||
|
||||
%include "gfx.h"
|
||||
%include "st7735_gfx.h"
|
||||
%{
|
||||
#include "gfx.h"
|
||||
#include "st7735_gfx.h"
|
||||
%}
|
||||
|
||||
%include "st7735.h"
|
||||
|
@ -1,9 +1,9 @@
|
||||
%module jsupm_st7735
|
||||
%include "../upm.i"
|
||||
|
||||
%include "gfx.h"
|
||||
%include "st7735_gfx.h"
|
||||
%{
|
||||
#include "gfx.h"
|
||||
#include "st7735_gfx.h"
|
||||
%}
|
||||
|
||||
%include "st7735.h"
|
||||
|
@ -6,9 +6,9 @@
|
||||
%feature("autodoc", "3");
|
||||
%rename("printString") print(std::string msg);
|
||||
|
||||
%include "gfx.h"
|
||||
%include "st7735_gfx.h"
|
||||
%{
|
||||
#include "gfx.h"
|
||||
#include "st7735_gfx.h"
|
||||
%}
|
||||
|
||||
%include "st7735.h"
|
||||
|
@ -33,7 +33,7 @@
|
||||
#include <mraa/gpio.hpp>
|
||||
|
||||
#include <mraa/spi.hpp>
|
||||
#include "gfx.h"
|
||||
#include "st7735_gfx.h"
|
||||
|
||||
#define INITR_GREENTAB 0x0
|
||||
#define INITR_REDTAB 0x1
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gfx.h"
|
||||
#include "st7735_gfx.h"
|
||||
|
||||
using namespace upm;
|
||||
|
@ -1740,7 +1740,7 @@ namespace upm {
|
||||
* FSK : N/A ( set to 0 )
|
||||
* LoRa: timeout in symbols
|
||||
* @param fixLen Fixed length packets [false: variable, true: fixed]
|
||||
* @param payloadLen Sets payload length when fixed lenght is used
|
||||
* @param payloadLen Sets payload length when fixed length is used
|
||||
* @param crcOn Enables/Disables the CRC [false: OFF, true: ON]
|
||||
* @param FreqHopOn Enables disables the intra-packet frequency hopping
|
||||
* FSK : N/A ( set to 0 )
|
||||
|
@ -8,7 +8,6 @@ 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)
|
||||
|
@ -221,6 +221,12 @@
|
||||
* @ingroup bycat
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Provide video or video camera access
|
||||
* @defgroup video Video
|
||||
* @ingroup bycat
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Provide WiFi, Bluetooth, RF communication
|
||||
* @defgroup wifi Wireless Communication
|
||||
|
18
src/vcap/CMakeLists.txt
Normal file
18
src/vcap/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
||||
set (libname "vcap")
|
||||
set (libdescription "upm Video Frame Capture and image save utility")
|
||||
set (module_src ${libname}.cxx)
|
||||
set (module_h ${libname}.hpp)
|
||||
set (reqlibname "jpeg")
|
||||
upm_module_init()
|
||||
target_link_libraries(${libname} jpeg)
|
||||
if (BUILDSWIG)
|
||||
if (BUILDSWIGNODE)
|
||||
swig_link_libraries (jsupm_${libname} jpeg ${MRAA_LIBRARIES} ${NODE_LIBRARIES})
|
||||
endif()
|
||||
if (BUILDSWIGPYTHON)
|
||||
swig_link_libraries (pyupm_${libname} jpeg ${PYTHON_LIBRARIES} ${MRAA_LIBRARIES})
|
||||
endif()
|
||||
if (BUILDSWIGJAVA)
|
||||
swig_link_libraries (javaupm_${libname} jpeg ${MRAAJAVA_LDFLAGS} ${JAVA_LDFLAGS})
|
||||
endif()
|
||||
endif()
|
19
src/vcap/javaupm_vcap.i
Normal file
19
src/vcap/javaupm_vcap.i
Normal file
@ -0,0 +1,19 @@
|
||||
%module javaupm_vcap
|
||||
%include "../upm.i"
|
||||
%include "std_string.i"
|
||||
|
||||
%include "vcap.hpp"
|
||||
%{
|
||||
#include "vcap.hpp"
|
||||
%}
|
||||
|
||||
%pragma(java) jniclasscode=%{
|
||||
static {
|
||||
try {
|
||||
System.loadLibrary("javaupm_vcap");
|
||||
} catch (UnsatisfiedLinkError e) {
|
||||
System.err.println("Native code library failed to load. \n" + e);
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
%}
|
10
src/vcap/jsupm_vcap.i
Normal file
10
src/vcap/jsupm_vcap.i
Normal file
@ -0,0 +1,10 @@
|
||||
%module jsupm_vcap
|
||||
%include "../upm.i"
|
||||
%include "std_string.i"
|
||||
|
||||
%include "vcap.hpp"
|
||||
%{
|
||||
#include "vcap.hpp"
|
||||
%}
|
||||
|
||||
|
14
src/vcap/pyupm_vcap.i
Normal file
14
src/vcap/pyupm_vcap.i
Normal file
@ -0,0 +1,14 @@
|
||||
// Include doxygen-generated documentation
|
||||
%include "pyupm_doxy2swig.i"
|
||||
%module pyupm_vcap
|
||||
%include "../upm.i"
|
||||
%include "std_string.i"
|
||||
|
||||
%feature("autodoc", "3");
|
||||
|
||||
%include "vcap.hpp"
|
||||
%{
|
||||
#include "vcap.hpp"
|
||||
%}
|
||||
|
||||
|
524
src/vcap/vcap.cxx
Normal file
524
src/vcap/vcap.cxx
Normal file
@ -0,0 +1,524 @@
|
||||
/*
|
||||
* 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 <iostream>
|
||||
#include <stdexcept>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "vcap.hpp"
|
||||
|
||||
using namespace upm;
|
||||
using namespace std;
|
||||
|
||||
#define CLAMP(_val, _min, _max) \
|
||||
(((_val) < (_min)) ? (_min) : (((_val) > (_max)) ? (_max) : (_val)))
|
||||
|
||||
VCAP::VCAP(string videoDev) :
|
||||
m_buffer(0), m_fd(-1)
|
||||
{
|
||||
memset(&m_caps, 0, sizeof(struct v4l2_capability));
|
||||
memset(&m_format, 0, sizeof(struct v4l2_format));
|
||||
|
||||
m_debugging = false;
|
||||
m_bufferLen = 0;
|
||||
m_videoDevice = videoDev;
|
||||
setJPGQuality(VCAP_DEFAULT_JPEG_QUALITY);
|
||||
|
||||
// try to open the video device, and set a default format.
|
||||
if (!initVideoDevice())
|
||||
throw std::runtime_error(std::string(__FUNCTION__) +
|
||||
": initVideoDevice() failed");
|
||||
|
||||
m_height = 0;
|
||||
m_width = 0;
|
||||
m_imageCaptured = false;
|
||||
}
|
||||
|
||||
VCAP::~VCAP()
|
||||
{
|
||||
releaseBuffer();
|
||||
|
||||
if (m_fd >= 0)
|
||||
close(m_fd);
|
||||
|
||||
m_fd = -1;
|
||||
}
|
||||
|
||||
bool VCAP::initVideoDevice()
|
||||
{
|
||||
if (m_videoDevice.empty())
|
||||
return false;
|
||||
|
||||
if ((m_fd = open(m_videoDevice.c_str(), O_RDWR)) < 0)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": open failed: " << strerror(errno) << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!checkCapabilities())
|
||||
{
|
||||
close(m_fd);
|
||||
m_fd = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// This seems... odd, but appears to be necessary.
|
||||
// Ignore error and retry if the ioctl fails due to EINTR
|
||||
int VCAP::xioctl(int fd, int request, void* argp)
|
||||
{
|
||||
int r;
|
||||
|
||||
do {
|
||||
r = ioctl(fd, request, argp);
|
||||
}
|
||||
while (r == -1 && errno == EINTR);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool VCAP::checkCapabilities()
|
||||
{
|
||||
if (xioctl(m_fd, VIDIOC_QUERYCAP, &m_caps) < 0)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": ioctl(VIDIOC_QUERYCAP) failed: "
|
||||
<< strerror(errno) << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_debugging)
|
||||
{
|
||||
cerr << "Driver: " << m_caps.driver << endl;
|
||||
cerr << "Device: " << m_caps.card << endl;
|
||||
cerr << "Caps : 0x" << std::hex << m_caps.capabilities << std::dec
|
||||
<< endl;
|
||||
}
|
||||
|
||||
// see if capturing is supported
|
||||
if (!(m_caps.capabilities & V4L2_CAP_VIDEO_CAPTURE))
|
||||
{
|
||||
cerr << __FUNCTION__ << ": Device does not support video capture"
|
||||
<< endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(m_caps.capabilities & V4L2_CAP_STREAMING))
|
||||
{
|
||||
cerr << __FUNCTION__ << ": Device does not support streaming I/O"
|
||||
<< endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VCAP::setResolution(int width, int height)
|
||||
{
|
||||
// in case we already created one
|
||||
releaseBuffer();
|
||||
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
|
||||
m_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
// initialize with the current format
|
||||
if (xioctl(m_fd, VIDIOC_G_FMT, &m_format) < 0)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": ioctl(VIDIOC_G_FMT) failed: "
|
||||
<< strerror(errno) << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// make our changes...
|
||||
m_format.fmt.pix.width = m_width;
|
||||
m_format.fmt.pix.height = m_height;
|
||||
m_format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
|
||||
m_format.fmt.pix.field = V4L2_FIELD_ANY;
|
||||
|
||||
if (xioctl(m_fd, VIDIOC_S_FMT, &m_format) < 0)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": ioctl(VIDIOC_S_FMT) failed: "
|
||||
<< strerror(errno) << endl;
|
||||
|
||||
// If it's just busy, then this still might work, so don't fail here
|
||||
if (errno != EBUSY)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now retrieve the driver's selected format and check it -
|
||||
// specifically, the width and height might change, causing
|
||||
// coredumps if we don't adjust them accordingly.
|
||||
|
||||
if (xioctl(m_fd, VIDIOC_G_FMT, &m_format) < 0)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": ioctl(VIDIOC_G_FMT) failed: "
|
||||
<< strerror(errno) << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// G_FMT will have adjusted these if neccessary, so verify
|
||||
if (m_format.fmt.pix.width != m_width)
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": Warning: Selected width "
|
||||
<< std::to_string(m_width)
|
||||
<< " adjusted by driver to "
|
||||
<< std::to_string(m_format.fmt.pix.width)
|
||||
<< endl;
|
||||
|
||||
m_width = m_format.fmt.pix.width;
|
||||
}
|
||||
|
||||
if (m_format.fmt.pix.height != m_height)
|
||||
{
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": Warning: Selected height "
|
||||
<< std::to_string(m_height)
|
||||
<< " adjusted by driver to "
|
||||
<< std::to_string(m_format.fmt.pix.height)
|
||||
<< endl;
|
||||
|
||||
m_height = m_format.fmt.pix.height;
|
||||
}
|
||||
|
||||
// now alloc the buffers here
|
||||
if (!allocBuffer())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VCAP::allocBuffer()
|
||||
{
|
||||
struct v4l2_requestbuffers rb;
|
||||
memset(&rb, 0, sizeof(rb));
|
||||
|
||||
// we just want one buffer, and we only support mmap().
|
||||
rb.count = 1;
|
||||
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
rb.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
if (xioctl(m_fd, VIDIOC_REQBUFS, &rb) < 0)
|
||||
{
|
||||
if (errno == EINVAL)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": Capture device does not support mmapped "
|
||||
<< "buffers"
|
||||
<< endl;
|
||||
}
|
||||
cerr << __FUNCTION__ << ": ioctl(VIDIOC_REQBUFS) failed: "
|
||||
<< strerror(errno) << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// get the buffer and mmap it
|
||||
struct v4l2_buffer mbuf;
|
||||
memset(&mbuf, 0, sizeof(mbuf));
|
||||
|
||||
mbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
mbuf.memory = V4L2_MEMORY_MMAP;
|
||||
mbuf.index = 0;
|
||||
|
||||
if (xioctl(m_fd, VIDIOC_QUERYBUF, &mbuf) < 0)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": ioctl(VIDIOC_QUERYBUF) failed: "
|
||||
<< strerror(errno) << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// map it
|
||||
m_buffer = (unsigned char *)mmap(NULL, mbuf.length,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
m_fd, mbuf.m.offset);
|
||||
|
||||
if (m_buffer == MAP_FAILED)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": mmap() failed: "
|
||||
<< strerror(errno) << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// we'll need this when unmapping
|
||||
m_bufferLen = mbuf.length;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VCAP::releaseBuffer()
|
||||
{
|
||||
// first unmap any buffers
|
||||
if (m_buffer)
|
||||
munmap(m_buffer, m_bufferLen);
|
||||
|
||||
m_buffer = 0;
|
||||
m_bufferLen = 0;
|
||||
|
||||
// then, tell the kernel driver to free any allocated buffer(s)...
|
||||
struct v4l2_requestbuffers rb;
|
||||
memset(&rb, 0, sizeof(rb));
|
||||
|
||||
rb.count = 0;
|
||||
rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
rb.memory = V4L2_MEMORY_MMAP;
|
||||
|
||||
if (xioctl(m_fd, VIDIOC_REQBUFS, &rb) < 0)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": ioctl(VIDIOC_REQBUFS) failed while freeing: "
|
||||
<< strerror(errno) << endl;
|
||||
}
|
||||
|
||||
// reset captured flag
|
||||
m_imageCaptured = false;
|
||||
}
|
||||
|
||||
|
||||
bool VCAP::YUYV2JPEG(FILE *file)
|
||||
{
|
||||
struct jpeg_compress_struct jpgInfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
JSAMPROW row_pointer[1];
|
||||
unsigned char *row_buffer = NULL;
|
||||
unsigned char *yuyv = NULL;
|
||||
int z;
|
||||
|
||||
row_buffer = (unsigned char *)calloc(m_width * 3, 1);
|
||||
if (!row_buffer)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": allocation of line buffer failed."
|
||||
<< endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
yuyv = m_buffer;
|
||||
|
||||
jpgInfo.err = jpeg_std_error(&jerr);
|
||||
jpeg_create_compress(&jpgInfo);
|
||||
jpeg_stdio_dest(&jpgInfo, file);
|
||||
|
||||
jpgInfo.image_width = m_width;
|
||||
jpgInfo.image_height = m_height;
|
||||
|
||||
// components R, G, B
|
||||
jpgInfo.input_components = 3;
|
||||
jpgInfo.in_color_space = JCS_RGB;
|
||||
|
||||
jpeg_set_defaults(&jpgInfo);
|
||||
jpeg_set_quality(&jpgInfo, m_jpgQuality, TRUE);
|
||||
|
||||
jpeg_start_compress(&jpgInfo, TRUE);
|
||||
|
||||
z = 0;
|
||||
|
||||
while (jpgInfo.next_scanline < jpgInfo.image_height)
|
||||
{
|
||||
int x;
|
||||
unsigned char *ptr = row_buffer;
|
||||
|
||||
for (x = 0; x < m_width; x++)
|
||||
{
|
||||
int r, g, b;
|
||||
int y, u, v;
|
||||
|
||||
if (!z)
|
||||
y = yuyv[0] << 8;
|
||||
else
|
||||
y = yuyv[2] << 8;
|
||||
u = yuyv[1] - 128;
|
||||
v = yuyv[3] - 128;
|
||||
|
||||
r = (y + (359 * v)) >> 8;
|
||||
g = (y - (88 * u) - (183 * v)) >> 8;
|
||||
b = (y + (454 * u)) >> 8;
|
||||
|
||||
*(ptr++) = CLAMP(r, 0, 255);
|
||||
*(ptr++) = CLAMP(g, 0, 255);
|
||||
*(ptr++) = CLAMP(b, 0, 255);
|
||||
|
||||
if (z++)
|
||||
{
|
||||
z = 0;
|
||||
yuyv += 4;
|
||||
}
|
||||
}
|
||||
|
||||
row_pointer[0] = row_buffer;
|
||||
jpeg_write_scanlines(&jpgInfo, row_pointer, 1);
|
||||
}
|
||||
|
||||
jpeg_finish_compress(&jpgInfo);
|
||||
jpeg_destroy_compress(&jpgInfo);
|
||||
|
||||
free(row_buffer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VCAP::saveImage(string filename)
|
||||
{
|
||||
// check m_buffer to make sure we have an actual buffer... If not,
|
||||
// we throw here.
|
||||
if (!m_buffer)
|
||||
{
|
||||
throw std::runtime_error(std::string(__FUNCTION__) +
|
||||
": no buffer. Call setResolution() first");
|
||||
}
|
||||
|
||||
// if we haven't done at least one capture yet...
|
||||
if (!m_imageCaptured)
|
||||
{
|
||||
throw std::runtime_error(std::string(__FUNCTION__) +
|
||||
": No data, call captureImage() first");
|
||||
}
|
||||
|
||||
FILE *file;
|
||||
if ((file = fopen(filename.c_str(), "wb")) == NULL)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": fopen() failed: "
|
||||
<< strerror(errno) << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
YUYV2JPEG(file);
|
||||
fclose(file);
|
||||
|
||||
if (m_debugging)
|
||||
cerr << __FUNCTION__ << ": Saved image to " << filename << endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VCAP::captureImage()
|
||||
{
|
||||
// first, make sure a resolution was specified. If not, set the
|
||||
// default
|
||||
if (m_width == 0 || m_height == 0)
|
||||
{
|
||||
if (!setResolution(VCAP_DEFAULT_WIDTH, VCAP_DEFAULT_HEIGHT))
|
||||
throw std::runtime_error(std::string(__FUNCTION__) +
|
||||
": setResolution() failed");
|
||||
}
|
||||
|
||||
// we basically just call doCaptureImage() twice - once to grab and
|
||||
// discard the first frame (which is usually a remnent of a previous
|
||||
// capture), and another to grab the real frame we are interesed in.
|
||||
|
||||
if (!doCaptureImage())
|
||||
{
|
||||
cerr << __FUNCTION__ << ": capture of first frame failed"
|
||||
<< endl;
|
||||
}
|
||||
|
||||
return doCaptureImage();
|
||||
}
|
||||
|
||||
|
||||
// the real workhorse
|
||||
bool VCAP::doCaptureImage()
|
||||
{
|
||||
struct v4l2_buffer buf = {0};
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = 0;
|
||||
|
||||
// queue our buffer
|
||||
if (xioctl(m_fd, VIDIOC_QBUF, &buf) < 0)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": ioctl(VIDIOC_QBUF) failed: "
|
||||
<< strerror(errno) << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// enable streaming
|
||||
if (xioctl(m_fd, VIDIOC_STREAMON, &buf.type) < 0)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": ioctl(VIDIOC_STREAMON) failed: "
|
||||
<< strerror(errno) << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// use select to wait for a complete frame.
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(m_fd, &fds);
|
||||
|
||||
struct timeval tv;
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
|
||||
// 5 seconds should be more than enough
|
||||
tv.tv_sec = 5;
|
||||
|
||||
int rv;
|
||||
if ((rv = select(m_fd + 1, &fds, NULL, NULL, &tv)) < 0)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": select() failed: "
|
||||
<< strerror(errno) << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!rv)
|
||||
{
|
||||
// timed out
|
||||
cerr << __FUNCTION__ << ": select() timed out waiting for frame"
|
||||
<< endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// de-queue the buffer, we're now free to access it via the mmapped
|
||||
// ptr (m_buffer)
|
||||
if (xioctl(m_fd, VIDIOC_DQBUF, &buf) < 0)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": ioctl(VIDIOC_DQBUF) failed: "
|
||||
<< strerror(errno) << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// turn off streaming
|
||||
if (xioctl(m_fd, VIDIOC_STREAMOFF, &buf.type) < 0)
|
||||
{
|
||||
cerr << __FUNCTION__ << ": ioctl(VIDIOC_STREAMOFF) failed: "
|
||||
<< strerror(errno) << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
m_imageCaptured = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VCAP::setJPGQuality(unsigned int qual)
|
||||
{
|
||||
m_jpgQuality = CLAMP(qual, 0, 100);
|
||||
}
|
214
src/vcap/vcap.hpp
Normal file
214
src/vcap/vcap.hpp
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* 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 <iostream>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <jpeglib.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#define VCAP_DEFAULT_VIDEODEV "/dev/video0"
|
||||
#define VCAP_DEFAULT_OUTPUTFILE "vcap.jpg"
|
||||
#define VCAP_DEFAULT_WIDTH 640
|
||||
#define VCAP_DEFAULT_HEIGHT 480
|
||||
#define VCAP_DEFAULT_JPEG_QUALITY 99
|
||||
|
||||
namespace upm {
|
||||
/**
|
||||
* @brief Take a snapshot from a video camera and save as a JPEG
|
||||
* @defgroup vcap libupm-vcap
|
||||
* @ingroup video
|
||||
*/
|
||||
|
||||
/**
|
||||
* @library vcap
|
||||
* @sensor vcap
|
||||
* @comname Video Capture
|
||||
* @type video
|
||||
*
|
||||
* @brief API for the Video Capture driver
|
||||
*
|
||||
* This UPM module captures a still frame from a Linux V4L device,
|
||||
* such as a USB webcam, and and then allows you to save it as a
|
||||
* JPEG image into a file.
|
||||
*
|
||||
* The camera and driver in use must support streaming, mmap-able
|
||||
* buffers and must provide data in YUYV format. This should
|
||||
* encompass most video cameras out there. It has been tested
|
||||
* with a few off the shelf cameras without any problems.
|
||||
*
|
||||
* @snippet vcap.cxx Interesting
|
||||
*/
|
||||
|
||||
class VCAP {
|
||||
public:
|
||||
|
||||
/**
|
||||
* VCAP object constructor
|
||||
*
|
||||
* @param videoDev The path to the video device, default is /dev/video0.
|
||||
*/
|
||||
VCAP(std::string videoDev=VCAP_DEFAULT_VIDEODEV);
|
||||
|
||||
/**
|
||||
* VCAP object destructor
|
||||
*/
|
||||
~VCAP();
|
||||
|
||||
/**
|
||||
* Set the desired resolution of the output image. Note, this is
|
||||
* a hint to the underlying video driver. The video driver is
|
||||
* free to lower the specified resolution if the hardware cannot
|
||||
* support it. You can use getHeight() and getWidth() after
|
||||
* calling this method to see what the video driver chose.
|
||||
*
|
||||
* @param width The desired width of the image.
|
||||
* @param width The desired height of the image.
|
||||
* @return true if the operation succeeded, false otherwise.
|
||||
*/
|
||||
bool setResolution(int width, int height);
|
||||
|
||||
/**
|
||||
* Capture an image from the camera.
|
||||
*
|
||||
* @return true if the operation succeeded, false otherwise.
|
||||
*/
|
||||
bool captureImage();
|
||||
|
||||
/**
|
||||
* Save the captured image (created with captureImage()) to a file
|
||||
* in JPEG format. The file will be overwritten if it already
|
||||
* exists.
|
||||
*
|
||||
* @param filename The name of the file in which to store the image.
|
||||
* @return true if the operation succeeded, false otherwise.
|
||||
*/
|
||||
bool saveImage(std::string filename=VCAP_DEFAULT_OUTPUTFILE);
|
||||
|
||||
/**
|
||||
* Return the current width of the image. You can use this method
|
||||
* to determine if the video driver downgraded it after a call to
|
||||
* setResolution().
|
||||
*
|
||||
* @return true Current width of capture.
|
||||
*/
|
||||
int getWidth() const
|
||||
{
|
||||
return m_width;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the current height of the image. You can use this method
|
||||
* to determine if the video driver downgraded it after a call to
|
||||
* setResolution().
|
||||
*
|
||||
* @return true Current height of capture.
|
||||
*/
|
||||
int getHeight() const
|
||||
{
|
||||
return m_height;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the JPEG quality.
|
||||
*
|
||||
* @param quality A number between 0-100, with higher numbers
|
||||
* meaning higher quality. Numbers less than 0 will be clamped to
|
||||
* 0, numbers higher than 100 will be clamped to 100.
|
||||
*/
|
||||
void setJPGQuality(unsigned int quality);
|
||||
|
||||
/**
|
||||
* Get the current JPEG quality setting.
|
||||
*
|
||||
* @return the current JPEG quality setting.
|
||||
*/
|
||||
int getJPGQuality() const
|
||||
{
|
||||
return m_jpgQuality;
|
||||
};
|
||||
|
||||
/**
|
||||
* Enable or disable debugging output.
|
||||
*
|
||||
* @param enable true to enable debugging, false otherwise
|
||||
*/
|
||||
void setDebug(bool enable)
|
||||
{
|
||||
m_debugging = enable;
|
||||
};
|
||||
|
||||
protected:
|
||||
// open the device and check that it meats minimum requirements
|
||||
bool initVideoDevice();
|
||||
|
||||
// make sure device is streamable, supports mmap and capture
|
||||
bool checkCapabilities();
|
||||
|
||||
// read the mmapped buffer in YUYV format and create a jpeg image
|
||||
bool YUYV2JPEG(FILE *file);
|
||||
|
||||
// buffer management
|
||||
bool allocBuffer();
|
||||
void releaseBuffer();
|
||||
|
||||
// does the actual capture
|
||||
bool doCaptureImage();
|
||||
|
||||
private:
|
||||
// internal ioctl
|
||||
int xioctl(int fd, int request, void* argp);
|
||||
|
||||
std::string m_videoDevice;
|
||||
|
||||
// our file descriptor to the video device
|
||||
int m_fd;
|
||||
|
||||
// v4l info
|
||||
struct v4l2_capability m_caps;
|
||||
struct v4l2_format m_format;
|
||||
|
||||
// our mmaped buffer
|
||||
unsigned char *m_buffer;
|
||||
size_t m_bufferLen;
|
||||
|
||||
// the resolution and quality
|
||||
int m_width;
|
||||
int m_height;
|
||||
int m_jpgQuality;
|
||||
|
||||
// at least one image captured with current settings?
|
||||
bool m_imageCaptured;
|
||||
|
||||
// are we debugging?
|
||||
bool m_debugging;
|
||||
};
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user