C++ Core: Add base class per sensor/actuator type

Adding base classes for UPM sensors and actuators.

Signed-off-by: Noel Eck <noel.eck@intel.com>
This commit is contained in:
Noel Eck
2017-06-08 13:50:09 -07:00
parent b55501e327
commit 0223cd2b85
184 changed files with 4462 additions and 1099 deletions

11
src/core/.core.i Normal file
View File

@ -0,0 +1,11 @@
/* Any java package including an interface .i requires an import for
upm_core java package in the JNI source */
%pragma(java) jniclassimports=%{
import upm_core.*;
%}
/* Add the global UPM methods to all wrappers */
%{
#include "../upm_library_globals.hpp"
%}
%include "../upm_library_globals.hpp"

13
src/core/.iADC.i Normal file
View File

@ -0,0 +1,13 @@
%include ".iSensorType.i"
#if (SWIGJAVA)
#if SWIG_VERSION >= 0x030009
%include "swiginterface.i"
%interface_impl(upm::iADC);
#endif
#endif
%{
#include "iADC.hpp"
%}
%include "iADC.hpp"

14
src/core/.iActuatorType.i Normal file
View File

@ -0,0 +1,14 @@
%include ".iUpmObject.i"
#if (SWIGJAVA)
#if SWIG_VERSION >= 0x030009
%include "swiginterface.i"
%interface(upm::iActuatorType);
#endif
%ignore upm::iUpmObject::JsonDefinition;
#endif
%{
#include "iActuatorType.hpp"
%}
%include "iActuatorType.hpp"

13
src/core/.iCO2Sensor.i Normal file
View File

@ -0,0 +1,13 @@
%include ".iSensorType.i"
#if (SWIGJAVA)
#if SWIG_VERSION >= 0x030009
%include "swiginterface.i"
%interface_impl(upm::iCO2Sensor);
#endif
#endif
%{
#include "iCO2Sensor.hpp"
%}
%include "iCO2Sensor.hpp"

View File

@ -0,0 +1,29 @@
%include ".iSensorType.i"
#if (SWIGJAVA)
#if SWIG_VERSION >= 0x030009
%include "swiginterface.i"
%interface_impl(upm::iHumiditySensor);
#endif
#endif
%{
#include "iHumiditySensor.hpp"
%}
%include "iHumiditySensor.hpp"
/* FOR JAVASCRIPT ONLY!
If there's a better way to allow multiple inheritance w/javascript, the
following macro definitions can go away.
usage: INHERIT_IHUMIDITYSENSOR(upm::MySensorClass)
*/
%define INHERIT_IHUMIDITYSENSOR(YourClassName)
%extend YourClassName {
/*using upm::iSensorType::JsonDefinition;*/
/*using upm::iSensorType::JsonValues;*/
using upm::iHumiditySensor::JsonHumidity;
using upm::iHumiditySensor::HumidityAll;
using upm::iHumiditySensor::HumidityForSources;
}
%enddef

View File

@ -0,0 +1,13 @@
%include ".iSensorType.i"
#if (SWIGJAVA)
#if SWIG_VERSION >= 0x030009
%include "swiginterface.i"
%interface_impl(upm::iLightController);
#endif
#endif
%{
#include "iLightController.hpp"
%}
%include "iLightController.hpp"

13
src/core/.iLightSensor.i Normal file
View File

@ -0,0 +1,13 @@
%include ".iSensorType.i"
#if (SWIGJAVA)
#if SWIG_VERSION >= 0x030009
%include "swiginterface.i"
%interface_impl(upm::iLightSensor);
#endif
#endif
%{
#include "iLightSensor.hpp"
%}
%include "iLightSensor.hpp"

View File

@ -0,0 +1,13 @@
%include ".iSensorType.i"
#if (SWIGJAVA)
#if SWIG_VERSION >= 0x030009
%include "swiginterface.i"
%interface_impl(upm::iMoistureSensor);
#endif
#endif
%{
#include "iMoistureSensor.hpp"
%}
%include "iMoistureSensor.hpp"

37
src/core/.iMraa.i Normal file
View File

@ -0,0 +1,37 @@
%include ".iUpmObject.i"
#if (SWIGJAVA)
#if SWIG_VERSION >= 0x030009
%include "swiginterface.i"
%interface_impl(upm::iMraa);
#endif
#endif
%{
#include "iMraa.hpp"
%}
%include "iMraa.hpp"
typedef std::vector<mraa::Aio*> vec_aio;
%template(vec_aio) std::vector<mraa::Aio*>;
typedef std::vector<mraa::Gpio*> vec_gpio;
%template(vec_gpio) std::vector<mraa::Gpio*>;
typedef std::vector<mraa::I2c*> vec_i2c;
%template(vec_i2c) std::vector<mraa::I2c*>;
typedef std::vector<mraa::Iio*> vec_iio;
%template(vec_iio) std::vector<mraa::Iio*>;
typedef std::vector<mraa::Pwm*> vec_pwm;
%template(vec_pwm) std::vector<mraa::Pwm*>;
typedef std::vector<mraa::Spi*> vec_spi;
%template(vec_spi) std::vector<mraa::Spi*>;
typedef std::vector<mraa::Uart*> vec_uart;
%template(vec_uart) std::vector<mraa::Uart*>;
typedef std::vector<mraa::UartOW*> vec_uartow;
%template(vec_uartow) std::vector<mraa::UartOW*>;

View File

@ -0,0 +1,13 @@
%include ".iSensorType.i"
#if (SWIGJAVA)
#if SWIG_VERSION >= 0x030009
%include "swiginterface.i"
%interface_impl(upm::iPressureSensor);
#endif
#endif
%{
#include "iPressureSensor.hpp"
%}
%include "iPressureSensor.hpp"

14
src/core/.iSensorType.i Normal file
View File

@ -0,0 +1,14 @@
%include ".iUpmObject.i"
#if (SWIGJAVA)
#if SWIG_VERSION >= 0x030009
%include "swiginterface.i"
%interface(upm::iSensorType);
#endif
%ignore upm::iUpmObject::JsonDefinition;
#endif
%{
#include "iSensorType.hpp"
%}
%include "iSensorType.hpp"

View File

@ -0,0 +1,13 @@
%include ".iActuatorType.i"
#if (SWIGJAVA)
#if SWIG_VERSION >= 0x030009
%include "swiginterface.i"
%interface_impl(upm::iServoActuator);
#endif
#endif
%{
#include "iServoActuator.hpp"
%}
%include "iServoActuator.hpp"

View File

@ -0,0 +1,28 @@
%include ".iSensorType.i"
#if (SWIGJAVA)
#if SWIG_VERSION >= 0x030009
%include "swiginterface.i"
%interface_impl(upm::iTemperatureSensor);
#endif
#endif
%{
#include "iTemperatureSensor.hpp"
%}
%include "iTemperatureSensor.hpp"
/* FOR JAVASCRIPT ONLY!
If there's a better way to allow multiple inheritance w/javascript, the
following macro definitions can go away.
usage: INHERIT_ITEMPERATURESENSOR(upm::MySensorClass)
*/
%define INHERIT_ITEMPERATURESENSOR(YourClassName)
%extend YourClassName {
/*using upm::iSensorType::JsonDefinition;*/
/*using upm::iSensorType::JsonValues;*/
using upm::iTemperatureSensor::JsonTemperature;
using upm::iTemperatureSensor::TemperatureAll;
using upm::iTemperatureSensor::TemperatureForSources;
}
%enddef

68
src/core/.iUpmObject.i Normal file
View File

@ -0,0 +1,68 @@
%include "../common_top.i"
%include "std_vector.i"
%include "std_map.i"
/* Using the JAVA class types outside the core package requires
getCPtr to be public, modify that here */
%typemap(javabody) SWIGTYPE %{
private long swigCPtr;
protected boolean swigCMemOwn;
public $javaclassname(long cPtr, boolean cMemoryOwn) {
swigCMemOwn = cMemoryOwn;
swigCPtr = cPtr;
}
public static long getCPtr($javaclassname obj) {
return (obj == null) ? 0 : obj.swigCPtr;
}
%}
typedef std::vector<std::string> vec_str;
%template(vec_str) std::vector<std::string>;
typedef std::map<std::string, float> map_str_float;
%template(map_str_float) std::map<std::string, float>;
typedef std::map<std::string, std::string> map_str_str;
%template(map_str_str) std::map<std::string, std::string>;
/* Any java package including an interface .i will import the
upm_core java package in the JAVA source */
%typemap(javaimports) SWIGTYPE %{
import upm_core.*;
%}
#if (SWIGJAVA)
#if SWIG_VERSION >= 0x030009
%include "swiginterface.i"
%interface_impl(upm::iUpmObject);
#endif
#endif
%{
#include "iUpmObject.hpp"
%}
%include "iUpmObject.hpp"
/* FOR JAVASCRIPT ONLY!
If there's a better way to allow multiple inheritance w/javascript, the
following macro definitions can go away.
usage: INHERIT_IUPMOBJECT(upm::MySensorClass)
*/
%define INHERIT_IUPMOBJECT(YourClassName)
%extend YourClassName {
using upm::iUpmObject::Description;
using upm::iUpmObject::JsonDefinition;
using upm::iUpmObject::Name;
using upm::iUpmObject::initFromJsonLibDesc;
using upm::iUpmObject::DataDirectory;
using upm::iUpmObject::DerivedClassName;
using upm::iUpmObject::LibraryAbsolutePath;
using upm::iUpmObject::LibraryBaseName;
using upm::iUpmObject::LibraryJsonFilename;
using upm::iUpmObject::LibraryJsonRaw;
using upm::iUpmObject::LibraryVersion;
}
%enddef

38
src/core/CMakeLists.txt Normal file
View File

@ -0,0 +1,38 @@
# Create a source file for constants
configure_file (iUpmObject_generated.cxx.in iUpmObject_generated.cxx @ONLY)
upm_mixed_module_init (NAME core
DESCRIPTION "CXX Interface Library"
CPP_HDR iADC.hpp
iCO2Sensor.hpp
iHumiditySensor.hpp
iLightController.hpp
iLightSensor.hpp
iMoistureSensor.hpp
iMraa.hpp
iPressureSensor.hpp
iSensorType.hpp
iActuatorType.hpp
iServoActuator.hpp
iTemperatureSensor.hpp
iUpmObject.hpp
CPP_SRC "${CMAKE_CURRENT_BINARY_DIR}/iUpmObject_generated.cxx"
iADC.cxx
iCO2Sensor.cxx
iHumiditySensor.cxx
iLightController.cxx
iLightSensor.cxx
iMoistureSensor.cxx
iMraa.cxx
iPressureSensor.cxx
iSensorType.cxx
iActuatorType.cxx
iServoActuator.cxx
iTemperatureSensor.cxx
iUpmObject.cxx
REQUIRES mraa utilities-c)
# Add a PUBLIC include directory to the CMAKE src dir
target_include_directories (core
PUBLIC ${CMAKE_SOURCE_DIR}/src
${CMAKE_BINARY_DIR}/src)

25
src/core/core.i Normal file
View File

@ -0,0 +1,25 @@
%include "../common_top.i"
#ifdef SWIGJAVA
JAVA_JNI_LOADLIBRARY(javaupm_core)
/* JAVA has multiple define collisions once these get flattened out,
so ignore the base implementation */
%ignore "upm::iUpmObject::JsonDefinition";
#endif
%include ".iUpmObject.i"
%include ".iSensorType.i"
%include ".iTemperatureSensor.i"
%include ".iHumiditySensor.i"
%include ".iMraa.i"
%include ".iADC.i"
%include ".iPressureSensor.i"
%include ".iMoistureSensor.i"
%include ".iLightSensor.i"
%include ".iLightController.i"
%include ".iCO2Sensor.i"
/* Actuator types */
%include ".iActuatorType.i"
%include ".iServoActuator.i"

3
src/core/iADC.cxx Normal file
View File

@ -0,0 +1,3 @@
#include "iADC.hpp"
upm::iADC::~iADC () {}

45
src/core/iADC.hpp Normal file
View File

@ -0,0 +1,45 @@
/*
* Author: Henry Bruce <henry.bruce@intel.com>
* Copyright (c) 2015 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 <stdint.h>
#include "iSensorType.hpp"
namespace upm
{
/**
* @brief Interface for ADC Sensors
*/
class iADC : public virtual iSensorType
{
public:
virtual unsigned int getResolutionInBits() = 0;
virtual unsigned int getNumInputs() = 0;
virtual unsigned int getRawValue(unsigned int input) = 0;
virtual float getVoltage(unsigned int input) = 0;
virtual ~iADC();
};
}

2
src/core/iADC.i Normal file
View File

@ -0,0 +1,2 @@
%import (module="upm.pyupm_core") ".iADC.i"
%include ".core.i"

187
src/core/iActuatorType.cxx Normal file
View File

@ -0,0 +1,187 @@
#include "iActuatorType.hpp"
#include "external/json/json.hpp"
using namespace upm;
namespace upm {
template <typename T>
void to_json(nlohmann::json& j, const ActuatorSink<T> &p) {
j = nlohmann::json{{"unit", p.unit}, {"min", p.min}, {"max", p.max}, {"accuracy", p.accuracy}};
}
template <typename T>
void from_json(const nlohmann::json& j, ActuatorSink<T>& p) {
p.unit = j.at("unit").get<std::string>();
p.min = j.at("min").get<T>();
p.max = j.at("max").get<T>();
p.accuracy = j.at("accuracy").get<T>();
}
template <typename T>
void to_json(nlohmann::json& j, const ActuatorCommand<T> &p) {
j = nlohmann::json{{"command", p.command}, {"unit", p.unit}, {"value", p.value}};
}
template <typename T>
void from_json(const nlohmann::json& j, ActuatorCommand<T>& p) {
p.command= j.at("command").get<std::string>();
p.unit = j.at("unit").get<std::string>();
p.value = j.at("value").get<T>();
}
template <class T>
std::ostream &operator<<(std::ostream& os, const ActuatorCommand<T>& ac)
{
nlohmann::json jcmd = ac;
return os << jcmd;
}
}
iActuatorType::iActuatorType()
{
DEBUG_MSG("XXX");
}
iActuatorType::~iActuatorType()
{
DEBUG_MSG("XXX");
}
std::string iActuatorType::LibraryJsonCommands()
{
std::stringstream ss;
ss << this->LibraryJson()["Sensor Class"][Name()]["Commands"] << std::endl;
return ss.str();
}
void iActuatorType::AddCommand (std::string source, std::string unit)
{
/* Add the source:unit to the map */
_sinks_2_units[source] = unit;
/* Each call regens the sinks and units vectors */
_sinks.clear();
_units.clear();
for(std::map<std::string, std::string>::const_iterator it = CommandMap().begin();
it != CommandMap().end(); ++it)
{
_sinks.push_back(it->first);
_units.push_back(it->second);
}
/* Uniquify the sinks vector */
std::sort(_sinks.begin(), _sinks.end());
_sinks.erase(std::unique(_sinks.begin(), _sinks.end()), _sinks.end());
/* Uniquify the units vector */
std::sort(_units.begin(), _units.end());
_units.erase(std::unique(_units.begin(), _units.end()), _units.end());
}
std::map <std::string, std::string> const & iActuatorType::CommandMap () const
{ return _sinks_2_units;}
std::vector <std::string> const & iActuatorType::Commands ()
{
/* If there are zero sinks, look to the library json descriptor file */
if (_sinks.empty())
{
/* Copy all commands out of the JSON */
nlohmann::json j_sinks = nlohmann::json::parse(LibraryJsonCommands());
for (nlohmann::json::iterator it = j_sinks.begin(); it != j_sinks.end(); ++it)
_sinks.push_back(it.key());
}
return _sinks;
}
std::vector <std::string> const & iActuatorType::Units () const
{ return _units; }
std::string const iActuatorType::Unit (std::string source) const
{
std::map<std::string, std::string>::const_iterator it =
CommandMap().find(source);
if (it != CommandMap().end())
return it->second;
else
return "";
}
bool iActuatorType::HasCommand (std::string source)
{
return std::find(Commands().begin(), Commands().end(), source) != Commands().end();
}
bool iActuatorType::HasUnit (std::string unit) const
{
return std::find(Units().begin(), Units().end(), unit) != Units().end();
}
std::string iActuatorType::JsonDefinition ()
{
std::stringstream ss;
ss << "{" << std::endl
<< " \"name\" : \"" << Name() << "\"," << std::endl
<< " \"description\" : \"" << Description() << "\"";
if (!CommandMap().empty())
{
ss << "," << std::endl << " \"sinks\" :" << std::endl << " {" << std::endl;
for(std::map<std::string, std::string>::const_iterator it = CommandMap().begin();
it != CommandMap().end();)
{
ss << " \"" << it->first << "\" : {\"units\" : \"" << it->second << "\"}";
if (++it != CommandMap().end())
ss << "," << std::endl;
}
ss << std::endl << " }";
}
ss << std::endl << "}";
return ss.str();
}
void iActuatorType::JsonCommands(std::string commands)
{
std::stringstream ss;
ss << "{" << std::endl;
if (!_child_value_serializers.empty())
{
/* Iterate over each serializer method */
for (std::map<t_getJson, iUpmObject*>::const_iterator it = _child_value_serializers.begin();
it != _child_value_serializers.end();)
{
// Call static method to serialize data from the derived classes
ss << it->first(it->second);
if (++it != _child_value_serializers.end()) ss << ",";
ss << std::endl;
}
}
ss << "}";
/* TODO Change this method to a command method */
}
/* Since nlohmann::json has only been fwd declared (not included in a header),
* json is a partial type. Because of this explicitly instantiate basic
* types.
*/
template void upm::to_json(nlohmann::json& j, const ActuatorSink<int>& p);
template void upm::from_json(const nlohmann::json& j, ActuatorSink<int>& p);
template void upm::to_json(nlohmann::json& j, const ActuatorSink<float>& p);
template void upm::from_json(const nlohmann::json& j, ActuatorSink<float>& p);
template void upm::to_json(nlohmann::json& j, const ActuatorSink<double>& p);
template void upm::from_json(const nlohmann::json& j, ActuatorSink<double>& p);
template void upm::to_json(nlohmann::json& j, const ActuatorCommand<int>& p);
template void upm::from_json(const nlohmann::json& j, ActuatorCommand<int>& p);
template void upm::to_json(nlohmann::json& j, const ActuatorCommand<float>& p);
template void upm::from_json(const nlohmann::json& j, ActuatorCommand<float>& p);
template void upm::to_json(nlohmann::json& j, const ActuatorCommand<double>& p);
template void upm::from_json(const nlohmann::json& j, ActuatorCommand<double>& p);
template std::ostream &upm::operator<<(std::ostream& os, const ActuatorCommand<float>& ac);

156
src/core/iActuatorType.hpp Normal file
View File

@ -0,0 +1,156 @@
#pragma once
#include "iUpmObject.hpp"
/* I/O fwd declaration header */
#include <iosfwd>
namespace upm
{
template <typename T>
struct ActuatorSink
{
std::string unit;
T min;
T max;
T accuracy;
};
template <class T>
void to_json(nlohmann::json& j, const ActuatorSink<T>& p);
template <class T>
void from_json(const nlohmann::json& j, ActuatorSink<T>& p);
template <typename T>
struct ActuatorCommand
{
std::string command;
std::string unit;
T value;
};
template <class T>
void to_json(nlohmann::json& j, const ActuatorCommand<T>& p);
template <class T>
void from_json(const nlohmann::json& j, ActuatorCommand<T>& p);
template <class T>
std::ostream &operator<<(std::ostream&, const ActuatorCommand<T>&);
/**
* Forward declaration of iActuatorType class for ostream usage
*/
class iActuatorType;
/**
* iActuatorType abstract class.
*
* Provides a common interface for actuator classes. This interface is
* meant to be used by derived actuator categories.
*
* For example, iTemperatureSensor or iLightSensor
*
*/
class iActuatorType : public virtual iUpmObject
{
public:
iActuatorType();
/**
* Allow derived classes to provide their own destructor
*/
virtual ~iActuatorType();
std::string LibraryJsonCommands();
/**
* Return a map reference of sinks to units. This map can
* be used to get the units for a actuator value given a source.
*
* @return Map of sinks to units.
*/
const std::map<std::string, std::string>& CommandMap() const;
/**
* Return a vector of all known sinks for this actuator.
*
* @return Vector of sinks
*/
const std::vector<std::string>& Commands();
/**
* Return a vector of all known units for this actuator.
*
* @return Vector of units
*/
const std::vector<std::string>& Units() const;
/**
* Return a unit string given a single source.
*
* @return Corresponding unit for source or empty string if not found.
*/
virtual const std::string Unit(std::string source) const;
/**
* Determine if this actuator has a given source.
*
* @return True if source string is available, fails otherwise.
*/
virtual bool HasCommand(std::string source);
/**
* Determine if this actuator has a given unit.
*
* @return True if unit string is available, fails otherwise.
*/
virtual bool HasUnit(std::string unit) const;
/**
* Return a JsonDefinition string which defines this actuator
*
* @return JsonDefinition-encoded string.
*/
virtual std::string JsonDefinition();
/**
* @brief Json string of actuator data.
*
* The JsonValues call serializes ALL values returned by this actuator
* as a Json string.
*
* Example:
*
* "Temperature" : {"value" : 25.0, "units" : "C"}
* "Acceleration" : {"value" : 1.1, "units" : "m/s^2"}
*
* @return Json-encoded string.
*/
virtual void JsonCommands(std::string commands);
private:
/**
* Sensor source vector
*/
std::vector<std::string> _sinks;
/**
* Sensor unit vector
*/
std::vector<std::string> _units;
/**
* Mapping of sinks to units
*/
std::map<std::string, std::string> _sinks_2_units;
protected:
/**
* Mapping of sinks to units
*/
void AddCommand(std::string source, std::string unit);
};
}

4
src/core/iActuatorType.i Normal file
View File

@ -0,0 +1,4 @@
%import (module="upm.pyupm_core") "iActuatorType.hpp"
%include ".iActuatorType.i"
%include ".core.i"

54
src/core/iCO2Sensor.cxx Normal file
View File

@ -0,0 +1,54 @@
#include "iCO2Sensor.hpp"
using namespace upm;
std::map <std::string, float> iCO2Sensor::CO2All ()
{return CO2ForSources(Sources());}
float iCO2Sensor::CO2ForSource(std::string source)
{
std::map<std::string, float> vals = CO2ForSources(std::vector<std::string>(1, source));
if (vals.empty())
{
std::stringstream ss;
ss << __FUNCTION__ << " sensor does not provide source: '"
<< source << ". Valid sources are: {";
std::copy(Sources().begin(), Sources().end() - 1,
std::ostream_iterator<std::string>(ss, ", "));
ss << Sources().back() << "}";
throw std::invalid_argument(ss.str());
}
return vals[source];
}
iCO2Sensor::iCO2Sensor ()
{
AddValueSerializer(this, &_JsonCO2);
}
std::string iCO2Sensor::JsonCO2 () const
{
return "{" + _JsonCO2((iCO2Sensor*)this) + "}";
}
std::string iCO2Sensor::_JsonCO2 (iUpmObject * inst)
{
std::stringstream ss;
/* Downcast to reference (throws if cast fails) */
iCO2Sensor& ref = dynamic_cast<iCO2Sensor&>(*inst);
std::map<std::string, float> data = ref.CO2All();
for (std::map<std::string, float>::const_iterator it = data.begin();
it != data.end();)
{
ss << "\"" << it->first << "\" : {\"value\" : " << it->second
<< ", \"units\" : \"" << ref.Unit(it->first) << "\"}";
if (++it != data.end()) ss << "," << std::endl;
}
return ss.str();
}

72
src/core/iCO2Sensor.hpp Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include <map>
#include <vector>
#include "iSensorType.hpp"
namespace upm
{
/**
* iCO2Sensor abstract class.
*
* Provides a common interface for all sensors which detect co2.
*/
class iCO2Sensor : public virtual upm::iSensorType
{
public:
/**
* Read and return all values for this sensor as a map of sources
* to values.
*
* @return Map of sources to values.
*/
virtual std::map<std::string, float> CO2All();
/**
* Read and return a single value from the source provided
*
* @param source Target source to read
*
* @throws std::invalid_argument If source is NOT valid for this sensor
*
* @return Map of sources to values.
*/
virtual float CO2ForSource(std::string source);
/**
* Read and return all values for this sensor for the provided
* vector of sources.
*
* @param sources Vector of sources to read
*
* @return Map of sources to values.
*/
virtual std::map<std::string, float> CO2ForSources(std::vector<std::string> sources) = 0;
/**
* Add a pointer to this type and a proxy function pointer for
* serializing all values from this sensor type.
*/
iCO2Sensor();
/**
* Read and return all values for this sensor as JSON
*
* @return JSON string of co2 values
*/
virtual std::string JsonCO2() const;
private:
/**
* Provide a means to read and serialize values from this sensor
* as a static method. This method, along with a pointer to the
* class can be called from a base class
*
* @param inst Instance of iCO2Sensor to call _JsonCO2 on
*
* @return JSON string of co2 values (minus wrapping '{' and '}'
*/
static std::string _JsonCO2(iUpmObject * inst);
};
}

2
src/core/iCO2Sensor.i Normal file
View File

@ -0,0 +1,2 @@
%import (module="upm.pyupm_core") ".iCO2Sensor.i"
%include ".core.i"

View File

@ -0,0 +1,51 @@
#include "iHumiditySensor.hpp"
using namespace upm;
std::map <std::string, float> iHumiditySensor::HumidityAll ()
{return HumidityForSources(Sources());}
float iHumiditySensor::HumidityForSource (std::string source)
{
std::map<std::string, float> vals = HumidityForSources(std::vector<std::string>(1, source));
if (vals.empty())
{
std::stringstream ss;
ss << __FUNCTION__ << " sensor does not provide source: '"
<< source << ". Valid sources are: {";
std::copy(Sources().begin(), Sources().end() - 1,
std::ostream_iterator<std::string>(ss, ", "));
ss << Sources().back() << "}";
throw std::invalid_argument(ss.str());
}
return vals[source];
}
iHumiditySensor::iHumiditySensor ()
{
AddValueSerializer(this, &_JsonHumidity);
}
std::string iHumiditySensor::JsonHumidity () const
{
return "{" + _JsonHumidity((iHumiditySensor*)this) + "}";
}
std::string iHumiditySensor::_JsonHumidity (iUpmObject * inst)
{
std::stringstream ss;
/* Downcast to reference (throws if cast fails) */
iHumiditySensor& ref = dynamic_cast<iHumiditySensor&>(*inst);
std::map<std::string, float> data = ref.HumidityAll();
for (std::map<std::string, float>::const_iterator it = data.begin();
it != data.end();)
{
ss << "\"" << it->first << "\" : {\"value\" : " << it->second
<< ", \"units\" : \"" << ref.Unit(it->first) << "\"}";
if (++it != data.end()) ss << "," << std::endl;
}
return ss.str();
}

View File

@ -0,0 +1,72 @@
#pragma once
#include <map>
#include <vector>
#include "iSensorType.hpp"
namespace upm
{
/**
* iHumiditySensor abstract class.
*
* Provides a common interface for all sensors which detect humidity.
*/
class iHumiditySensor : public virtual iSensorType
{
public:
/**
* Read and return all values for this sensor as a map of sources
* to values.
*
* @return Map of sources to values.
*/
virtual std::map<std::string, float> HumidityAll();
/**
* Read and return a single value from the source provided
*
* @param source Target source to read
*
* @throws std::invalid_argument If source is NOT valid for this sensor
*
* @return Map of sources to values.
*/
virtual float HumidityForSource(std::string source);
/**
* Read and return all values for this sensor for the provided
* vector of sources.
*
* @param sources Vector of sources to read
*
* @return Map of sources to values.
*/
virtual std::map<std::string, float> HumidityForSources(std::vector<std::string> sources) = 0;
/**
* Add a pointer to this type and a proxy function pointer for
* serializing all values from this sensor type.
*/
iHumiditySensor();
/**
* Read and return all values for this sensor as JSON
*
* @return JSON string of humidity values
*/
virtual std::string JsonHumidity() const;
private:
/**
* Provide a means to read and serialize values from this sensor
* as a static method. This method, along with a pointer to the
* class can be called from a base class
*
* @param inst Instance of iHumiditySensor to call _JsonHumidity on
*
* @return JSON string of humidity values (minus wrapping '{' and '}'
*/
static std::string _JsonHumidity(iUpmObject * inst);
};
}

View File

@ -0,0 +1,2 @@
%import (module="upm.pyupm_core") ".iHumiditySensor.i"
%include ".core.i"

View File

@ -0,0 +1,3 @@
#include "iLightController.hpp"
upm::ILightController::~ILightController () {}

View File

@ -0,0 +1,93 @@
/*
* Author: Henry Bruce <henry.bruce@intel.com>
* Copyright (c) 2014 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
namespace upm
{
/**
* @brief ILightController Interface for Light Controllers
*/
/**
*
* @brief Interface for Light Controllers
* This interface is used to represent light controllers
* @snippet light-controllers.cxx Interesting
*/
class ILightController
{
public:
/**
* Turn on power
*
* @throws std::runtime_error
*/
virtual void setPowerOn() = 0;
/**
* Turn off power
*
* @throws std::runtime_error
*/
virtual void setPowerOff() = 0;
/**
* Get power state
*
* @return true if powered, false otherwise
*
* @throws std::runtime_error
*/
virtual bool isPowered() = 0;
/**
* Set brightness
*
* @param percent brightness as percentage
*
* @throws std::runtime_error
*/
virtual void setBrightness(int percent) = 0;
/**
* Get brightness
*
* @return brightness as percentage
*
* @throws std::runtime_error
*/
virtual int getBrightness() = 0;
virtual ~ILightController();
};
}

View File

@ -0,0 +1,2 @@
%import (module="upm.pyupm_core") ".iLightController.i"
%include ".core.i"

54
src/core/iLightSensor.cxx Normal file
View File

@ -0,0 +1,54 @@
#include "iLightSensor.hpp"
using namespace upm;
std::map <std::string, float> iLightSensor::LightAll ()
{return LightForSources(Sources());}
float iLightSensor::LightForSource (std::string source)
{
std::map<std::string, float> vals = LightForSources(std::vector<std::string>(1, source));
if (vals.empty())
{
std::stringstream ss;
ss << __FUNCTION__ << " sensor does not provide source: '"
<< source << ". Valid sources are: {";
std::copy(Sources().begin(), Sources().end() - 1,
std::ostream_iterator<std::string>(ss, ", "));
ss << Sources().back() << "}";
throw std::invalid_argument(ss.str());
}
return vals[source];
}
iLightSensor::iLightSensor ()
{
AddValueSerializer(this, &_JsonLight);
}
std::string iLightSensor::JsonLight ()
{
return "{" + _JsonLight(dynamic_cast<iLightSensor*>(this)) + "}";
}
std::string iLightSensor::_JsonLight (iUpmObject * inst)
{
std::stringstream ss;
/* Downcast to reference (throws if cast fails) */
iLightSensor& ref = dynamic_cast<iLightSensor&>(*inst);
std::map<std::string, float> data = ref.LightAll();
for (std::map<std::string, float>::const_iterator it = data.begin();
it != data.end();)
{
ss << "\"" << it->first << "\" : {\"value\" : " << it->second
<< ", \"units\" : \"" << ref.Unit(it->first) << "\"}";
if (++it != data.end()) ss << "," << std::endl;
}
return ss.str();
}

72
src/core/iLightSensor.hpp Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include <map>
#include <vector>
#include "iSensorType.hpp"
namespace upm
{
/**
* iLightSensor abstract class.
*
* Provides a common interface for all sensors which detect light.
*/
class iLightSensor : public virtual iSensorType
{
public:
/**
* Read and return all values for this sensor as a map of sources
* to values.
*
* @return Map of sources to values.
*/
virtual std::map<std::string, float> LightAll();
/**
* Read and return a single value from the source provided
*
* @param source Target source to read
*
* @throws std::invalid_argument If source is NOT valid for this sensor
*
* @return Map of sources to values.
*/
virtual float LightForSource(std::string source);
/**
* Read and return all values for this sensor for the provided
* vector of sources.
*
* @param sources Vector of sources to read
*
* @return Map of sources to values.
*/
virtual std::map<std::string, float> LightForSources(std::vector<std::string> sources) = 0;
/**
* Add a pointer to this type and a proxy function pointer for
* serializing all values from this sensor type.
*/
iLightSensor();
/**
* Read and return all values for this sensor as JSON
*
* @return JSON string of light values
*/
virtual std::string JsonLight();
private:
/**
* Provide a means to read and serialize values from this sensor
* as a static method. This method, along with a pointer to the
* class can be called from a base class
*
* @param inst Instance of iLightSensor to call _JsonLight on
*
* @return JSON string of light values (minus wrapping '{' and '}'
*/
static std::string _JsonLight(iUpmObject * inst);
};
}

2
src/core/iLightSensor.i Normal file
View File

@ -0,0 +1,2 @@
%import (module="upm.pyupm_core") ".iLightSensor.i"
%include ".core.i"

View File

@ -0,0 +1,39 @@
#include "iMoistureSensor.hpp"
using namespace upm;
std::map <std::string, float> iMoistureSensor::MoistureAll ()
{return MoistureForSources(Sources());}
std::map <std::string, float> iMoistureSensor::MoistureForSource (std::string source)
{ return MoistureForSources(std::vector<std::string>(1, source)); }
iMoistureSensor::iMoistureSensor ()
{
AddValueSerializer(this, &_JsonMoisture);
}
std::string iMoistureSensor::JsonMoisture () const
{
return "{" + _JsonMoisture((iMoistureSensor*)this) + "}";
}
std::string iMoistureSensor::_JsonMoisture (iUpmObject * inst)
{
std::stringstream ss;
/* Downcast to reference (throws if cast fails) */
iMoistureSensor& ref = dynamic_cast<iMoistureSensor&>(*inst);
std::map<std::string, float> data = ref.MoistureAll();
for (std::map<std::string, float>::const_iterator it = data.begin();
it != data.end();)
{
ss << "\"" << it->first << "\" : {\"value\" : " << it->second
<< ", \"units\" : \"" << ref.Unit(it->first) << "\"}";
if (++it != data.end()) ss << "," << std::endl;
}
return ss.str();
}

View File

@ -0,0 +1,29 @@
#pragma once
#include <map>
#include <vector>
#include "iSensorType.hpp"
namespace upm
{
class iMoistureSensor : public virtual iSensorType
{
public:
virtual std::map<std::string, float> MoistureAll();
virtual std::map<std::string, float> MoistureForSource(std::string source);
virtual std::map<std::string, float> MoistureForSources(std::vector<std::string> sources) = 0;
iMoistureSensor();
/**
* Read and return all values for this sensor as JSON
*
* @return JSON string of moisture values
*/
virtual std::string JsonMoisture() const;
private:
static std::string _JsonMoisture(iUpmObject * inst);
};
}

View File

@ -0,0 +1,2 @@
%import (module="upm.pyupm_core") ".iMoistureSensor.i"
%include ".core.i"

286
src/core/iMraa.cxx Normal file
View File

@ -0,0 +1,286 @@
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <regex>
#include "iUpmObject.hpp"
#include "iMraa.hpp"
#include "mraa/iio.hpp"
#include "mraa/uart_ow.hpp"
#define iMraaThrow(failure, protocol, fullstring) throw std::runtime_error("Failed to initialize " + \
std::string(protocol) + " from " + std::string(fullstring) + ", cause: " + \
std::string(failure))
using namespace upm;
template<typename Out>
void split(const std::string &s, char delim, Out result)
{
std::stringstream ss;
ss.str(s);
std::string item;
while (std::getline(ss, item, delim))
*(result++) = item;
}
std::vector<std::string> split(const std::string &s, char delim)
{
std::vector<std::string> elems;
split(s, delim, std::back_inserter(elems));
return elems;
}
uint32_t str2uint32(const std::string &number)
{
std::string lwr = number;
std::transform(lwr.begin(), lwr.end(), lwr.begin(), ::tolower);
uint32_t ret = 0;
std::stringstream ss;
if ((lwr.compare(0, 2, "0x") == 0) &&
(lwr.substr(2).find_first_not_of("0123456789abcdef") == std::string::npos))
{
ss << std::hex << lwr.substr(2);
ss >> ret;
}
else if (!lwr.empty() && lwr.find_first_not_of("0123456789") == std::string::npos)
{
ss << lwr;
ss >> ret;
}
else
throw std::runtime_error("Cannot convert '" + number + "' to an integer");
return ret;
}
std::map<std::string, mraa::Mode> _mraa_Mode =
{
{"strong", mraa::MODE_STRONG},
{"pullup", mraa::MODE_PULLUP},
{"pulldown", mraa::MODE_PULLDOWN},
{"hiz", mraa::MODE_HIZ},
};
std::map<std::string, mraa::Dir> _mraa_Dir =
{
{"out", mraa::DIR_OUT},
{"in", mraa::DIR_IN},
{"high", mraa::DIR_OUT_HIGH},
{"low", mraa::DIR_OUT_LOW},
};
std::map<std::string, mraa::Edge> _mraa_Edge =
{
{"none", mraa::EDGE_NONE},
{"both", mraa::EDGE_BOTH},
{"rising", mraa::EDGE_RISING},
{"falling", mraa::EDGE_FALLING},
};
std::map<std::string, mraa::InputMode> _mraa_InputMode =
{
{"active_high", mraa::MODE_IN_ACTIVE_HIGH},
{"avtive_low", mraa::MODE_IN_ACTIVE_LOW},
};
std::map<std::string, mraa::OutputMode> _mraa_OutputMode =
{
{"open_drain", mraa::MODE_OUT_OPEN_DRAIN},
{"push_pull", mraa::MODE_OUT_PUSH_PULL},
};
std::map<std::string, mraa::I2cMode> _mraa_I2cModes =
{
{"std", mraa::I2C_STD},
{"fast", mraa::I2C_FAST},
{"high", mraa::I2C_HIGH},
};
iMraa::iMraa()
{
DEBUG_MSG("XXX");
if (mraa::init() != mraa::SUCCESS)
throw std::runtime_error("Failed to initialize MRAA");
}
iMraa::iMraa(const std::string &init_string) : iMraa()
{
DEBUG_MSG("XXX");
/* Convert to lower case for processing */
std::string lwr = init_string;
std::transform(lwr.begin(), lwr.end(), lwr.begin(), ::tolower);
/* Split string into protocols separated by ',' */
std::vector<std::string> protocols = split(lwr, ',');
for (std::vector<std::string>::const_iterator it = protocols.begin();
it != protocols.end(); ++it)
{
/* Assign a reference for easier use */
const std::string& proto_str = *it;
/* Split proto_str into chunks separated by ':' */
std::vector<std::string> params = split(proto_str, ':');
/* Some basic error checking */
if (params.size() < 2)
throw std::runtime_error("Invalid initialization string: '" +
proto_str + "'. Format is proto0:val0:val1,proto1:val0:val1");
/* First character of first parameter defines the protocol */
const char proto = params[0][0];
switch (proto)
{
case 'a':
{
/* Next chunk should be a pin # */
uint32_t pin = str2uint32(params[1]);
try {_aio.push_back(new mraa::Aio(pin));}
catch (std::exception &e)
{
throw std::invalid_argument("Failed to initialize Aio from string: '" +
proto_str + "'. Reason: " + e.what());
}
break;
}
case 'g':
{
/* Next chunk should be a pin # */
uint32_t pin = str2uint32(params[1]);
try { _gpio.push_back(new mraa::Gpio(pin)); }
catch (std::exception &e)
{
throw std::invalid_argument("Failed to initialize Gpio from string: '" +
proto_str + "'. Reason: " + e.what());
}
/* Parse any additional parameters */
for(size_t i = 2; i < params.size(); ++i)
{
/* Gpio output modes */
if (_mraa_Mode.find(params[i]) != _mraa_Mode.end())
{
if (_gpio.back()->mode(_mraa_Mode[params[i]]) != mraa::SUCCESS)
iMraaThrow("mode(" + params[i] + ") failed.", "GPIO", proto_str);
}
/* Gpio direction options */
else if (_mraa_Dir.find(params[i]) != _mraa_Dir.end())
{
if (_gpio.back()->dir(_mraa_Dir[params[i]]) != mraa::SUCCESS)
iMraaThrow("dir(" + params[i] + ") failed.", "GPIO", proto_str);
}
/* Gpio edge types for interrupts */
else if (_mraa_Edge.find(params[i]) != _mraa_Edge.end())
{
if (_gpio.back()->edge(_mraa_Edge[params[i]]) != mraa::SUCCESS)
iMraaThrow("edge(" + params[i] + ") failed.", "GPIO", proto_str);
}
/* Gpio input modes */
else if (_mraa_InputMode.find(params[i]) != _mraa_InputMode.end())
{
if (_gpio.back()->inputMode(_mraa_InputMode[params[i]]) != mraa::SUCCESS)
iMraaThrow("inputMode(" + params[i] + ") failed.", "GPIO", proto_str);
}
/* Gpio output driver modes */
else if (_mraa_OutputMode.find(params[i]) != _mraa_OutputMode.end())
{
if (_gpio.back()->outputMode(_mraa_OutputMode[params[i]]) != mraa::SUCCESS)
iMraaThrow("outputMode(" + params[i] + ") failed.", "GPIO", proto_str);
}
/* Empty chunk? Skip it */
else if (params[i].empty()) {}
/* Unknown string? Write to stderr and continue */
else std::cerr << "Unknown parameter: '" << params[i] << "' from "
<< proto_str<< std::endl;
}
break;
}
case 'i':
{
/* Next chunk should be a bus # */
uint32_t bus = str2uint32(params[1]);
try { _i2c.push_back(new mraa::I2c(bus)); }
catch (std::exception &e)
{
throw std::invalid_argument("Failed to initialize I2c from string: '" +
proto_str + "'. Reason: " + e.what());
}
/* Parse any additional parameters */
for(size_t i = 2; i < params.size(); ++i)
{
/* I2c modes */
if (_mraa_I2cModes.find(params[i]) != _mraa_I2cModes.end())
{
if (_i2c.back()->frequency(_mraa_I2cModes[params[i]]) != mraa::SUCCESS)
iMraaThrow("frequency(" + params[i] + ") failed.", "I2C", proto_str);
}
}
break;
}
case 'o':
break;
case 'p': /* p:<pin>[:min_pw_us][:max_pw_us] */
{
/* Next chunk should be a pin # */
uint32_t pin = str2uint32(params[1]);
try { _pwm.push_back(new mraa::Pwm(pin)); }
catch (std::exception &e)
{
throw std::invalid_argument("Failed to initialize Pwm from string: '" +
proto_str + "'. Reason: " + e.what());
}
///* Parse any additional parameters */
///* Min pulse width in us */
//if (params.size() > 2)
//{
// if (_pwm.back()->min(_mraa_I2cModes[params[i]]) != mraa::SUCCESS)
// iMraaThrow("frequency(" + params[i] + ") failed.", "I2C", proto_str);
//}
break;
}
case 's':
break;
case 'u':
break;
case 'w':
break;
default:
break;
}
}
return;
}
iMraa::~iMraa()
{
for (std::vector<mraa::Aio*>::iterator it = _aio.begin();
it != _aio.end(); ++it) delete *it;
for (std::vector<mraa::Gpio*>::iterator it = _gpio.begin();
it != _gpio.end(); ++it) delete *it;
for (std::vector<mraa::I2c*>::iterator it = _i2c.begin();
it != _i2c.end(); ++it) delete *it;
for (std::vector<mraa::Pwm*>::iterator it = _pwm.begin();
it != _pwm.end(); ++it) delete *it;
}
std::string iMraa::Connections()
{
std::stringstream ss;
ss << "MRAA connections ("
<< _aio.size() + _gpio.size() + _i2c.size() + _iio.size() +
_pwm.size() + _spi.size() + _uart.size() + _uartow.size()
<< "):" << std::endl;
if (!_aio.empty()) ss << "\tAIO: " << _aio.size() << std::endl;
if (!_gpio.empty()) ss << "\tGPIO: " << _gpio.size() << std::endl;
if (!_i2c.empty()) ss << "\tI2C: " << _i2c.size() << std::endl;
if (!_iio.empty()) ss << "\tIIO: " << _iio.size() << std::endl;
if (!_pwm.empty()) ss << "\tPWM: " << _pwm.size() << std::endl;
if (!_spi.empty()) ss << "\tSPI: " << _spi.size() << std::endl;
if (!_uart.empty()) ss << "\tUART: " << _uart.size() << std::endl;
if (!_uartow.empty()) ss << "\tOneWire: " << _uartow.size() << std::endl;
return ss.str();
}

55
src/core/iMraa.hpp Normal file
View File

@ -0,0 +1,55 @@
#pragma once
#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <regex>
#include "iUpmObject.hpp"
#include "mraa.hpp"
#include "mraa/iio.hpp"
#include "mraa/uart_ow.hpp"
namespace upm
{
class iMraa : public virtual iUpmObject
{
public:
iMraa();
iMraa(const std::string &init_string);
virtual ~iMraa();
std::string Connections();
//
// template <typename T>
// T& Connection(std::string label);
//
// template <typename T>
// bool DefineConnections(std::vector<std::string> labels)
// {
// if (std::is_same<T, mraa::Aio>::value)
// {
// }
// else if (std::is_same<T, mraa::Gpio>::value) {}
// else if (std::is_same<T, mraa::I2c>::value)
// {
// }
//
// return false;
// }
//private:
std::vector<mraa::Aio*> _aio;
std::vector<mraa::Gpio*> _gpio;
std::vector<mraa::I2c*> _i2c;
std::vector<mraa::Iio*> _iio;
std::vector<mraa::Pwm*> _pwm;
std::vector<mraa::Spi*> _spi;
std::vector<mraa::Uart*> _uart;
std::vector<mraa::UartOW*> _uartow;
};
}

2
src/core/iMraa.i Normal file
View File

@ -0,0 +1,2 @@
%import (module="upm.pyupm_core") ".iMraa.i"
%include ".core.i"

View File

@ -0,0 +1,54 @@
#include "iPressureSensor.hpp"
using namespace upm;
std::map <std::string, float> iPressureSensor::PressureAll ()
{return PressureForSources(Sources());}
float iPressureSensor::PressureForSource (std::string source)
{
std::map<std::string, float> vals = PressureForSources(std::vector<std::string>(1, source));
if (vals.empty())
{
std::stringstream ss;
ss << __FUNCTION__ << " sensor does not provide source: '"
<< source << ". Valid sources are: {";
std::copy(Sources().begin(), Sources().end() - 1,
std::ostream_iterator<std::string>(ss, ", "));
ss << Sources().back() << "}";
throw std::invalid_argument(ss.str());
}
return vals[source];
}
iPressureSensor::iPressureSensor ()
{
AddValueSerializer(this, &_JsonPressure);
}
std::string iPressureSensor::JsonPressure () const
{
return "{" + _JsonPressure((iPressureSensor*)this) + "}";
}
std::string iPressureSensor::_JsonPressure (iUpmObject * inst)
{
std::stringstream ss;
/* Downcast to reference (throws if cast fails) */
iPressureSensor& ref = dynamic_cast<iPressureSensor&>(*inst);
std::map<std::string, float> data = ref.PressureAll();
for (std::map<std::string, float>::const_iterator it = data.begin();
it != data.end();)
{
ss << "\"" << it->first << "\" : {\"value\" : " << it->second
<< ", \"units\" : \"" << ref.Unit(it->first) << "\"}";
if (++it != data.end()) ss << "," << std::endl;
}
return ss.str();
}

View File

@ -0,0 +1,72 @@
#pragma once
#include <map>
#include <vector>
#include "iSensorType.hpp"
namespace upm
{
/**
* iPressureSensor abstract class.
*
* Provides a common interface for all sensors which detect pressure.
*/
class iPressureSensor : public virtual iSensorType
{
public:
/**
* Read and return all values for this sensor as a map of sources
* to values.
*
* @return Map of sources to values.
*/
virtual std::map<std::string, float> PressureAll();
/**
* Read and return a single value from the source provided
*
* @param source Target source to read
*
* @throws std::invalid_argument If source is NOT valid for this sensor
*
* @return Map of sources to values.
*/
virtual float PressureForSource(std::string source);
/**
* Read and return all values for this sensor for the provided
* vector of sources.
*
* @param sources Vector of sources to read
*
* @return Map of sources to values.
*/
virtual std::map<std::string, float> PressureForSources(std::vector<std::string> sources) = 0;
/**
* Add a pointer to this type and a proxy function pointer for
* serializing all values from this sensor type.
*/
iPressureSensor();
/**
* Read and return all values for this sensor as JSON
*
* @return JSON string of pressure values
*/
virtual std::string JsonPressure() const;
private:
/**
* Provide a means to read and serialize values from this sensor
* as a static method. This method, along with a pointer to the
* class can be called from a base class
*
* @param inst Instance of iPressureSensor to call _JsonPressure on
*
* @return JSON string of pressure values (minus wrapping '{' and '}'
*/
static std::string _JsonPressure(iUpmObject * inst);
};
}

View File

@ -0,0 +1,2 @@
%import (module="upm.pyupm_core") ".iPressureSensor.i"
%include ".core.i"

156
src/core/iSensorType.cxx Normal file
View File

@ -0,0 +1,156 @@
#include "iSensorType.hpp"
#include "external/json/json.hpp"
using namespace upm;
namespace upm {
template <typename T>
void to_json(nlohmann::json& j, const SensorSource<T> &p) {
j = nlohmann::json{{"unit", p.unit}, {"min", p.min}, {"max", p.max}, {"accuracy", p.accuracy}};
}
template <typename T>
void from_json(const nlohmann::json& j, SensorSource<T>& p) {
p.unit = j.at("unit").get<std::string>();
p.min = j.at("min").get<T>();
p.max = j.at("max").get<T>();
p.accuracy = j.at("accuracy").get<T>();
}
}
iSensorType::iSensorType()
{
DEBUG_MSG("XXX");
}
iSensorType::~iSensorType()
{
DEBUG_MSG("XXX");
}
std::string iSensorType::LibraryJsonSources()
{
std::stringstream ss;
ss << this->LibraryJson()["Sensor Class"][Name()]["Sources"] << std::endl;
return ss.str();
}
void iSensorType::AddSource (std::string source, std::string unit)
{
/* Add the source:unit to the map */
_sources_2_units[source] = unit;
/* Each call regens the sources and units vectors */
_sources.clear();
_units.clear();
for(std::map<std::string, std::string>::const_iterator it = SourceMap().begin();
it != SourceMap().end(); ++it)
{
_sources.push_back(it->first);
_units.push_back(it->second);
}
/* Uniquify the sources vector */
std::sort(_sources.begin(), _sources.end());
_sources.erase(std::unique(_sources.begin(), _sources.end()), _sources.end());
/* Uniquify the units vector */
std::sort(_units.begin(), _units.end());
_units.erase(std::unique(_units.begin(), _units.end()), _units.end());
}
std::map <std::string, std::string> const & iSensorType::SourceMap () const
{ return _sources_2_units;}
std::vector <std::string> const & iSensorType::Sources ()
{
/* If there are zero sources, look to the library json descriptor file */
if (_sources.empty())
{
/* Copy all commands out of the JSON */
nlohmann::json j_sources = nlohmann::json::parse(LibraryJsonSources());
for (nlohmann::json::iterator it = j_sources.begin(); it != j_sources.end(); ++it)
_sources.push_back(it.key());
}
return _sources; }
std::vector <std::string> const & iSensorType::Units () const
{ return _units; }
std::string const iSensorType::Unit (std::string source) const
{
std::map<std::string, std::string>::const_iterator it =
SourceMap().find(source);
if (it != SourceMap().end())
return it->second;
else
return "";
}
bool iSensorType::HasSource (std::string source)
{
return std::find(Sources().begin(), Sources().end(), source) != Sources().end();
}
bool iSensorType::HasUnit (std::string unit) const
{
return std::find(Units().begin(), Units().end(), unit) != Units().end();
}
std::string iSensorType::JsonDefinition ()
{
std::stringstream ss;
ss << "{" << std::endl
<< " \"name\" : \"" << Name() << "\"," << std::endl
<< " \"description\" : \"" << Description() << "\"";
if (!SourceMap().empty())
{
ss << "," << std::endl << " \"sources\" :" << std::endl << " {" << std::endl;
for(std::map<std::string, std::string>::const_iterator it = SourceMap().begin();
it != SourceMap().end();)
{
ss << " \"" << it->first << "\" : {\"units\" : \"" << it->second << "\"}";
if (++it != SourceMap().end())
ss << "," << std::endl;
}
ss << std::endl << " }";
}
ss << std::endl << "}";
return ss.str();
}
std::string iSensorType::JsonValues ()
{
std::stringstream ss;
ss << "{" << std::endl;
if (!_child_value_serializers.empty())
{
/* Iterate over each serializer method */
for (std::map<t_getJson, iUpmObject*>::const_iterator it = _child_value_serializers.begin();
it != _child_value_serializers.end();)
{
// Call static method to serialize data from the derived classes
ss << it->first(it->second);
if (++it != _child_value_serializers.end()) ss << ",";
ss << std::endl;
}
}
ss << "}";
return ss.str();
}
/* Since nlohmann::json has only been fwd declared (not included in a header),
* json is a partial type. Because of this explicitly instantiate basic
* types.
*/
template void upm::to_json(nlohmann::json& j, const SensorSource<int>& p);
template void upm::from_json(const nlohmann::json& j, SensorSource<int>& p);
template void upm::to_json(nlohmann::json& j, const SensorSource<float>& p);
template void upm::from_json(const nlohmann::json& j, SensorSource<float>& p);
template void upm::to_json(nlohmann::json& j, const SensorSource<double>& p);
template void upm::from_json(const nlohmann::json& j, SensorSource<double>& p);

143
src/core/iSensorType.hpp Normal file
View File

@ -0,0 +1,143 @@
#pragma once
#include <map>
#include <sstream>
#include <vector>
#include <iterator>
#include <algorithm>
#include "iUpmObject.hpp"
namespace upm
{
template <typename T>
struct SensorSource
{
std::string unit;
T min;
T max;
T accuracy;
};
template <class T>
void to_json(nlohmann::json& j, const SensorSource<T>& p);
template <class T>
void from_json(const nlohmann::json& j, SensorSource<T>& p);
/**
* Forward declaration of iSensorType class for ostream usage
*/
class iSensorType;
/**
* iSensorType abstract class.
*
* Provides a common interface for sensor classes. This interface is
* meant to be used by derived sensor categories.
*
* For example, iTemperatureSensor or iLightSensor
*
*/
class iSensorType : public virtual iUpmObject
{
public:
iSensorType();
/**
* Allow derived classes to provide their own destructor
*/
virtual ~iSensorType();
std::string LibraryJsonSources();
/**
* Return a map reference of sources to units. This map can
* be used to get the units for a sensor value given a source.
*
* @return Map of sources to units.
*/
const std::map<std::string, std::string>& SourceMap() const;
/**
* Return a vector of all known sources for this sensor.
*
* @return Vector of sources
*/
const std::vector<std::string>& Sources();
/**
* Return a vector of all known units for this sensor.
*
* @return Vector of units
*/
const std::vector<std::string>& Units() const;
/**
* Return a unit string given a single source.
*
* @return Corresponding unit for source or empty string if not found.
*/
virtual const std::string Unit(std::string source) const;
/**
* Determine if this sensor has a given source.
*
* @return True if source string is available, fails otherwise.
*/
virtual bool HasSource(std::string source);
/**
* Determine if this sensor has a given unit.
*
* @return True if unit string is available, fails otherwise.
*/
virtual bool HasUnit(std::string unit) const;
/**
* Return a JsonDefinition string which defines this sensor
*
* @return JsonDefinition-encoded string.
*/
virtual std::string JsonDefinition();
/**
* @brief Json string of sensor data.
*
* The JsonValues call serializes ALL values returned by this sensor
* as a Json string.
*
* Example:
*
* "Temperature" : {"value" : 25.0, "units" : "C"}
* "Acceleration" : {"value" : 1.1, "units" : "m/s^2"}
*
* @return Json-encoded string.
*/
virtual std::string JsonValues();
private:
/**
* Sensor source vector
*/
std::vector<std::string> _sources;
/**
* Sensor unit vector
*/
std::vector<std::string> _units;
/**
* Mapping of sources to units
*/
std::map<std::string, std::string> _sources_2_units;
protected:
/**
* Mapping of sources to units
*/
void AddSource(std::string source, std::string unit);
};
}

4
src/core/iSensorType.i Normal file
View File

@ -0,0 +1,4 @@
%import (module="upm.pyupm_core") "iSensorType.hpp"
%include ".iSensorType.i"
%include ".core.i"

147
src/core/iServoActuator.cxx Normal file
View File

@ -0,0 +1,147 @@
#include <iterator>
#include "iServoActuator.hpp"
#include "external/json/json.hpp"
#include <iostream>
using namespace upm;
iServoActuator::iServoActuator ()
{
DEBUG_MSG("XXX");
AddJsonDeserializer(this, &_DeserializeAngleCommands);
}
iServoActuator::~iServoActuator ()
{
DEBUG_MSG("XXX");
}
void iServoActuator::AngleAll (float angle)
{
std::map<std::string, float> tmpcmds;
for(std::vector<std::string>::const_iterator it = Commands().begin();
it != Commands().end(); ++it)
tmpcmds[*it] = angle;
AngleForCommands(tmpcmds);
}
void iServoActuator::AngleForCommand (float angle, std::string command)
{
DEBUG_MSG("Number of commands: " << Commands().size() << std::endl);
if (std::find(Commands().begin(), Commands().end(), command) == Commands().end())
{
std::stringstream ss;
ss << DerivedClassName() << " does not provide command: '"
<< command << "'. Valid commands are: {";
std::copy(Commands().begin(), Commands().end() - 1,
std::ostream_iterator<std::string>(ss, ", "));
if (!Commands().empty())
ss << Commands().back();
ss << "}";
throw std::invalid_argument(ss.str());
}
AngleForCommands(std::map<std::string, float> {{command, angle}});
}
void iServoActuator::AngleFromJson(std::string json_commands)
{
std::vector<ActuatorCommand<float>> cmds;
/* First, try to deserialize 1 command */
try
{
nlohmann::json json_cmd = nlohmann::json::parse(json_commands);
cmds.push_back(json_cmd);
}
catch (const std::exception& e)
{
DEBUG_MSG("Deserialize single command failed, attempting to deserialize command vector...");
}
/* If no commands were created, try to deserialize a vector of commands */
if (cmds.empty())
{
try
{
nlohmann::json json_cmd = nlohmann::json::parse(json_commands);
/* TODO: get rid of this second copy */
std::vector<ActuatorCommand<float>> tmp_cmds = json_cmd;
cmds = tmp_cmds;
}
catch (const std::exception& e)
{
DEBUG_MSG("Deserialize command vector failed...");
}
}
/* If no commands exist, throw */
if (cmds.empty())
{
std::stringstream ss;
ss << "Failed to deserialize commands from json string: '";
ss << json_commands << "'" << std::endl;
ss << "Valid JSON command string examples:" << std::endl;
/* Make the examples (at least 2) */
std::vector<ActuatorCommand<float>> tmp_cmds(Commands().size() < 2 ? 2 : Commands().size());
for(size_t i = 0; i < Commands().size(); i++)
tmp_cmds[i].command = Commands()[i];
/* Example strings show a single command and vector or commands */
nlohmann::json jcmd = tmp_cmds[0];
nlohmann::json jcmds = tmp_cmds;
ss << "'" << jcmd << "' or '" << jcmds << "'";
throw std::invalid_argument(ss.str());
}
/* Run the commands */
for (std::vector<ActuatorCommand<float>>::const_iterator it = cmds.begin(); it != cmds.end(); ++it)
{
AngleForCommand(it->value, it->command);
}
}
std::string iServoActuator::_DeserializeAngleCommands (iUpmObject * inst)
{
/* Downcast to reference (throws if cast fails) */
iServoActuator& ref = dynamic_cast<iServoActuator&>(*inst);
/* Make sure the derived class name (from std::type_info) matches a JSON sensor class name */
std::string classname_derived = ref.DerivedClassName();
/* First, get a json reference to the "Sensor Class" */
nlohmann::json json_class = ref.LibraryJson()["Sensor Class"];
if (json_class.find(classname_derived) == json_class.end())
{
std::stringstream ss;
for (nlohmann::json::iterator it = json_class.begin(); it != json_class.end(); ++it)
{
ss << it.key();
if (*it != json_class.back()) ss << ", ";
}
throw std::invalid_argument("JSON library descriptor file " + inst->LibraryJsonFilename() + " does not contain a class object named '" +
classname_derived + "'. Valid classes are: {" + ss.str() + "}");
}
/* Get a reference to the 'Commands' object, if none exists, catch and continue */
nlohmann::json jsrs;
try { jsrs = ref.LibraryJson()["Sensor Class"][classname_derived].at("Commands"); }
catch (...) {}
/* Add all commands to iSensorType's command vector */
for (nlohmann::json::iterator it = jsrs.begin(); it != jsrs.end(); ++it)
{
upm::ActuatorSink<float> _as = it.value();
ref.AddCommand(it.key(), _as.unit);
}
/* Return a string */
return jsrs.dump();
}

View File

@ -0,0 +1,58 @@
#pragma once
#include "iActuatorType.hpp"
namespace upm
{
/**
* iServoActuator abstract class.
*
* Provides a common interface for all sensors which detect light.
*/
class iServoActuator : public virtual iActuatorType
{
public:
/**
* Add a pointer to this type and a proxy function pointer for
* serializing all values from this sensor type.
*/
iServoActuator();
/* Provide a virtual destructor */
virtual ~iServoActuator();
/**
* Read and return all values for this sensor as a map of commands
* to values.
*
* @return Map of commands to values.
*/
virtual void AngleAll(float angle);
/**
* Read and return a single value from the command provided
*
* @param command Target command to read
*
* @throws std::invalid_argument If command is NOT valid for this sensor
*
* @return Map of commands to values.
*/
virtual void AngleForCommand(float angle, std::string command);
/**
* Read and return all values for this sensor for the provided
* vector of commands.
*
* @param commands Vector of commands to read
*
* @return Map of commands to values.
*/
virtual void AngleForCommands(std::map<std::string, float> commands) = 0;
virtual void AngleFromJson(std::string json_commands);
private:
static std::string _DeserializeAngleCommands(iUpmObject * inst);
};
}

View File

@ -0,0 +1,2 @@
%import (module="upm.pyupm_core") ".iServoActuator.i"
%include ".core.i"

View File

@ -0,0 +1,90 @@
#include "iTemperatureSensor.hpp"
#include "external/json/json.hpp"
using namespace upm;
typedef struct
{
std::string unit;
float min;
float max;
float accuracy;
} SensorSource ;
std::map <std::string, float> iTemperatureSensor::TemperatureAll ()
{return TemperatureForSources(Sources());}
float iTemperatureSensor::TemperatureForSource (std::string source)
{
std::map<std::string, float> vals = TemperatureForSources(std::vector<std::string>(1, source));
if (vals.empty())
{
std::stringstream ss;
ss << __FUNCTION__ << " sensor does not provide source: '"
<< source << "'. Valid sources are: {";
std::copy(Sources().begin(), Sources().end() - 1,
std::ostream_iterator<std::string>(ss, ", "));
ss << Sources().back() << "}";
throw std::invalid_argument(ss.str());
}
return vals[source];
}
iTemperatureSensor::iTemperatureSensor ()
{
AddValueSerializer(this, &_JsonTemperature);
AddJsonDeserializer(this, &_DeserializeTemperatureSources);
}
std::string iTemperatureSensor::JsonTemperature () const
{
return "{" + _JsonTemperature((iTemperatureSensor*)this) + "}";
}
std::string iTemperatureSensor::_JsonTemperature (iUpmObject * inst)
{
std::stringstream ss;
/* Downcast to reference (throws if cast fails) */
iTemperatureSensor& ref = dynamic_cast<iTemperatureSensor&>(*inst);
std::map<std::string, float> data = ref.TemperatureAll();
for (std::map<std::string, float>::const_iterator it = data.begin();
it != data.end();)
{
ss << "\"" << it->first << "\" : {\"value\" : " << it->second
<< ", \"units\" : \"" << ref.Unit(it->first) << "\"}";
if (++it != data.end()) ss << "," << std::endl;
}
return ss.str();
}
std::string iTemperatureSensor::_DeserializeTemperatureSources (iUpmObject * inst)
{
/* Downcast to reference (throws if cast fails) */
iTemperatureSensor& ref = dynamic_cast<iTemperatureSensor&>(*inst);
/* Make sure the derived class name (from std::type_info) matches a JSON sensor class name */
std::string classname_derived = ref.DerivedClassName();
/* Get a reference to the object */
nlohmann::json jsrs = ref.LibraryJson()["Sensor Class"][classname_derived]["Sources"];
/* Deserialize to a temperature source map */
std::map<std::string, upm::SensorSource<float>> sources = jsrs;
/* Assign to this instance */
ref._temp_sources = sources;
/* Add all sources to iSensorType's source vector */
for (std::map<std::string, upm::SensorSource<float>>::const_iterator it = ref._temp_sources.begin();
it != ref._temp_sources.end(); ++it)
ref.AddSource(it->first, it->second.unit);
/* Return a string */
return jsrs.dump();
}

View File

@ -0,0 +1,77 @@
#pragma once
#include <map>
#include <vector>
#include "iSensorType.hpp"
namespace upm
{
/**
* iTemperatureSensor abstract class.
*
* Provides a common interface for all sensors which detect temperature.
*/
class iTemperatureSensor : public virtual iSensorType
{
public:
/**
* Read and return all values for this sensor as a map of sources
* to values.
*
* @return Map of sources to values.
*/
virtual std::map<std::string, float> TemperatureAll();
/**
* Read and return a single value from the source provided
*
* @param source Target source to read
*
* @throws std::invalid_argument If source is NOT valid for this sensor
*
* @return Map of sources to values.
*/
virtual float TemperatureForSource(std::string source);
/**
* Read and return all values for this sensor for the provided
* vector of sources.
*
* @param sources Vector of sources to read
*
* @return Map of sources to values.
*/
virtual std::map<std::string, float> TemperatureForSources(std::vector<std::string> sources) = 0;
/**
* Add a pointer to this type and a proxy function pointer for
* serializing all values from this sensor type.
*/
iTemperatureSensor();
/**
* Read and return all values for this sensor as JSON
*
* @return JSON string of temperature values
*/
virtual std::string JsonTemperature() const;
private:
/**
* Provide a means to read and serialize values from this sensor
* as a static method. This method, along with a pointer to the
* class can be called from a base class
*
* @param inst Instance of iTemperatureSensor to call _JsonTemperature on
*
* @return JSON string of temperature values (minus wrapping '{' and '}'
*/
static std::string _JsonTemperature(iUpmObject * inst);
static std::string _DeserializeTemperatureSources(iUpmObject * inst);
std::map<std::string, upm::SensorSource<float>> _temp_sources;
};
}

View File

@ -0,0 +1,2 @@
%import (module="upm.pyupm_core") ".iTemperatureSensor.i"
%include ".core.i"

287
src/core/iUpmObject.cxx Normal file
View File

@ -0,0 +1,287 @@
#include <dlfcn.h>
#include <typeinfo>
#include <cxxabi.h>
#include <string.h>
#include <iostream>
#include <regex>
#include <fstream>
#include "external/json/json.hpp"
#include "iUpmObject.hpp"
#include "upm_library_globals.hpp"
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define THROW_RUNTIME(msg) throw std::runtime_error(std::string(__FILENAME__) + ":" + std::to_string(__LINE__) + " [" + std::string(__FUNCTION__) + "] " + msg)
extern const char* DATA_DIRECTORY;
static std::string DATA_DIRECTORY_STR = DATA_DIRECTORY;
using namespace upm;
using json = nlohmann::json;
/* Locate method to test if a file exists */
static bool exists(const std::string& filename, bool throw_exception = false)
{
std::ifstream f;
if (throw_exception)
f.exceptions(std::ifstream::failbit);
try {
f.open(filename.c_str());
}
catch (const std::exception& e)
{
throw std::runtime_error("'" + filename + "' does not exist or is not accessible.");
}
return f.good();
}
/* Always create an instance of the _json pointer (empty) */
iUpmObject::iUpmObject()
{
DEBUG_MSG("XXX");
}
iUpmObject::~iUpmObject()
{
DEBUG_MSG("XXX");
if (_json)
{
delete _json;
_json = NULL;
}
}
void iUpmObject::initFromJsonLibDesc(std::string path_to_json_file)
{
/* Throw if the file exists (as is, no realpath) */
exists(path_to_json_file, true);
/* Next, convert to a realpath */
const char * rp = realpath(path_to_json_file.c_str(), NULL);
if (!rp)
throw std::runtime_error("'" + path_to_json_file + "' does not exist or is not accessible.");
std::string realpath_json_file(rp);
/* If this method is getting called ALWAYS delete and re-init */
if (_json)
{
delete _json;
_json = NULL;
}
_json = new json;
/* Does the provided file exist? Is it readable? */
std::string json_str;
std::ifstream t(realpath_json_file);
json_str.assign((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
/* Parse the file as JSON */
*_json = _json->parse(json_str.c_str(), nullptr, false);
/* Set the library JSON filename */
_LibraryJsonFilename = realpath_json_file;
/* Run any additional deserializers available on the JSON */
if (!_child_json_deserializers.empty())
{
std::stringstream ss;
/* Iterate over each serializer method */
for (std::map<t_getJson, iUpmObject*>::const_iterator it = _child_json_deserializers.begin();
it != _child_json_deserializers.end();)
{
// Call static method to serialize data from the derived classes
ss << it->first(it->second);
if (++it != _child_json_deserializers.end()) ss << ",";
ss << std::endl;
}
DEBUG_MSG("XXX Deserializers: " << ss.str());
}
}
std::string iUpmObject::Description()
{
json x = LibraryJson()["Sensor Class"][Name()]["Description"];
if (x.empty())
THROW_RUNTIME("No Description found for sensor class '" + Name() + "' in the JSON library descriptor file: " + LibraryJsonFilename());
return x;
}
std::string iUpmObject::JsonDefinition ()
{
std::stringstream ss;
ss << "{" << std::endl
<< " \"name\" : \"" << Name() << "\"," << std::endl
<< " \"description\" : \"" << Description() << "\""
<< std::endl << "}";
return ss.str();
}
std::string iUpmObject::Name()
{
/* Make sure the derived class name (from std::type_info) matches a JSON sensor class name */
std::string classname_derived = DerivedClassName();
/* Look at all objects under 'Sensor Class' */
json x = LibraryJson()["Sensor Class"][classname_derived];
if (x.empty())
THROW_RUNTIME("Sensor class Name '" + classname_derived + "' was not found in the JSON library descriptor file: " + LibraryJsonFilename());
return classname_derived;
}
json &iUpmObject::LibraryJson()
{
/* If no object, create one and load the library descriptor file*/
if (!_json)
{
_json = new json;
initFromJsonLibDesc(LibraryJsonFilename());
}
/* If the library descriptor JSON file has NOT been loaded, load it */
// if (_json->empty())
// {
// initFromJsonLibDesc(LibraryJsonFilename().c_str());
// //*_json = _json->parse(LibraryJsonRaw());
// }
/* Perform a quick error check: Library element must be equal to LibraryBaseName() */
// std::string lib_base_name = LibraryBaseName();
// std::string lib_json_name = (*_json)["Library"];
// if (lib_base_name != (*_json)["Library"])
// THROW_RUNTIME("Library base name '" + lib_base_name + "' does NOT match the Library name specified in the JSON file '" + lib_json_name +"'");
return *_json;
}
std::string iUpmObject::DerivedClassName() const
{
int status = 0;
char *name_demangled;
const std::type_info &this_type = typeid(*this);
/* Demangle class name */
name_demangled = abi::__cxa_demangle(this_type.name(), 0, 0, &status);
if (status)
THROW_RUNTIME("Failed to demangle class name.");
std::string name = name_demangled;
free(name_demangled);
Dl_info info;
/* Returns 0 on failure */
if (!dladdr((const void*)&this_type, &info))
return NULL;
/* Return class name only */
return name.substr(name.find_last_of(":") + 1);
}
std::string iUpmObject::LibraryAbsolutePath() const
{
Dl_info info;
const std::type_info &this_type = typeid(*this);
/* Throw on failure */
if (!dladdr((const void*)&this_type, &info))
THROW_RUNTIME("Failed to locate the library for this type.");
/* Attempt a realpath */
return realpath(info.dli_fname, NULL);
}
std::string iUpmObject::LibraryBaseName() const
{
/* First, get the full filename */
std::string filename = LibraryAbsolutePath();
std::string basename = filename.substr(filename.find_last_of("/\\") + 1);
/* Regex the library *base* name from the library file name */
std::smatch sm;
std::regex reg1("libupm-(\\S+)\\.so");
if (std::regex_search(basename, sm, reg1))
basename = sm.str(1);
// else
// std::cout << "XXX warning, binary: " << filename << " does not match format: libupm-<libname>.so, using: " << basename;
//THROW_RUNTIME("Could not get base library name. UPM library name does not follow the libupm-<library>.so format.");
return basename;
}
std::string iUpmObject::LibraryJsonFilename() const
{
if (!_LibraryJsonFilename.empty())
return _LibraryJsonFilename;
std::string json_file = DataDirectory() + "/" + LibraryBaseName() + ".json";
if (!exists(json_file))
THROW_RUNTIME("Failed to locate library JSON definition: " + json_file);
return json_file;
}
std::string iUpmObject::DataDirectory() const
{
std::string lib_loc = LibraryAbsolutePath();
/* If a json file has already been provided, use it */
std::string json_lib_def_file = _LibraryJsonFilename;
/* Otherwise, attempt to build the location of the json file */
if (json_lib_def_file.empty())
json_lib_def_file = lib_loc.substr(0, lib_loc.find_last_of("/\\")) + "/" + LibraryBaseName() + ".json";
/* If no local <libname>.json exists, look in DATADIR */
if (!exists(json_lib_def_file))
{
// If the library is:
// /usr/local/lib/libupm-rhusb.so.1.6.0
// then look one directory up for share/upm like so:
// /usr/local/share/upm/rhusb/rhusb.json
json_lib_def_file = DATA_DIRECTORY_STR + "/upm/" + LibraryBaseName() + "/" + LibraryBaseName() + ".json";
}
if (!exists(json_lib_def_file))
THROW_RUNTIME("Data directory for UPM was not found. Library found: " + lib_loc + ", expected JSON definition file: " + json_lib_def_file);
return json_lib_def_file.substr(0, json_lib_def_file.find_last_of("/\\"));
}
std::string iUpmObject::LibraryJsonRaw() const
{
std::string json_file = LibraryJsonFilename();
/* Return the contents as a string */
std::string json_str;
std::ifstream t(json_file);
json_str.assign((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
return json_str.c_str();
}
std::string iUpmObject::LibraryVersion() const
{
return ::LibraryVersion();
}
void iUpmObject::AddValueSerializer (iUpmObject * instance, t_getJson method)
{ _child_value_serializers[method] = instance; }
void iUpmObject::AddJsonDeserializer(iUpmObject * instance, t_getJson method)
{ _child_json_deserializers[method] = instance; }

121
src/core/iUpmObject.hpp Normal file
View File

@ -0,0 +1,121 @@
#pragma once
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <stdint.h>
#include <memory>
#if !defined(NDEBUG)
#include <iostream>
#endif
#ifndef SWIG
/* Forward declare the basic_json class */
namespace nlohmann
{
template<typename, typename>
struct adl_serializer;
template<template<typename, typename, typename...> class ObjectType,
template<typename, typename...> class ArrayType,
class StringType,
class BooleanType,
class NumberIntegerType,
class NumberUnsignedType,
class NumberFloatType,
template<typename> class AllocatorType,
template<typename, typename> class JSONSerializer>
class basic_json;
using json = basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, double, std::allocator, nlohmann::adl_serializer>;
}
#endif
namespace upm
{
inline std::string __func_or_memberfunc(const std::string& cxx_function)
{
size_t colons = cxx_function.find("::");
size_t begin = cxx_function.substr(0, colons).rfind(" ") + 1;
size_t end = cxx_function.rfind(")") - begin + 1;
return cxx_function.substr(begin, end);
}
#define __PRETTY_FUNCTIONS__ __func_or_memberfunc(__PRETTY_FUNCTION__)
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#if !defined(NDEBUG)
#define DEBUG_MSG(msg) do { std::cout << __FILENAME__ << ":" << __LINE__ \
<< " [" << __PRETTY_FUNCTIONS__ << "] " << msg << std::endl; } while (0)
#else
#define DEBUG_MSG(msg) do {} while (0)
#endif
class iUpmObject;
/**
* Function pointer typedef for child-to-parent proxy call
*/
typedef std::string (*t_getJson)(iUpmObject*);
class iUpmObject
{
public:
iUpmObject();
virtual ~iUpmObject();
virtual std::string Description();
virtual std::string JsonDefinition();
virtual std::string Name();
virtual void initFromJsonLibDesc(std::string path_to_json_file);
#ifndef SWIG
nlohmann::json& LibraryJson();
#endif
std::string DataDirectory() const;
std::string DerivedClassName() const;
std::string LibraryAbsolutePath() const;
std::string LibraryBaseName() const;
std::string LibraryJsonFilename() const;
std::string LibraryJsonRaw() const;
std::string LibraryVersion() const;
protected:
void AddValueSerializer(iUpmObject* instance, t_getJson method);
void AddJsonDeserializer(iUpmObject* instance, t_getJson method);
/**
* Used by child classes for child-to-parent proxy call
*/
std::map<t_getJson, iUpmObject*> _child_value_serializers;
/**
* Used by child classes for child-to-parent proxy call
*/
std::map<t_getJson, iUpmObject*> _child_json_deserializers;
///*
//friend std::ostream& operator<<(std::ostream& os, const iUpmObject& o)
//{
// return os << " \"name\" : \"" << o.Name() << "\"," << std::endl
// << " \"description\" : \"" << o.Description() << "\"";
//}
//friend std::ostream& operator<<(std::ostream& os, const iUpmObject* o)
//{ return os << *o; }
//*/
private:
nlohmann::json *_json = NULL;
std::string _Description;
std::string _LibraryJsonFilename;
std::string _LibraryJsonRaw;
};
}

2
src/core/iUpmObject.i Normal file
View File

@ -0,0 +1,2 @@
%import (module="upm.pyupm_core") "iUpmObject.hpp"
%include ".iUpmObject.i"

View File

@ -0,0 +1 @@
const char* DATA_DIRECTORY = "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_DATADIR@";