diff --git a/CMakeLists.txt b/CMakeLists.txt index 7df2f855..d17e6dd6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -482,9 +482,6 @@ endif() # UPM common headers set (UPM_COMMON_HEADER_DIRS ${CMAKE_HOME_DIRECTORY}/include) -# Generate a build-only C++ header to add functionality to SWIG'ed modules -configure_file (${PROJECT_SOURCE_DIR}/cmake/modules/version.hpp.in ${PROJECT_BINARY_DIR}/src/version.hpp @ONLY) - # UPM source add_subdirectory (src) diff --git a/cmake/modules/version.hpp.in b/cmake/modules/version.hpp.in deleted file mode 100644 index 27ccb7ad..00000000 --- a/cmake/modules/version.hpp.in +++ /dev/null @@ -1,6 +0,0 @@ -#include - -inline std::string getVersion() -{ - return "@upm_VERSION_STRING@"; -} diff --git a/docs/images/noelstemplightreader.png b/docs/images/noelstemplightreader.png new file mode 100644 index 00000000..9fdaac84 Binary files /dev/null and b/docs/images/noelstemplightreader.png differ diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index c179f4de..3bc7537c 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -120,7 +120,7 @@ if(BUILDEXAMPLES) # Add all examples as an install component (if building examples) install (DIRECTORY ${PROJECT_SOURCE_DIR}/examples - DESTINATION ${CMAKE_INSTALL_DATADIR}/upm/ + DESTINATION ${CMAKE_INSTALL_DATADIR}/upm COMPONENT ${CMAKE_PROJECT_NAME}-examples FILES_MATCHING PATTERN "*.c" diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index 68553354..1d1b1347 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -4,15 +4,15 @@ file (GLOB example_src_list RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.cxx") # - Handle special cases here -------------------------------------------------- # Test humidity interface for 2 sensor libraries -add_example(interfaces-humiditysensor.cxx TARGETS si7005 bmp280) +add_example(core-humiditysensor.cxx TARGETS si7005 bmp280) # Test pressure interface for 2 sensor libraries -add_example(interfaces-pressuresensor.cxx TARGETS bmp280 bmpx8x) +add_example(core-pressuresensor.cxx TARGETS bmp280 bmpx8x) # Test temperature interface for 3 sensor libraries -add_example(interfaces-temperaturesensor.cxx TARGETS bmp280 bmpx8x si7005) +add_example(core-temperaturesensor.cxx TARGETS bmp280 bmpx8x si7005) # Test light interface for 2 sensor libraries -add_example(interfaces-lightsensor.cxx TARGETS si1132 max44009) +add_example(core-lightsensor.cxx TARGETS si1132 max44009) # Test light controller interface for 3 sensor libraries -add_example(interfaces-lightcontroller.cxx TARGETS lp8860 ds1808lc hlg150h) +add_example(core-lightcontroller.cxx TARGETS lp8860 ds1808lc hlg150h) # - Create an executable for all other src files in this directory ------------- foreach (_example_src ${example_src_list}) diff --git a/examples/c++/ads1x15-adc-sensor.cxx b/examples/c++/ads1x15-adc-sensor.cxx index ee6bf4bb..2b88497e 100644 --- a/examples/c++/ads1x15-adc-sensor.cxx +++ b/examples/c++/ads1x15-adc-sensor.cxx @@ -43,14 +43,14 @@ main() mraa::Gpio gpio(EDISON_GPIO_SI7005_CS); gpio.dir(mraa::DIR_OUT_HIGH); - /* Show usage from the IADC interface */ - upm::IADC* adc = static_cast(&sensor); + /* Show usage from the iADC interface */ + upm::iADC* adc = static_cast(&sensor); if (adc == NULL) { std::cout << "ADC not detected" << std::endl; return 1; } - std::cout << "ADC " << adc->getModuleName() << " detected. "; + std::cout << "ADC " << adc->Name() << " detected. "; std::cout << adc->getNumInputs() << " inputs available" << std::endl; while (true) { for (unsigned int i = 0; i < adc->getNumInputs(); ++i) { diff --git a/examples/c++/interfaces-humiditysensor.cxx b/examples/c++/core-humiditysensor.cxx similarity index 73% rename from examples/c++/interfaces-humiditysensor.cxx rename to examples/c++/core-humiditysensor.cxx index 52973dc3..c8c5b7ea 100644 --- a/examples/c++/interfaces-humiditysensor.cxx +++ b/examples/c++/core-humiditysensor.cxx @@ -38,14 +38,14 @@ #define EDISON_GPIO_SI7005_CS 20 //! [Interesting] -// Simple example of using ILightSensor to determine +// Simple example of using iHumiditySensor to determine // which sensor is present and return its name. -// ILightSensor is then used to get readings from sensor +// iHumiditySensor is then used to get readings from sensor -upm::IHumiditySensor* +upm::iHumiditySensor* getHumiditySensor() { - upm::IHumiditySensor* humiditySensor = NULL; + upm::iHumiditySensor* humiditySensor = NULL; try { humiditySensor = new upm::BME280(mraa_get_sub_platform_id(FT4222_I2C_BUS)); @@ -66,22 +66,26 @@ getHumiditySensor() int main() { - upm::IHumiditySensor* humiditySensor = getHumiditySensor(); - if (humiditySensor == NULL) { + upm::iHumiditySensor* sensor = getHumiditySensor(); + + if (sensor == NULL) { std::cout << "Humidity sensor not detected" << std::endl; return 1; } - std::cout << "Humidity sensor " << humiditySensor->getModuleName() << " detected" << std::endl; - while (true) { - try { - int value = humiditySensor->getHumidityRelative(); - std::cout << "Humidity = " << value << "%" << std::endl; - } catch (std::exception& e) { - std::cerr << e.what() << std::endl; - } - upm_delay(1); + + std::cout << "Humidity sensor " << sensor->Name() << " detected" << std::endl; + + try { + std::map values = sensor->HumidityAll(); + for (std::map::const_iterator it = values.begin(); + it != values.end(); ++it) + std::cout << it->first << " = " << it->second + << sensor->Unit(it->first) << std::endl; + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; } - delete humiditySensor; + + delete sensor; return 0; } diff --git a/examples/c++/interfaces-lightcontroller.cxx b/examples/c++/core-lightcontroller.cxx similarity index 96% rename from examples/c++/interfaces-lightcontroller.cxx rename to examples/c++/core-lightcontroller.cxx index cc99a119..e6d69bed 100644 --- a/examples/c++/interfaces-lightcontroller.cxx +++ b/examples/c++/core-lightcontroller.cxx @@ -66,7 +66,7 @@ main(int argc, char** argv) upm::ILightController* lightController = getLightController(); if (lightController != NULL) { - std::cout << "Detected light controller " << lightController->getModuleName() << std::endl; + //std::cout << "Detected light controller " << lightController->getModuleName() << std::endl; } else { std::cerr << "Error. Unsupported platform." << std::endl; return 1; diff --git a/examples/c++/interfaces-lightsensor.cxx b/examples/c++/core-lightsensor.cxx similarity index 73% rename from examples/c++/interfaces-lightsensor.cxx rename to examples/c++/core-lightsensor.cxx index 9f754f89..b8f11416 100644 --- a/examples/c++/interfaces-lightsensor.cxx +++ b/examples/c++/core-lightsensor.cxx @@ -36,14 +36,14 @@ #define FT4222_I2C_BUS 0 //! [Interesting] -// Simple example of using ILightSensor to determine +// Simple example of using iLightSensor to determine // which sensor is present and return its name. -// ILightSensor is then used to get readings from sensor +// iLightSensor is then used to get readings from sensor -upm::ILightSensor* +upm::iLightSensor* getLightSensor() { - upm::ILightSensor* lightSensor = NULL; + upm::iLightSensor* lightSensor = NULL; try { lightSensor = new upm::SI1132(mraa_get_sub_platform_id(FT4222_I2C_BUS)); return lightSensor; @@ -62,22 +62,26 @@ getLightSensor() int main() { - upm::ILightSensor* lightSensor = getLightSensor(); - if (lightSensor == NULL) { + upm::iLightSensor* sensor = getLightSensor(); + + if (sensor == NULL) { std::cout << "Light sensor not detected" << std::endl; return 1; } - std::cout << "Light sensor " << lightSensor->getModuleName() << " detected" << std::endl; - while (true) { - try { - float value = lightSensor->getVisibleLux(); - std::cout << "Light level = " << value << " lux" << std::endl; - } catch (std::exception& e) { - std::cerr << e.what() << std::endl; - } - upm_delay(1); + + std::cout << "Light sensor " << sensor->Name() << " detected" << std::endl; + + try { + std::map values = sensor->LightAll(); + for (std::map::const_iterator it = values.begin(); + it != values.end(); ++it) + std::cout << it->first << " = " << it->second + << sensor->Unit(it->first) << std::endl; + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; } - delete lightSensor; + + delete sensor; return 0; } diff --git a/examples/c++/interfaces-pressuresensor.cxx b/examples/c++/core-pressuresensor.cxx similarity index 73% rename from examples/c++/interfaces-pressuresensor.cxx rename to examples/c++/core-pressuresensor.cxx index 437011a2..ea8c8fdb 100644 --- a/examples/c++/interfaces-pressuresensor.cxx +++ b/examples/c++/core-pressuresensor.cxx @@ -36,14 +36,14 @@ #define FT4222_I2C_BUS 0 //! [Interesting] -// Simple example of using ILightSensor to determine +// Simple example of using iPressureSensor to determine // which sensor is present and return its name. -// ILightSensor is then used to get readings from sensor +// iPressureSensor is then used to get readings from sensor -upm::IPressureSensor* +upm::iPressureSensor* getPressureSensor() { - upm::IPressureSensor* pressureSensor = NULL; + upm::iPressureSensor* pressureSensor = NULL; try { pressureSensor = new upm::BME280(mraa_get_sub_platform_id(FT4222_I2C_BUS)); return pressureSensor; @@ -63,22 +63,26 @@ getPressureSensor() int main() { - upm::IPressureSensor* pressureSensor = getPressureSensor(); - if (pressureSensor == NULL) { + upm::iPressureSensor* sensor = getPressureSensor(); + + if (sensor == NULL) { std::cout << "Pressure sensor not detected" << std::endl; return 1; } - std::cout << "Pressure sensor " << pressureSensor->getModuleName() << " detected" << std::endl; - while (true) { - try { - int value = pressureSensor->getPressurePa(); - std::cout << "Pressure = " << value << " Pa" << std::endl; - } catch (std::exception& e) { - std::cerr << e.what() << std::endl; - } - upm_delay(1); + + std::cout << "Pressure sensor " << sensor->Name() << " detected" << std::endl; + + try { + std::map values = sensor->PressureAll(); + for (std::map::const_iterator it = values.begin(); + it != values.end(); ++it) + std::cout << it->first << " = " << it->second + << sensor->Unit(it->first) << std::endl; + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; } - delete pressureSensor; + + delete sensor; return 0; } diff --git a/examples/c++/interfaces-temperaturesensor.cxx b/examples/c++/core-temperaturesensor.cxx similarity index 75% rename from examples/c++/interfaces-temperaturesensor.cxx rename to examples/c++/core-temperaturesensor.cxx index 8871166f..37bce940 100644 --- a/examples/c++/interfaces-temperaturesensor.cxx +++ b/examples/c++/core-temperaturesensor.cxx @@ -39,14 +39,14 @@ #define EDISON_GPIO_SI7005_CS 20 //! [Interesting] -// Simple example of using ITemperatureSensor to determine +// Simple example of using iTemperatureSensor to determine // which sensor is present and return its name. -// ITemperatureSensor is then used to get readings from sensor +// iTemperatureSensor is then used to get readings from sensor -upm::ITemperatureSensor* +upm::iTemperatureSensor* getTemperatureSensor() { - upm::ITemperatureSensor* temperatureSensor = NULL; + upm::iTemperatureSensor* temperatureSensor = NULL; try { temperatureSensor = new upm::BME280(mraa_get_sub_platform_id(FT4222_I2C_BUS)); @@ -73,23 +73,26 @@ getTemperatureSensor() int main() { - upm::ITemperatureSensor* temperatureSensor = getTemperatureSensor(); - if (temperatureSensor == NULL) { + upm::iTemperatureSensor* sensor = getTemperatureSensor(); + + if (sensor == NULL) { std::cout << "Temperature sensor not detected" << std::endl; return 1; } - std::cout << "Temperature sensor " << temperatureSensor->getModuleName() << " detected" - << std::endl; - while (true) { - try { - int value = temperatureSensor->getTemperatureCelsius(); - std::cout << "Temperature = " << value << "C" << std::endl; - } catch (std::exception& e) { - std::cerr << e.what() << std::endl; - } - upm_delay(1); + + std::cout << "Temperature sensor " << sensor->Name() << " detected" << std::endl; + + try { + std::map values = sensor->TemperatureAll(); + for (std::map::const_iterator it = values.begin(); + it != values.end(); ++it) + std::cout << it->first << " = " << it->second + << sensor->Unit(it->first) << std::endl; + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; } - delete temperatureSensor; + + delete sensor; return 0; } diff --git a/examples/c++/ims.cxx b/examples/c++/ims.cxx index ae574dc8..c52557b6 100644 --- a/examples/c++/ims.cxx +++ b/examples/c++/ims.cxx @@ -47,7 +47,7 @@ main(int argc, char** argv) //! [Interesting] // Instantiate a IMS instance using i2c bus 0 and default address - upm::IMS sensor(0); + upm::IMS sensor("i:0:0x20"); int i2c_addr_cur = IMS_ADDRESS_DEFAULT + 1; while (shouldRun) { diff --git a/examples/c++/noelstemplightreader.cxx b/examples/c++/noelstemplightreader.cxx new file mode 100644 index 00000000..8df89ca0 --- /dev/null +++ b/examples/c++/noelstemplightreader.cxx @@ -0,0 +1,49 @@ +#include +#include + +#include "core/iUpmObject.hpp" +#include "noelstemplightreader.hpp" + +void printMap(upm::NoelsTempLightReader &sensor, std::map &data) +{ + if (data.empty()) + std::cout << "Empty map" << std::endl; + for (std::map::const_iterator it = data.begin(); + it != data.end(); ++it) + { + std::cout << "label: " << it->first << ", value: " << it->second + << ", unit: " << sensor.Unit(it->first) << std::endl; + } + std::cout << std::endl; +} + +int main () +{ + upm::NoelsTempLightReader sensor; + std::cout << "iUpmObject JsonDefinition..." << std::endl << ((upm::iUpmObject&)sensor).JsonDefinition() << std::endl << std::endl; + std::cout << "iSensorType JsonDefinition..." << std::endl << ((upm::iSensorType&)sensor).JsonDefinition() << std::endl << std::endl; + std::cout << "iMraa JsonDefinition..." << std::endl << ((upm::iMraa&)sensor).JsonDefinition() << std::endl << std::endl; + std::cout << "NoelsTempLightReader JsonDefinition..." << std::endl << sensor.JsonDefinition() << std::endl << std::endl; + + std::cout << "Read all light values..." << std::endl; + std::map values = sensor.LightAll(); + printMap(sensor, values); + + std::cout << "Read a single light value for light0..." << std::endl; + std::cout << "Single value = " << sensor.LightForSource("light0") << std::endl << std::endl; + + try + { + std::cout << "Read a single light value for lightX (doesn't exist)..." << std::endl; + sensor.LightForSource("lightX"); + } + catch (const std::exception& e) { std::cout << e.what() << std::endl << std::endl;} + + std::cout << "Read a light value for lightX (doesn't exist)..." << std::endl; + values = sensor.LightForSources(std::vector({"lightX"})); + printMap(sensor, values); + + std::cout << "Read all values as JsonDefinition..." << std::endl << sensor.JsonValues() << std::endl; + + return 0; +} diff --git a/examples/c++/servo-es08a.cxx b/examples/c++/servo-es08a.cxx index 6790759f..6766e5bb 100644 --- a/examples/c++/servo-es08a.cxx +++ b/examples/c++/servo-es08a.cxx @@ -31,7 +31,7 @@ int main(int argc, char** argv) { //! [Interesting] - upm::ES08A servo(5); + upm::ES08A servo("p:5"); // Sets the shaft to 180, then to 90, then to 0, // then back to 90, and finally back to 180, diff --git a/examples/c++/t6713-co2-sensor.cxx b/examples/c++/t6713-co2-sensor.cxx index 444c66ef..a5d0f60f 100644 --- a/examples/c++/t6713-co2-sensor.cxx +++ b/examples/c++/t6713-co2-sensor.cxx @@ -42,18 +42,18 @@ main() /* Create an instance of the T6713 sensor */ upm::T6713 sensor(EDISON_I2C_BUS); - /* Show usage from the ICO2Sensor interface */ - upm::ICO2Sensor* cO2Sensor = static_cast(&sensor); + /* Show usage from the iCO2Sensor interface */ + upm::iCO2Sensor* cO2Sensor = static_cast(&sensor); if (cO2Sensor == NULL) { std::cout << "CO2 sensor not detected" << std::endl; return 1; } - std::cout << "CO2 sensor " << cO2Sensor->getModuleName() << " detected" << std::endl; + std::cout << "CO2 sensor " << cO2Sensor->Name() << " detected" << std::endl; while (true) { try { - uint16_t value = cO2Sensor->getPpm(); - std::cout << "CO2 level = " << value << " ppm" << std::endl; + uint16_t value = cO2Sensor->CO2ForSource(cO2Sensor->Sources()[0]); + std::cout << "CO2 level = " << value << cO2Sensor->Units()[0] << std::endl; } catch (std::exception& e) { std::cerr << e.what() << std::endl; } diff --git a/examples/java/BME280_Interface_Example.java b/examples/java/BME280_Interface_Example.java index e3940d2a..10186bde 100644 --- a/examples/java/BME280_Interface_Example.java +++ b/examples/java/BME280_Interface_Example.java @@ -24,7 +24,7 @@ */ import upm_bmp280.*; -import upm_interfaces.*; +import upm_core.*; public class BME280_Interface_Example { @@ -35,9 +35,9 @@ public class BME280_Interface_Example // Instantiate a BME280 instance using default i2c bus and address BME280 sensor = new BME280(); - ITemperatureSensor t_sensor = sensor; - IHumiditySensor h_sensor = sensor; - IPressureSensor p_sensor = sensor; + iTemperatureSensor t_sensor = sensor; + iHumiditySensor h_sensor = sensor; + iPressureSensor p_sensor = sensor; // For SPI, bus 0, you would pass -1 as the address, and a // valid pin for CS: @@ -51,15 +51,15 @@ public class BME280_Interface_Example System.out.println("Calling Interface Functions: "); System.out.println("Compensation Temperature: " - + t_sensor.getTemperatureCelsius() + + t_sensor.TemperatureForSource("temperature") + " C / "); System.out.println("Pressure: " - + p_sensor.getPressurePa() + + p_sensor.PressureForSource("pressure") + " Pa"); System.out.println("Humidity: " - + h_sensor.getHumidityRelative() + + h_sensor.HumidityForSource("humidity") + " %RH"); System.out.println(); diff --git a/examples/java/CMakeLists.txt b/examples/java/CMakeLists.txt index ed246b5e..258741d3 100644 --- a/examples/java/CMakeLists.txt +++ b/examples/java/CMakeLists.txt @@ -24,9 +24,9 @@ include(UseJava) # add_example(SensorFooExample sensorfoo) # # # Creates SensorFooExample JAVA target, depends on targets: sensorfoo, -# # and interfaces and will add both upm_sensorfoo.jar and upm_interfaces.jar +# # and core and will add both upm_sensorfoo.jar and upm_core.jar # # to the javac classpath. -# add_example(SensorFooExample "sensorfoo;interfaces"") +# add_example(SensorFooExample "sensorfoo;core"") # function(add_example example_class_name dependency_list) set(example_file "${example_class_name}.java") @@ -68,7 +68,7 @@ add_example(A110X_Example a110x) add_example(A110X_intr_Example a110x) add_example(Ad8232_Example ad8232) add_example(ADC121C021_Example adc121c021) -add_example(Ads1015_Example "ads1x15;interfaces") +add_example(Ads1015_Example "ads1x15;core") add_example(Ads1115_Example ads1x15) add_example(Adxl345_Example adxl345) add_example(AM2315_Example am2315) @@ -78,13 +78,13 @@ add_example(BH1750_Example bh1750) add_example(BISS0001_Example biss0001) add_example(BMA250E_Example bma250e) add_example(BMC150_Example bmx055) -add_example(BME280_Example "bmp280;interfaces") +add_example(BME280_Example "bmp280;core") add_example(BMG160_Example bmg160) add_example(BMI055_Example bmx055) add_example(BMI160_Example bmi160) add_example(BMM150_Example bmm150) -add_example(BMP280_Example "bmp280;interfaces") -add_example(BMPX8X_Example "bmpx8x;interfaces") +add_example(BMP280_Example "bmp280;core") +add_example(BMPX8X_Example "bmpx8x;core") add_example(BMX055_Example bmx055) add_example(BNO055_Example bno055) add_example(Button_Example button) @@ -101,7 +101,7 @@ add_example(ECS1030_Example ecs1030) add_example(EHR_Example ehr) add_example(Emg_Example emg) add_example(ENC03R_Example enc03r) -add_example(ES08A_Example "servo;interfaces") +add_example(ES08A_Example "servo;core") add_example(FlexSensor_Example flex) add_example(Gp2y0a_Example gp2y0a) add_example(GroveButton_Example grove) @@ -229,9 +229,9 @@ add_example(YG1006_Example yg1006) add_example(ZFM20_Example zfm20) if(SWIG_VERSION VERSION_GREATER 3.0.8) - add_example(BME280_Interface_Example "bmp280;interfaces") - add_example(IMS_Example "ims;interfaces") - add_example(RHUSB_Example "rhusb;interfaces") + add_example(BME280_Interface_Example "bmp280;core") + add_example(IMS_Example "ims;core") + add_example(RHUSB_Example "rhusb;core") endif() if (OPENZWAVE_FOUND) diff --git a/examples/java/ES08A_Example.java b/examples/java/ES08A_Example.java index 01db78c9..6c7b2b33 100644 --- a/examples/java/ES08A_Example.java +++ b/examples/java/ES08A_Example.java @@ -50,4 +50,4 @@ public class ES08A_Example { System.out.println("Set angle to 180"); // ! [Interesting] } -} \ No newline at end of file +} diff --git a/examples/java/IMS_Example.java b/examples/java/IMS_Example.java index 8b9ef002..0c29b781 100644 --- a/examples/java/IMS_Example.java +++ b/examples/java/IMS_Example.java @@ -22,8 +22,6 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import upm_ims.IMS; - public class IMS_Example { public static void main(String[] args) throws InterruptedException @@ -31,18 +29,18 @@ public class IMS_Example // ! [Interesting] // Instantiate a IMS instance using bus 0 and default i2c address - IMS sensor = new IMS((short)0); + upm_ims.IMS sensor = new upm_ims.IMS((short)0); while (true) { System.out.println("Version: " - + sensor.get_version() + + upm_ims.javaupm_ims.LibraryVersion() + " light: " - + sensor.get_light() + + sensor.LightForSource("light") + " moisture: " - + sensor.get_moisture() + + sensor.MoistureForSource("moisture") + " temp: " - + sensor.get_temperature() + + sensor.TemperatureForSource("temperature") + " C"); Thread.sleep(1000); diff --git a/examples/java/NoelsTempLightReaderSample.java b/examples/java/NoelsTempLightReaderSample.java new file mode 100644 index 00000000..dd152a96 --- /dev/null +++ b/examples/java/NoelsTempLightReaderSample.java @@ -0,0 +1,42 @@ +/* + * The MIT License (MIT) + * + * Author: Your Full Name + * Copyright (c) + * + * 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_noelstemplightreader.*; + +public class NoelsTempLightReaderSample { + public static void main (String args[]) throws InterruptedException { + //! [Interesting] + // Instantiate new sensor instance + upm_noelstemplightreader.NoelsTempLightReader sensor = new upm_noelstemplightreader.NoelsTempLightReader(); + + while (true) { + + //System.out.println("NoelsTempLightReader says: " + sensor.Name()); + + // Repeate every 2 seconds + Thread.sleep(2000); + } + //! [Interesting] + } +} diff --git a/examples/java/RHUSB_Example.java b/examples/java/RHUSB_Example.java index 2d7add07..02a00e76 100644 --- a/examples/java/RHUSB_Example.java +++ b/examples/java/RHUSB_Example.java @@ -39,6 +39,12 @@ public class RHUSB_Example { // Instantiate an RHUSB instance on defaultDev upm_rhusb.RHUSB sensor = new upm_rhusb.RHUSB(defaultDev); + // Print out info from the sensor core + System.out.println("UPM Version:" + System.lineSeparator() + + upm_rhusb.javaupm_rhusb.LibraryVersion() + System.lineSeparator()); + System.out.println("JSON Definition:" + System.lineSeparator() + + sensor.JsonDefinition() + System.lineSeparator()); + // output the firmware ID System.out.println("Firmware ID: " + sensor.getFirmwareID()); diff --git a/examples/javascript/noelstemplightreader.js b/examples/javascript/noelstemplightreader.js new file mode 100644 index 00000000..218342be --- /dev/null +++ b/examples/javascript/noelstemplightreader.js @@ -0,0 +1,40 @@ +/* + * The MIT License (MIT) + * + * Author: Your Full Name + * Copyright (c) + * + * 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 jsupm_noelstemplightreader = require('jsupm_noelstemplightreader'); + +// Create an instance of the sensor +var sensor = new upm_noelstemplightreader.NoelsTempLightReader(0); + +loop(); + +function loop() +{ + // Call a method from the noelstemplightreader + console.log("NoelsTempLightReader says: " + sensor.helloWorld()); + + // Call loop every 2 seconds + setTimeout(loop, 2000); +} diff --git a/examples/python/noelstemplightreader.py b/examples/python/noelstemplightreader.py new file mode 100755 index 00000000..2207a3cd --- /dev/null +++ b/examples/python/noelstemplightreader.py @@ -0,0 +1,39 @@ +# The MIT License (MIT) +# +# Author: Your Full Name +# Copyright (c) +# +# 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. + + +from __future__ import print_function +import time +from upm import pyupm_noelstemplightreader + +def main(): + # Create an instance of NoelsTempLightReader + sensor = pyupm_noelstemplightreader.NoelsTempLightReader(0) + + while True: + print("NoelsTempLightReader says: %s" % sensor.helloWorld) + + # Repeat every 2 seconds + sleep(2) + +if __name__ == '__main__': + main() diff --git a/scripts/build-android.sh b/scripts/build-android.sh index 85358dd1..5ee93830 100755 --- a/scripts/build-android.sh +++ b/scripts/build-android.sh @@ -68,7 +68,7 @@ make -j8 -Cbuild # Anotate the .java src from doxygen find src/ -name "*.i" > build/upm.i.list #../doxy/doxyport build/upm.i.list \ -# -s src/interfaces/,src/bacnetmstp,src/bmg160,src/bma250e,src/bmm150 \ +# -s src/core/,src/bacnetmstp,src/bmg160,src/bma250e,src/bmm150 \ # -m doxy/samples.mapping.txt \ # -d build/src/ \ # --convert-protected-to-private \ diff --git a/scripts/build-doc.sh b/scripts/build-doc.sh index 26ad679b..241f6c8e 100755 --- a/scripts/build-doc.sh +++ b/scripts/build-doc.sh @@ -25,7 +25,7 @@ cd ${ROOT_DIR} && make -j8 -Cbuild 2> ${BUILD_LOGS_DIR}/build-doc.log cd ${BUILD_DIR} && find ../src/ -name "*.i" > upm.i.list && \ ../doxy/doxyport/doxyport upm.i.list \ --cmake ./compile_commands.json \ - --source ../src/interfaces/,../src/bacnetmstp,src \ + --source ../src/core/,../src/bacnetmstp,src \ --destination src/ \ --convert-protected-to-private \ --output upm-java-files.txt \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 030218a3..15074ec9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,7 +7,8 @@ set (SWIG_CXX_DISABLE_WARNINGS -Wno-error -Wno-delete-non-virtual-dtor -Wno-unused-function -Wno-maybe-uninitialized - -Wno-strict-aliasing) + -Wno-strict-aliasing + -Wno-unused-but-set-variable) # If building under android, make sure swig gets an ANDROID flag if (ANDROID) @@ -514,13 +515,13 @@ function(upm_swig_java) swig_add_library (javaupm_${libname} LANGUAGE java SOURCES ${SWIG_CURRENT_DOT_I_FILE}) endif () - # If the C++ target depends on C++ interfaces, make the JAVA target - # depend on the JAVA interfaces - if ("${_c_cxx_dependency_list}" MATCHES interfaces) - add_dependencies(javaupm_${libname} javaupm_interfaces) - # If this target depends on interfaces, include the java interfaces + # If the C++ target depends on C++ core, make the JAVA target + # depend on the JAVA core + if ("${_c_cxx_dependency_list}" MATCHES core) + add_dependencies(javaupm_${libname} javaupm_core) + # If this target depends on core, include the java core # target .jar file in the classpath, otherwise this variable will be empty - set (INTERFACES_JAR_FILE ${CMAKE_BINARY_DIR}/src/interfaces/upm_interfaces.jar) + set (INTERFACES_JAR_FILE ${CMAKE_BINARY_DIR}/src/core/upm_core.jar) endif () # For linker to report unresolved symbols. Note, there is currently no test # for linker flags (similar to compile files), so this is it for now. @@ -564,10 +565,10 @@ function(upm_swig_java) set (JAR $ENV{JAVA_HOME_NATIVE}/bin/jar) endif () - # Only include the upm_interfaces.jar in the classpath for targets which - # depend on the interfaces target. This fixes an issue where javac - # complains about an empty upm_interfaces.jar when trying to build a target - # which does not depend on javaupm_interfaces. If not previously set, + # Only include the upm_core.jar in the classpath for targets which + # depend on the core target. This fixes an issue where javac + # complains about an empty upm_core.jar when trying to build a target + # which does not depend on javaupm_core. If not previously set, # INTERFACES_JAR_FILE will be empty, and javac *should* not complain. add_custom_command (TARGET javaupm_${libname} POST_BUILD @@ -632,12 +633,12 @@ if (BUILDSWIGNODE) file (COPY ${CMAKE_SOURCE_DIR}/include DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/jsupm_${libname}) set (upm_LIB_INCLUDE_DIRS_GYP "'.',\n${upm_LIB_INCLUDE_DIRS_GYP}") - # Utilities and interfaces + # Utilities and core file (COPY ${CMAKE_SOURCE_DIR}/src/utilities DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/jsupm_${libname}) - file (COPY ${CMAKE_SOURCE_DIR}/src/interfaces DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/jsupm_${libname}) + file (COPY ${CMAKE_SOURCE_DIR}/src/core DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/jsupm_${libname}) set (upm_LIB_SRCS_GYP "'utilities/upm_utilities.c',\n${upm_LIB_SRCS_GYP}") set (upm_LIB_INCLUDE_DIRS_GYP "'utilities',\n${upm_LIB_INCLUDE_DIRS_GYP}") - set (upm_LIB_INCLUDE_DIRS_GYP "'interfaces',\n${upm_LIB_INCLUDE_DIRS_GYP}") + set (upm_LIB_INCLUDE_DIRS_GYP "'core',\n${upm_LIB_INCLUDE_DIRS_GYP}") # Add readme, package.json for NPM and node-gyp config file configure_file (${PROJECT_SOURCE_DIR}/src/binding.gyp.in ${CMAKE_CURRENT_BINARY_DIR}/jsupm_${libname}/binding.gyp @ONLY) @@ -789,6 +790,22 @@ function(upm_module_init) # Create the target library from src/hdrs add_library (${libname} SHARED ${module_src} ${module_hpp}) + # Add a upm_library_globals to all C++ libraries + if (NOT IS_C_LIBRARY) + # Share some GLOBAL (per library) info with the library (UPM version and library base name) + target_compile_definitions(${libname} + PRIVATE -DUPM_LIBRARY_BASE_NAME=${libname} + -DUPM_VERSION_STRING=${upm_VERSION_STRING}) + + # Add a source file which contains the shared GLOBAL info + target_sources(${libname} + PRIVATE ${CMAKE_SOURCE_DIR}/src/upm_library_globals.cxx + ${CMAKE_SOURCE_DIR}/src/upm_library_globals.hpp) + + # This source depends on libdl (uses dladdr), make sure to link this + target_link_libraries (${libname} ${CMAKE_DL_LIBS}) + endif() + # Specify the current source directory as an INTERFACE include dir. # This allows for transitive header dependencies via target_link_libraries target_include_directories(${libname} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) @@ -855,8 +872,14 @@ function(upm_module_init) DESTINATION include/upm COMPONENT ${CMAKE_PROJECT_NAME}-dev) - # Install JSON library descriptor files into datadir (if they exist) + # Handle build/install for JSON library descriptor file if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${basename}.json") + # Copy JSON library descriptor file to binary directory (for testing/running from build dir) + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${basename}.json" + "${CMAKE_CURRENT_BINARY_DIR}/${basename}.json" + COPYONLY) + + # Install JSON library descriptor files into datadir (if they exist) install (FILES "${CMAKE_CURRENT_SOURCE_DIR}/${basename}.json" DESTINATION ${CMAKE_INSTALL_DATADIR}/upm/${basename} COMPONENT ${CMAKE_PROJECT_NAME}) @@ -908,10 +931,10 @@ if (NOT "${MODULE_LIST}" MATCHES ";utilities;") set(MODULE_LIST "utilities;${MODULE_LIST}") endif() -# If the module list does NOT include the interfaces directory, prepend it since -# some sensor library targets depend on interfaces -if (NOT "${MODULE_LIST}" MATCHES ";interfaces;") - set(MODULE_LIST "interfaces;${MODULE_LIST}") +# If the module list does NOT include the core directory, prepend it since +# some sensor library targets depend on core +if (NOT "${MODULE_LIST}" MATCHES ";core;") + set(MODULE_LIST "core;${MODULE_LIST}") endif() # Iterate over each directory in MODULE_LIST diff --git a/src/ads1x15/CMakeLists.txt b/src/ads1x15/CMakeLists.txt index cce80b43..e94feee0 100644 --- a/src/ads1x15/CMakeLists.txt +++ b/src/ads1x15/CMakeLists.txt @@ -2,7 +2,7 @@ set (libname "ads1x15") set (libdescription "Texas Instruments I2C ADC Library") set (module_src ${libname}.cxx ads1115.cxx ads1015.cxx) set (module_hpp ${libname}.hpp ads1115.hpp ads1015.hpp) -upm_module_init(interfaces mraa) +upm_module_init(core mraa) compiler_flag_supported(CXX is_supported -Wno-overloaded-virtual) if (is_supported) target_compile_options(${libname} PUBLIC -Wno-overloaded-virtual) diff --git a/src/ads1x15/ads1015.cxx b/src/ads1x15/ads1015.cxx index 40fefdae..e23c7587 100644 --- a/src/ads1x15/ads1015.cxx +++ b/src/ads1x15/ads1015.cxx @@ -40,7 +40,7 @@ ADS1015::ADS1015(int bus, uint8_t address, float vref) : ADS1X15(bus, address) { m_bitShift = 4; ADS1X15::getCurrentConfig(); if (vref < 0.0 || vref > 6.144) - UPM_THROW("vref out of range"); + throw std::runtime_error(std::string(__FUNCTION__) + " : vref out of range"); else if (vref > 4.096) setGain(GAIN_TWOTHIRDS); else if (vref > 2.048) @@ -57,12 +57,6 @@ ADS1015::ADS1015(int bus, uint8_t address, float vref) : ADS1X15(bus, address) { ADS1015::~ADS1015(){}; -const char* -ADS1015::getModuleName() { - return m_name.c_str(); -} - - unsigned int ADS1015::getNumInputs() { return 4; @@ -73,7 +67,7 @@ ADS1015::getResolutionInBits() { return 12; } -uint16_t +unsigned int ADS1015::getRawValue(unsigned int input) { ADS1X15::ADSMUXMODE mode = getMuxMode(input); updateConfigRegister((m_config_reg & ~ADS1X15_MUX_MASK) | mode, true); @@ -163,7 +157,7 @@ ADS1015::getMuxMode(unsigned int input) { case 3: return SINGLE_3; default: - UPM_THROW("Invalid input"); + throw std::runtime_error(std::string(__FUNCTION__) + " : Invalid input"); } } diff --git a/src/ads1x15/ads1015.hpp b/src/ads1x15/ads1015.hpp index 3b7cbe00..637a845a 100644 --- a/src/ads1x15/ads1015.hpp +++ b/src/ads1x15/ads1015.hpp @@ -26,7 +26,7 @@ #pragma once #include "ads1x15.hpp" -#include "interfaces/iADC.hpp" +#include "iADC.hpp" #define ADS1015_VREF 2.048 @@ -54,63 +54,63 @@ /*=========================================================================*/ namespace upm { - /** - * @library ads1x15 - * @sensor ADS1015 - * @comname 12-bit ADC with Integrated MUX, PGA, Comparator, Oscillator, and Reference - * @type electric - * @man ti adafruit - * @con i2c - * @web http://www.ti.com/lit/ds/symlink/ads1015.pdf - * - * @brief API for ADS1015 - * - * The ADS1013, ADS1014, and ADS1015 are precision analog-to-digital converters (ADCs) with 12 bits of resolution - * offered in an ultra-small, leadless QFN-10 package or an MSOP-10 package. The ADS1013/4/5 are designed with - * precision, power, and ease of implementation in mind. The ADS1013/4/5 feature an onboard reference and oscillator. - * Data is transferred via an I2C-compatible serial interface; four I2C slave addresses can be selected. The ADS1013/4/5 - * operate from a single power supply ranging from 2.0V to 5.5V. - * The ADS1013/4/5 can perform conversions at rates up to 3300 samples per second (SPS). An onboard PGA is available - * on the ADS1014 and ADS1015 that offers input ranges from the supply to as low as +/- 256mV, allowing both large and small - * signals to be measured with high resolution. The ADS1015 also features an input multiplexer (MUX) that provides two - * differential or four single-ended inputs. - * The ADS1013/4/5 operate either in continuous conversion mode or a single-shot mode that automatically powers down - * after a conversion and greatly reduces current consumption during idle periods. The ADS1013/4/5 are specified from - * -40 deg C to +125 deg C. - * - * Tested with Adafriut ADS1015 board: https://www.adafruit.com/products/1083 - * - * @image html ads1015.jpg - * @snippet ads1x15.cxx Interesting - * @snippet ads1x15-ads1015.cxx Interesting - * @snippet ads1x15-adc-sensor.cxx Interesting - */ - class ADS1015 : public ADS1X15, public IADC { + /** + * @library ads1x15 + * @sensor ADS1015 + * @comname 12-bit ADC with Integrated MUX, PGA, Comparator, Oscillator, and Reference + * @type electric + * @man ti adafruit + * @con i2c + * @web http://www.ti.com/lit/ds/symlink/ads1015.pdf + * + * @brief API for ADS1015 + * + * The ADS1013, ADS1014, and ADS1015 are precision analog-to-digital converters (ADCs) with 12 bits of resolution + * offered in an ultra-small, leadless QFN-10 package or an MSOP-10 package. The ADS1013/4/5 are designed with + * precision, power, and ease of implementation in mind. The ADS1013/4/5 feature an onboard reference and oscillator. + * Data is transferred via an I2C-compatible serial interface; four I2C slave addresses can be selected. The ADS1013/4/5 + * operate from a single power supply ranging from 2.0V to 5.5V. + * The ADS1013/4/5 can perform conversions at rates up to 3300 samples per second (SPS). An onboard PGA is available + * on the ADS1014 and ADS1015 that offers input ranges from the supply to as low as +/- 256mV, allowing both large and small + * signals to be measured with high resolution. The ADS1015 also features an input multiplexer (MUX) that provides two + * differential or four single-ended inputs. + * The ADS1013/4/5 operate either in continuous conversion mode or a single-shot mode that automatically powers down + * after a conversion and greatly reduces current consumption during idle periods. The ADS1013/4/5 are specified from + * -40 deg C to +125 deg C. + * + * Tested with Adafriut ADS1015 board: https://www.adafruit.com/products/1083 + * + * @image html ads1015.jpg + * @snippet ads1x15.cxx Interesting + * @snippet ads1x15-ads1015.cxx Interesting + * @snippet ads1x15-adc-sensor.cxx Interesting + */ + class ADS1015 : public ADS1X15, public iADC { public: - /** - * @enum ADSSAMPLERATE - * @brief uint16_t enum containing values - * representing the sample rate of the device. - * - * @var ADSSAMPLERATE::SPS_128 = 0x0000 - * @var ADSSAMPLERATE::SPS_250 = 0x0020 - * @var ADSSAMPLERATE::SPS_490 = 0x0040 - * @var ADSSAMPLERATE::SPS_920 = 0x0060 - * @var ADSSAMPLERATE::SPS_1600 = 0x0080 - * @var ADSSAMPLERATE::SPS_2400 = 0x00A0 - * @var ADSSAMPLERATE::SPS_3300 = 0x00C0 - */ - typedef enum ADSSAMPLERATE { - SPS_128 = ADS1015_DR_128SPS, - SPS_250 = ADS1015_DR_250SPS, - SPS_490 = ADS1015_DR_490SPS, - SPS_920 = ADS1015_DR_920SPS, - SPS_1600 = ADS1015_DR_1600SPS, - SPS_2400 = ADS1015_DR_2400SPS, - SPS_3300 = ADS1015_DR_3300SPS - } ADSSAMPLERATE; + /** + * @enum ADSSAMPLERATE + * @brief uint16_t enum containing values + * representing the sample rate of the device. + * + * @var ADSSAMPLERATE::SPS_128 = 0x0000 + * @var ADSSAMPLERATE::SPS_250 = 0x0020 + * @var ADSSAMPLERATE::SPS_490 = 0x0040 + * @var ADSSAMPLERATE::SPS_920 = 0x0060 + * @var ADSSAMPLERATE::SPS_1600 = 0x0080 + * @var ADSSAMPLERATE::SPS_2400 = 0x00A0 + * @var ADSSAMPLERATE::SPS_3300 = 0x00C0 + */ + typedef enum ADSSAMPLERATE { + SPS_128 = ADS1015_DR_128SPS, + SPS_250 = ADS1015_DR_250SPS, + SPS_490 = ADS1015_DR_490SPS, + SPS_920 = ADS1015_DR_920SPS, + SPS_1600 = ADS1015_DR_1600SPS, + SPS_2400 = ADS1015_DR_2400SPS, + SPS_3300 = ADS1015_DR_3300SPS + } ADSSAMPLERATE; /** @@ -130,6 +130,9 @@ namespace upm { */ ~ADS1015 (); + virtual std::string Name() {return "ADS1015";} + virtual std::string Description() {return "12-bit ADC with integrated MUX, PGA, comparator, oscillator, and reference";} + /** * Sets the sample rate of the device. This function * needs to be overridden in subclasses as the ADS1115 and @@ -151,7 +154,7 @@ namespace upm { * * @return current conversion value */ - uint16_t getRawValue(unsigned int input); + unsigned int getRawValue(unsigned int input); /** * Read current voltage for current single ended analogue input @@ -167,14 +170,6 @@ namespace upm { */ unsigned int getResolutionInBits(); - /** - * Returns module name - * - * @return modulename as const char* - */ - const char* getModuleName(); - - protected: float getMultiplier(void); void setDelay(void); diff --git a/src/ads1x15/ads1x15.i b/src/ads1x15/ads1x15.i index e3252da9..48831f14 100644 --- a/src/ads1x15/ads1x15.i +++ b/src/ads1x15/ads1x15.i @@ -1,28 +1,12 @@ %include "../common_top.i" +%include "iADC.i" /* BEGIN Java syntax ------------------------------------------------------- */ #ifdef SWIGJAVA -%import "../interfaces/javaupm_iADC.i" -%typemap(javaimports) SWIGTYPE %{import upm_interfaces.*;%} - JAVA_JNI_LOADLIBRARY(javaupm_ads1x15) #endif /* END Java syntax */ -/* BEGIN Javascript syntax ------------------------------------------------- */ -#ifdef SWIGJAVASCRIPT -%include "iModuleStatus.hpp" -%include "iADC.hpp" -#endif -/* END Javascript syntax */ - -/* BEGIN Python syntax ----------------------------------------------------- */ -#ifdef SWIGPYTHON -%include "iModuleStatus.hpp" -%include "iADC.hpp" -#endif -/* END Python syntax */ - /* BEGIN Common SWIG syntax ------------------------------------------------- */ %{ #include "ads1x15.hpp" diff --git a/src/bmp280/CMakeLists.txt b/src/bmp280/CMakeLists.txt index 4864a80e..d805e19d 100644 --- a/src/bmp280/CMakeLists.txt +++ b/src/bmp280/CMakeLists.txt @@ -5,5 +5,5 @@ upm_mixed_module_init (NAME bmp280 CPP_HDR bmp280.hpp bme280.hpp CPP_SRC bmp280.cxx bme280.cxx CPP_WRAPS_C - REQUIRES mraa interfaces utilities-c) + REQUIRES mraa core utilities-c) target_link_libraries(${libnamec} m) diff --git a/src/bmp280/bme280.cxx b/src/bmp280/bme280.cxx index 7936cc7d..caf86246 100644 --- a/src/bmp280/bme280.cxx +++ b/src/bmp280/bme280.cxx @@ -54,3 +54,17 @@ void BME280::setOversampleRateHumidity(BME280_OSRS_H_T rate) { bmp280_set_oversample_rate_humidity(m_bmp280, rate); } + +std::map BME280::HumidityForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "humidity") != sources.end()) + { + update(); + ret["humidity"] = getHumidity(); + } + + return ret; +} + diff --git a/src/bmp280/bme280.hpp b/src/bmp280/bme280.hpp index fd03992e..6220e5bb 100644 --- a/src/bmp280/bme280.hpp +++ b/src/bmp280/bme280.hpp @@ -26,7 +26,7 @@ #pragma once #include -#include "interfaces/iHumiditySensor.hpp" +#include "iHumiditySensor.hpp" #include "bmp280.hpp" @@ -57,7 +57,7 @@ namespace upm { * @snippet bmp280-bme280.cxx Interesting */ - class BME280 : public BMP280, public IHumiditySensor { + class BME280 : public virtual BMP280, public virtual iHumiditySensor { public: /** @@ -88,6 +88,12 @@ namespace upm { */ virtual ~BME280(); + virtual std::string Name () {return "BME280";} + virtual std::string Description () {return "Digital absolute pressure sensor with humidity";} + + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map HumidityForSources(std::vector sources); + /** * Return the current measured relative humidity. update() * must have been called prior to calling this method. If the @@ -108,12 +114,6 @@ namespace upm { */ void setOversampleRateHumidity(BME280_OSRS_H_T rate); - // Interface support - const char *getModuleName() - { - return "BME280"; - }; - int getHumidityRelative() { return int(getHumidity()); diff --git a/src/bmp280/bmp280.cxx b/src/bmp280/bmp280.cxx index b9d338fc..4f469ee9 100644 --- a/src/bmp280/bmp280.cxx +++ b/src/bmp280/bmp280.cxx @@ -48,6 +48,8 @@ BMP280::BMP280(int bus, int addr, int cs) : if (!m_bmp280) throw std::runtime_error(string(__FUNCTION__) + ": bmp280_init() failed"); + AddSource("temperature", "C"); + AddSource("pressure", "Pa"); } BMP280::~BMP280() @@ -150,3 +152,29 @@ void BMP280::setUsageMode(BMP280_USAGE_MODE_T mode) bmp280_set_usage_mode(m_bmp280, mode); } +std::map BMP280::TemperatureForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "temperature") != sources.end()) + { + update(); + ret["temperature"] = getTemperature(false); + } + + return ret; +} + +std::map BMP280::PressureForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "pressure") != sources.end()) + { + update(); + ret["pressure"] = getPressure(); + } + + return ret; +} + diff --git a/src/bmp280/bmp280.hpp b/src/bmp280/bmp280.hpp index 18889681..5e415240 100644 --- a/src/bmp280/bmp280.hpp +++ b/src/bmp280/bmp280.hpp @@ -28,8 +28,8 @@ #include #include "bmp280.h" -#include "interfaces/iPressureSensor.hpp" -#include "interfaces/iTemperatureSensor.hpp" +#include "iPressureSensor.hpp" +#include "iTemperatureSensor.hpp" namespace upm { @@ -67,7 +67,7 @@ namespace upm { * @snippet bmp280.cxx Interesting */ - class BMP280 : public ITemperatureSensor, public IPressureSensor { + class BMP280 : public virtual iTemperatureSensor, public virtual iPressureSensor { public: /** @@ -93,6 +93,16 @@ namespace upm { BMP280(int bus=BMP280_DEFAULT_I2C_BUS, int addr=BMP280_DEFAULT_ADDR, int cs=-1); + virtual std::string Name () {return "BMP280";} + + virtual std::string Description () {return "Digital absolute pressure sensor";} + + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map TemperatureForSources(std::vector sources); + + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map PressureForSources(std::vector sources); + /** * BMP280 Destructor. */ @@ -217,12 +227,6 @@ namespace upm { void setMeasureMode(BMP280_MODES_T mode); - // Interface support - const char *getModuleName() - { - return "BMP280"; - }; - int getTemperatureCelsius() { return int(getTemperature(false)); diff --git a/src/bmp280/bmp280.i b/src/bmp280/bmp280.i index ebd316ab..c25b6267 100644 --- a/src/bmp280/bmp280.i +++ b/src/bmp280/bmp280.i @@ -1,40 +1,17 @@ %include "../common_top.i" +%include "iHumiditySensor.i" +%include "iTemperatureSensor.i" +%include "iPressureSensor.i" /* BEGIN Java syntax ------------------------------------------------------- */ #ifdef SWIGJAVA -%import "../interfaces/javaupm_iTemperatureSensor.i" -%import "../interfaces/javaupm_iHumiditySensor.i" -%import "../interfaces/javaupm_iPressureSensor.i" - %include "arrays_java.i"; %include "../java_buffer.i" -%typemap(javaimports) SWIGTYPE %{ - import upm_interfaces.*; -%} - JAVA_JNI_LOADLIBRARY(javaupm_bmp280) #endif /* END Java syntax */ -/* BEGIN Javascript syntax ------------------------------------------------- */ -#ifdef SWIGJAVASCRIPT -%include "iModuleStatus.hpp" -%include "iTemperatureSensor.hpp" -%include "iPressureSensor.hpp" -%include "iHumiditySensor.hpp" -#endif -/* END Javascript syntax */ - -/* BEGIN Python syntax ----------------------------------------------------- */ -#ifdef SWIGPYTHON -%include "iModuleStatus.hpp" -%include "iTemperatureSensor.hpp" -%include "iPressureSensor.hpp" -%include "iHumiditySensor.hpp" -#endif -/* END Python syntax */ - /* BEGIN Common SWIG syntax ------------------------------------------------- */ %{ #include "bmp280_regs.h" diff --git a/src/bmpx8x/CMakeLists.txt b/src/bmpx8x/CMakeLists.txt index ea363518..3a762fb7 100644 --- a/src/bmpx8x/CMakeLists.txt +++ b/src/bmpx8x/CMakeLists.txt @@ -6,5 +6,5 @@ upm_mixed_module_init (NAME bmpx8x CPP_SRC bmpx8x.cxx FTI_SRC bmpx8x_fti.c CPP_WRAPS_C - REQUIRES mraa interfaces utilities-c) + REQUIRES mraa core utilities-c) target_link_libraries(${libnamec} m) diff --git a/src/bmpx8x/bmpx8x.cxx b/src/bmpx8x/bmpx8x.cxx index 36144907..7b671793 100644 --- a/src/bmpx8x/bmpx8x.cxx +++ b/src/bmpx8x/bmpx8x.cxx @@ -44,6 +44,9 @@ BMPX8X::BMPX8X (int bus, int addr) : if (!m_bmpx8x) throw std::runtime_error(string(__FUNCTION__) + ": bmpx8x_init() failed"); + + AddSource("temperature", "C"); + AddSource("pressure", "Pa"); } BMPX8X::~BMPX8X() @@ -118,3 +121,24 @@ float BMPX8X::getAltitude(int sealevelPressure) { return bmpx8x_get_altitude(m_bmpx8x, sealevelPressure); } + +std::map BMPX8X::TemperatureForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "temperature") != sources.end()) + ret["temperature"] = getTemperatureCelsius(); + + return ret; +} + +std::map BMPX8X::PressureForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "pressure") != sources.end()) + ret["pressure"] = getPressurePa(); + + return ret; +} + diff --git a/src/bmpx8x/bmpx8x.hpp b/src/bmpx8x/bmpx8x.hpp index 680c2b57..d00250dd 100644 --- a/src/bmpx8x/bmpx8x.hpp +++ b/src/bmpx8x/bmpx8x.hpp @@ -32,8 +32,8 @@ #include "bmpx8x.h" -#include "interfaces/iPressureSensor.hpp" -#include "interfaces/iTemperatureSensor.hpp" +#include "iPressureSensor.hpp" +#include "iTemperatureSensor.hpp" namespace upm { @@ -68,7 +68,7 @@ namespace upm { * @snippet bmpx8x.cxx Interesting */ - class BMPX8X : public IPressureSensor, public ITemperatureSensor { + class BMPX8X : public iPressureSensor, public iTemperatureSensor { public: /** * Instantiates a BMPX8X object @@ -85,6 +85,18 @@ namespace upm { */ virtual ~BMPX8X(); + /** Return the name of this device */ + virtual std::string Name () {return "BMPX8X";} + + /** Return the description of this device */ + virtual std::string Description () {return "Atmospheric pressure sensor";} + + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map TemperatureForSources(std::vector sources); + + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map PressureForSources(std::vector sources); + /** * Query the device and update the internal state. This * method must be called before calling getPressure(), @@ -178,7 +190,7 @@ namespace upm { /** * Return latest calculated temperature value in Celsius. See - * ITemperatureSensor. + * iTemperatureSensor. * * @return The current temperature in Celsius. */ @@ -190,7 +202,7 @@ namespace upm { /** * Return latest calculated pressure value in Pascals. See - * IPressureSensor. + * iPressureSensor. * * @return The current pressure in Pascals. */ @@ -200,16 +212,6 @@ namespace upm { return getPressure(); } - /** - * Returns the name of module. - * - * @return The name of the module. - */ - const char *getModuleName() - { - return "BMPX8X"; - } - protected: // our underlying C context. bmpx8x_context m_bmpx8x; diff --git a/src/bmpx8x/bmpx8x.i b/src/bmpx8x/bmpx8x.i index 08465a5d..ed0917ab 100644 --- a/src/bmpx8x/bmpx8x.i +++ b/src/bmpx8x/bmpx8x.i @@ -1,23 +1,13 @@ %include "../common_top.i" +%include "iPressureSensor.i" +%include "iTemperatureSensor.i" /* BEGIN Java syntax ------------------------------------------------------- */ #ifdef SWIGJAVA -%import "../interfaces/javaupm_iPressureSensor.i" -%typemap(javaimports) SWIGTYPE %{import upm_interfaces.*;%} -%import "../interfaces/javaupm_iTemperatureSensor.i" - JAVA_JNI_LOADLIBRARY(javaupm_bmpx8x) #endif /* END Java syntax */ -/* BEGIN Python syntax ----------------------------------------------------- */ -#ifdef SWIGPYTHON -%include "iModuleStatus.hpp" -%include "iTemperatureSensor.hpp" -%include "iPressureSensor.hpp" -#endif -/* END Python syntax */ - /* BEGIN Common SWIG syntax ------------------------------------------------- */ %{ #include "bmpx8x_defs.h" diff --git a/src/common_top.i b/src/common_top.i index c9edb585..484dc7c7 100644 --- a/src/common_top.i +++ b/src/common_top.i @@ -2,15 +2,14 @@ %include "cpointer.i" %include "stdint.i" %include "typemaps.i" + +#if SWIGJAVA +%include "java_exceptions.i" +#else %include "upm_exception.i" +#endif -/* Import additional SWIG helps (not exposed in wrapper) */ -%import _upm.i - -%{ -#include "version.hpp" -%} -%include "version.hpp" +%import "_upm.i" %apply int { speed_t }; %apply int { mraa_result_t }; @@ -35,7 +34,6 @@ void cleanUp() {;} } %} -void cleanUp(); #endif #if (SWIGJAVA) @@ -43,7 +41,7 @@ void cleanUp(); %typemap(jstype) jobject runnable "java.lang.Runnable" #endif -// Disable nested struct warnings +/* Disable nested struct warnings */ #pragma SWIG nowarn=312,325 #if SWIGPYTHON diff --git a/src/core/.core.i b/src/core/.core.i new file mode 100644 index 00000000..1ac354cd --- /dev/null +++ b/src/core/.core.i @@ -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" diff --git a/src/core/.iADC.i b/src/core/.iADC.i new file mode 100644 index 00000000..c1122563 --- /dev/null +++ b/src/core/.iADC.i @@ -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" diff --git a/src/core/.iActuatorType.i b/src/core/.iActuatorType.i new file mode 100644 index 00000000..28925303 --- /dev/null +++ b/src/core/.iActuatorType.i @@ -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" diff --git a/src/core/.iCO2Sensor.i b/src/core/.iCO2Sensor.i new file mode 100644 index 00000000..818e0e57 --- /dev/null +++ b/src/core/.iCO2Sensor.i @@ -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" diff --git a/src/core/.iHumiditySensor.i b/src/core/.iHumiditySensor.i new file mode 100644 index 00000000..fb0006ad --- /dev/null +++ b/src/core/.iHumiditySensor.i @@ -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 diff --git a/src/core/.iLightController.i b/src/core/.iLightController.i new file mode 100644 index 00000000..58dbc2ba --- /dev/null +++ b/src/core/.iLightController.i @@ -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" diff --git a/src/core/.iLightSensor.i b/src/core/.iLightSensor.i new file mode 100644 index 00000000..a695d846 --- /dev/null +++ b/src/core/.iLightSensor.i @@ -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" diff --git a/src/core/.iMoistureSensor.i b/src/core/.iMoistureSensor.i new file mode 100644 index 00000000..6b3fecba --- /dev/null +++ b/src/core/.iMoistureSensor.i @@ -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" diff --git a/src/core/.iMraa.i b/src/core/.iMraa.i new file mode 100644 index 00000000..035bc653 --- /dev/null +++ b/src/core/.iMraa.i @@ -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 vec_aio; +%template(vec_aio) std::vector; + +typedef std::vector vec_gpio; +%template(vec_gpio) std::vector; + +typedef std::vector vec_i2c; +%template(vec_i2c) std::vector; + +typedef std::vector vec_iio; +%template(vec_iio) std::vector; + +typedef std::vector vec_pwm; +%template(vec_pwm) std::vector; + +typedef std::vector vec_spi; +%template(vec_spi) std::vector; + +typedef std::vector vec_uart; +%template(vec_uart) std::vector; + +typedef std::vector vec_uartow; +%template(vec_uartow) std::vector; diff --git a/src/core/.iPressureSensor.i b/src/core/.iPressureSensor.i new file mode 100644 index 00000000..b4d2bb52 --- /dev/null +++ b/src/core/.iPressureSensor.i @@ -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" diff --git a/src/core/.iSensorType.i b/src/core/.iSensorType.i new file mode 100644 index 00000000..96816bd8 --- /dev/null +++ b/src/core/.iSensorType.i @@ -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" diff --git a/src/core/.iServoActuator.i b/src/core/.iServoActuator.i new file mode 100644 index 00000000..6d83a284 --- /dev/null +++ b/src/core/.iServoActuator.i @@ -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" diff --git a/src/core/.iTemperatureSensor.i b/src/core/.iTemperatureSensor.i new file mode 100644 index 00000000..4392c432 --- /dev/null +++ b/src/core/.iTemperatureSensor.i @@ -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 diff --git a/src/core/.iUpmObject.i b/src/core/.iUpmObject.i new file mode 100644 index 00000000..b9673d39 --- /dev/null +++ b/src/core/.iUpmObject.i @@ -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 vec_str; +%template(vec_str) std::vector; + +typedef std::map map_str_float; +%template(map_str_float) std::map; + +typedef std::map map_str_str; +%template(map_str_str) std::map; + +/* 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 diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt new file mode 100644 index 00000000..4c963e0e --- /dev/null +++ b/src/core/CMakeLists.txt @@ -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) diff --git a/src/core/core.i b/src/core/core.i new file mode 100644 index 00000000..191b03b6 --- /dev/null +++ b/src/core/core.i @@ -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" diff --git a/src/core/iADC.cxx b/src/core/iADC.cxx new file mode 100644 index 00000000..8beb188d --- /dev/null +++ b/src/core/iADC.cxx @@ -0,0 +1,3 @@ +#include "iADC.hpp" + +upm::iADC::~iADC () {} diff --git a/src/interfaces/iADC.hpp b/src/core/iADC.hpp similarity index 74% rename from src/interfaces/iADC.hpp rename to src/core/iADC.hpp index a852f17f..496b9611 100644 --- a/src/interfaces/iADC.hpp +++ b/src/core/iADC.hpp @@ -22,26 +22,24 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - #pragma once + #include -#include "iModuleStatus.hpp" + +#include "iSensorType.hpp" namespace upm { -/** - * @brief Interface for ADC Sensors - */ - - class IADC : virtual public IModuleStatus - { - public: - virtual unsigned int getResolutionInBits() = 0; - virtual unsigned int getNumInputs() = 0; - virtual uint16_t getRawValue(unsigned int input) = 0; - virtual float getVoltage(unsigned int input) = 0; - virtual ~IADC() {} - }; - + /** + * @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(); + }; } - diff --git a/src/core/iADC.i b/src/core/iADC.i new file mode 100644 index 00000000..9f7ad0cf --- /dev/null +++ b/src/core/iADC.i @@ -0,0 +1,2 @@ +%import (module="upm.pyupm_core") ".iADC.i" +%include ".core.i" diff --git a/src/core/iActuatorType.cxx b/src/core/iActuatorType.cxx new file mode 100644 index 00000000..306c1b61 --- /dev/null +++ b/src/core/iActuatorType.cxx @@ -0,0 +1,187 @@ +#include "iActuatorType.hpp" +#include "external/json/json.hpp" + +using namespace upm; + +namespace upm { + +template +void to_json(nlohmann::json& j, const ActuatorSink &p) { + j = nlohmann::json{{"unit", p.unit}, {"min", p.min}, {"max", p.max}, {"accuracy", p.accuracy}}; +} + +template +void from_json(const nlohmann::json& j, ActuatorSink& p) { + p.unit = j.at("unit").get(); + p.min = j.at("min").get(); + p.max = j.at("max").get(); + p.accuracy = j.at("accuracy").get(); +} + +template +void to_json(nlohmann::json& j, const ActuatorCommand &p) { + j = nlohmann::json{{"command", p.command}, {"unit", p.unit}, {"value", p.value}}; +} + +template +void from_json(const nlohmann::json& j, ActuatorCommand& p) { + p.command= j.at("command").get(); + p.unit = j.at("unit").get(); + p.value = j.at("value").get(); +} + +template +std::ostream &operator<<(std::ostream& os, const ActuatorCommand& 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::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 const & iActuatorType::CommandMap () const +{ return _sinks_2_units;} + +std::vector 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 const & iActuatorType::Units () const +{ return _units; } + +std::string const iActuatorType::Unit (std::string source) const +{ + std::map::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::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::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& p); +template void upm::from_json(const nlohmann::json& j, ActuatorSink& p); +template void upm::to_json(nlohmann::json& j, const ActuatorSink& p); +template void upm::from_json(const nlohmann::json& j, ActuatorSink& p); +template void upm::to_json(nlohmann::json& j, const ActuatorSink& p); +template void upm::from_json(const nlohmann::json& j, ActuatorSink& p); + +template void upm::to_json(nlohmann::json& j, const ActuatorCommand& p); +template void upm::from_json(const nlohmann::json& j, ActuatorCommand& p); +template void upm::to_json(nlohmann::json& j, const ActuatorCommand& p); +template void upm::from_json(const nlohmann::json& j, ActuatorCommand& p); +template void upm::to_json(nlohmann::json& j, const ActuatorCommand& p); +template void upm::from_json(const nlohmann::json& j, ActuatorCommand& p); + +template std::ostream &upm::operator<<(std::ostream& os, const ActuatorCommand& ac); diff --git a/src/core/iActuatorType.hpp b/src/core/iActuatorType.hpp new file mode 100644 index 00000000..f0201f69 --- /dev/null +++ b/src/core/iActuatorType.hpp @@ -0,0 +1,156 @@ +#pragma once + +#include "iUpmObject.hpp" + +/* I/O fwd declaration header */ +#include + +namespace upm +{ + template + struct ActuatorSink + { + std::string unit; + T min; + T max; + T accuracy; + }; + + template + void to_json(nlohmann::json& j, const ActuatorSink& p); + + template + void from_json(const nlohmann::json& j, ActuatorSink& p); + + template + struct ActuatorCommand + { + std::string command; + std::string unit; + T value; + }; + + template + void to_json(nlohmann::json& j, const ActuatorCommand& p); + + template + void from_json(const nlohmann::json& j, ActuatorCommand& p); + + template + std::ostream &operator<<(std::ostream&, const ActuatorCommand&); + + /** + * 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& CommandMap() const; + + /** + * Return a vector of all known sinks for this actuator. + * + * @return Vector of sinks + */ + const std::vector& Commands(); + + /** + * Return a vector of all known units for this actuator. + * + * @return Vector of units + */ + const std::vector& 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 _sinks; + + /** + * Sensor unit vector + */ + std::vector _units; + + /** + * Mapping of sinks to units + */ + std::map _sinks_2_units; + + protected: + /** + * Mapping of sinks to units + */ + void AddCommand(std::string source, std::string unit); + + }; +} diff --git a/src/core/iActuatorType.i b/src/core/iActuatorType.i new file mode 100644 index 00000000..fb4f657d --- /dev/null +++ b/src/core/iActuatorType.i @@ -0,0 +1,4 @@ +%import (module="upm.pyupm_core") "iActuatorType.hpp" +%include ".iActuatorType.i" + +%include ".core.i" diff --git a/src/core/iCO2Sensor.cxx b/src/core/iCO2Sensor.cxx new file mode 100644 index 00000000..561ffa1d --- /dev/null +++ b/src/core/iCO2Sensor.cxx @@ -0,0 +1,54 @@ +#include "iCO2Sensor.hpp" + +using namespace upm; + +std::map iCO2Sensor::CO2All () +{return CO2ForSources(Sources());} + +float iCO2Sensor::CO2ForSource(std::string source) +{ + std::map vals = CO2ForSources(std::vector(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(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(*inst); + + std::map data = ref.CO2All(); + + for (std::map::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(); +} diff --git a/src/core/iCO2Sensor.hpp b/src/core/iCO2Sensor.hpp new file mode 100644 index 00000000..be721a6b --- /dev/null +++ b/src/core/iCO2Sensor.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include +#include + +#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 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 CO2ForSources(std::vector 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); + }; +} diff --git a/src/core/iCO2Sensor.i b/src/core/iCO2Sensor.i new file mode 100644 index 00000000..3f322ac8 --- /dev/null +++ b/src/core/iCO2Sensor.i @@ -0,0 +1,2 @@ +%import (module="upm.pyupm_core") ".iCO2Sensor.i" +%include ".core.i" diff --git a/src/core/iHumiditySensor.cxx b/src/core/iHumiditySensor.cxx new file mode 100644 index 00000000..9b4270f3 --- /dev/null +++ b/src/core/iHumiditySensor.cxx @@ -0,0 +1,51 @@ +#include "iHumiditySensor.hpp" + +using namespace upm; + +std::map iHumiditySensor::HumidityAll () +{return HumidityForSources(Sources());} + +float iHumiditySensor::HumidityForSource (std::string source) +{ + std::map vals = HumidityForSources(std::vector(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(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(*inst); + + std::map data = ref.HumidityAll(); + + for (std::map::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(); +} diff --git a/src/core/iHumiditySensor.hpp b/src/core/iHumiditySensor.hpp new file mode 100644 index 00000000..19d32380 --- /dev/null +++ b/src/core/iHumiditySensor.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include +#include + +#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 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 HumidityForSources(std::vector 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); + }; +} diff --git a/src/core/iHumiditySensor.i b/src/core/iHumiditySensor.i new file mode 100644 index 00000000..30edf0fe --- /dev/null +++ b/src/core/iHumiditySensor.i @@ -0,0 +1,2 @@ +%import (module="upm.pyupm_core") ".iHumiditySensor.i" +%include ".core.i" diff --git a/src/core/iLightController.cxx b/src/core/iLightController.cxx new file mode 100644 index 00000000..780687da --- /dev/null +++ b/src/core/iLightController.cxx @@ -0,0 +1,3 @@ +#include "iLightController.hpp" + +upm::ILightController::~ILightController () {} diff --git a/src/interfaces/iLightController.hpp b/src/core/iLightController.hpp similarity index 94% rename from src/interfaces/iLightController.hpp rename to src/core/iLightController.hpp index 813d6c0a..4b08b90f 100644 --- a/src/interfaces/iLightController.hpp +++ b/src/core/iLightController.hpp @@ -24,7 +24,6 @@ #pragma once -#include "iModuleStatus.hpp" namespace upm { @@ -41,7 +40,7 @@ namespace upm * @snippet light-controllers.cxx Interesting */ - class ILightController : virtual public IModuleStatus + class ILightController { public: /** @@ -84,8 +83,8 @@ namespace upm * @throws std::runtime_error */ virtual int getBrightness() = 0; - - virtual ~ILightController() {} + + virtual ~ILightController(); }; } diff --git a/src/core/iLightController.i b/src/core/iLightController.i new file mode 100644 index 00000000..097c6228 --- /dev/null +++ b/src/core/iLightController.i @@ -0,0 +1,2 @@ +%import (module="upm.pyupm_core") ".iLightController.i" +%include ".core.i" diff --git a/src/core/iLightSensor.cxx b/src/core/iLightSensor.cxx new file mode 100644 index 00000000..9111f252 --- /dev/null +++ b/src/core/iLightSensor.cxx @@ -0,0 +1,54 @@ +#include "iLightSensor.hpp" + +using namespace upm; + +std::map iLightSensor::LightAll () +{return LightForSources(Sources());} + +float iLightSensor::LightForSource (std::string source) +{ + std::map vals = LightForSources(std::vector(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(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(this)) + "}"; +} + +std::string iLightSensor::_JsonLight (iUpmObject * inst) +{ + std::stringstream ss; + + /* Downcast to reference (throws if cast fails) */ + iLightSensor& ref = dynamic_cast(*inst); + + std::map data = ref.LightAll(); + + for (std::map::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(); +} diff --git a/src/core/iLightSensor.hpp b/src/core/iLightSensor.hpp new file mode 100644 index 00000000..246732a7 --- /dev/null +++ b/src/core/iLightSensor.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include +#include + +#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 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 LightForSources(std::vector 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); + }; +} diff --git a/src/core/iLightSensor.i b/src/core/iLightSensor.i new file mode 100644 index 00000000..e2e3ffbf --- /dev/null +++ b/src/core/iLightSensor.i @@ -0,0 +1,2 @@ +%import (module="upm.pyupm_core") ".iLightSensor.i" +%include ".core.i" diff --git a/src/core/iMoistureSensor.cxx b/src/core/iMoistureSensor.cxx new file mode 100644 index 00000000..b48a2de3 --- /dev/null +++ b/src/core/iMoistureSensor.cxx @@ -0,0 +1,39 @@ +#include "iMoistureSensor.hpp" + +using namespace upm; + +std::map iMoistureSensor::MoistureAll () +{return MoistureForSources(Sources());} + +std::map iMoistureSensor::MoistureForSource (std::string source) +{ return MoistureForSources(std::vector(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(*inst); + + std::map data = ref.MoistureAll(); + + for (std::map::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(); +} diff --git a/src/core/iMoistureSensor.hpp b/src/core/iMoistureSensor.hpp new file mode 100644 index 00000000..a40a7044 --- /dev/null +++ b/src/core/iMoistureSensor.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +#include "iSensorType.hpp" + +namespace upm +{ + class iMoistureSensor : public virtual iSensorType + { + public: + virtual std::map MoistureAll(); + virtual std::map MoistureForSource(std::string source); + virtual std::map MoistureForSources(std::vector 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); + }; +} diff --git a/src/core/iMoistureSensor.i b/src/core/iMoistureSensor.i new file mode 100644 index 00000000..026db7ca --- /dev/null +++ b/src/core/iMoistureSensor.i @@ -0,0 +1,2 @@ +%import (module="upm.pyupm_core") ".iMoistureSensor.i" +%include ".core.i" diff --git a/src/core/iMraa.cxx b/src/core/iMraa.cxx new file mode 100644 index 00000000..ead8e07d --- /dev/null +++ b/src/core/iMraa.cxx @@ -0,0 +1,286 @@ +#include +#include +#include +#include +#include +#include + +#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 +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 split(const std::string &s, char delim) +{ + std::vector 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 _mraa_Mode = +{ + {"strong", mraa::MODE_STRONG}, + {"pullup", mraa::MODE_PULLUP}, + {"pulldown", mraa::MODE_PULLDOWN}, + {"hiz", mraa::MODE_HIZ}, +}; + +std::map _mraa_Dir = +{ + {"out", mraa::DIR_OUT}, + {"in", mraa::DIR_IN}, + {"high", mraa::DIR_OUT_HIGH}, + {"low", mraa::DIR_OUT_LOW}, +}; +std::map _mraa_Edge = +{ + {"none", mraa::EDGE_NONE}, + {"both", mraa::EDGE_BOTH}, + {"rising", mraa::EDGE_RISING}, + {"falling", mraa::EDGE_FALLING}, +}; +std::map _mraa_InputMode = +{ + {"active_high", mraa::MODE_IN_ACTIVE_HIGH}, + {"avtive_low", mraa::MODE_IN_ACTIVE_LOW}, +}; +std::map _mraa_OutputMode = +{ + {"open_drain", mraa::MODE_OUT_OPEN_DRAIN}, + {"push_pull", mraa::MODE_OUT_PUSH_PULL}, +}; + +std::map _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 protocols = split(lwr, ','); + + for (std::vector::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 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:[: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::iterator it = _aio.begin(); + it != _aio.end(); ++it) delete *it; + for (std::vector::iterator it = _gpio.begin(); + it != _gpio.end(); ++it) delete *it; + for (std::vector::iterator it = _i2c.begin(); + it != _i2c.end(); ++it) delete *it; + for (std::vector::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(); +} diff --git a/src/core/iMraa.hpp b/src/core/iMraa.hpp new file mode 100644 index 00000000..5ae4074e --- /dev/null +++ b/src/core/iMraa.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#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 + // T& Connection(std::string label); + // + // template + // bool DefineConnections(std::vector labels) + // { + // if (std::is_same::value) + // { + // } + // else if (std::is_same::value) {} + // else if (std::is_same::value) + // { + // } + // + // return false; + // } + //private: + std::vector _aio; + std::vector _gpio; + std::vector _i2c; + std::vector _iio; + std::vector _pwm; + std::vector _spi; + std::vector _uart; + std::vector _uartow; + }; +} diff --git a/src/core/iMraa.i b/src/core/iMraa.i new file mode 100644 index 00000000..c0250342 --- /dev/null +++ b/src/core/iMraa.i @@ -0,0 +1,2 @@ +%import (module="upm.pyupm_core") ".iMraa.i" +%include ".core.i" diff --git a/src/core/iPressureSensor.cxx b/src/core/iPressureSensor.cxx new file mode 100644 index 00000000..080b0fb9 --- /dev/null +++ b/src/core/iPressureSensor.cxx @@ -0,0 +1,54 @@ +#include "iPressureSensor.hpp" + +using namespace upm; + +std::map iPressureSensor::PressureAll () +{return PressureForSources(Sources());} + +float iPressureSensor::PressureForSource (std::string source) +{ + std::map vals = PressureForSources(std::vector(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(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(*inst); + + std::map data = ref.PressureAll(); + + for (std::map::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(); +} diff --git a/src/core/iPressureSensor.hpp b/src/core/iPressureSensor.hpp new file mode 100644 index 00000000..38cf6947 --- /dev/null +++ b/src/core/iPressureSensor.hpp @@ -0,0 +1,72 @@ +#pragma once + +#include +#include + +#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 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 PressureForSources(std::vector 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); + }; +} diff --git a/src/core/iPressureSensor.i b/src/core/iPressureSensor.i new file mode 100644 index 00000000..5336da1f --- /dev/null +++ b/src/core/iPressureSensor.i @@ -0,0 +1,2 @@ +%import (module="upm.pyupm_core") ".iPressureSensor.i" +%include ".core.i" diff --git a/src/core/iSensorType.cxx b/src/core/iSensorType.cxx new file mode 100644 index 00000000..f39dfaba --- /dev/null +++ b/src/core/iSensorType.cxx @@ -0,0 +1,156 @@ +#include "iSensorType.hpp" + +#include "external/json/json.hpp" + +using namespace upm; + +namespace upm { +template +void to_json(nlohmann::json& j, const SensorSource &p) { + j = nlohmann::json{{"unit", p.unit}, {"min", p.min}, {"max", p.max}, {"accuracy", p.accuracy}}; +} + +template +void from_json(const nlohmann::json& j, SensorSource& p) { + p.unit = j.at("unit").get(); + p.min = j.at("min").get(); + p.max = j.at("max").get(); + p.accuracy = j.at("accuracy").get(); +} +} + +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::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 const & iSensorType::SourceMap () const +{ return _sources_2_units;} + +std::vector 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 const & iSensorType::Units () const +{ return _units; } + +std::string const iSensorType::Unit (std::string source) const +{ + std::map::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::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::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& p); +template void upm::from_json(const nlohmann::json& j, SensorSource& p); +template void upm::to_json(nlohmann::json& j, const SensorSource& p); +template void upm::from_json(const nlohmann::json& j, SensorSource& p); +template void upm::to_json(nlohmann::json& j, const SensorSource& p); +template void upm::from_json(const nlohmann::json& j, SensorSource& p); diff --git a/src/core/iSensorType.hpp b/src/core/iSensorType.hpp new file mode 100644 index 00000000..a21a3299 --- /dev/null +++ b/src/core/iSensorType.hpp @@ -0,0 +1,143 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "iUpmObject.hpp" + +namespace upm +{ + + template + struct SensorSource + { + std::string unit; + T min; + T max; + T accuracy; + }; + + template + void to_json(nlohmann::json& j, const SensorSource& p); + + template + void from_json(const nlohmann::json& j, SensorSource& 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& SourceMap() const; + + /** + * Return a vector of all known sources for this sensor. + * + * @return Vector of sources + */ + const std::vector& Sources(); + + /** + * Return a vector of all known units for this sensor. + * + * @return Vector of units + */ + const std::vector& 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 _sources; + + /** + * Sensor unit vector + */ + std::vector _units; + + /** + * Mapping of sources to units + */ + std::map _sources_2_units; + + protected: + /** + * Mapping of sources to units + */ + void AddSource(std::string source, std::string unit); + + }; +} diff --git a/src/core/iSensorType.i b/src/core/iSensorType.i new file mode 100644 index 00000000..576e4367 --- /dev/null +++ b/src/core/iSensorType.i @@ -0,0 +1,4 @@ +%import (module="upm.pyupm_core") "iSensorType.hpp" +%include ".iSensorType.i" + +%include ".core.i" diff --git a/src/core/iServoActuator.cxx b/src/core/iServoActuator.cxx new file mode 100644 index 00000000..baf768c4 --- /dev/null +++ b/src/core/iServoActuator.cxx @@ -0,0 +1,147 @@ +#include + +#include "iServoActuator.hpp" +#include "external/json/json.hpp" +#include + +using namespace upm; + +iServoActuator::iServoActuator () +{ + DEBUG_MSG("XXX"); + AddJsonDeserializer(this, &_DeserializeAngleCommands); +} + +iServoActuator::~iServoActuator () +{ + DEBUG_MSG("XXX"); +} + +void iServoActuator::AngleAll (float angle) +{ + std::map tmpcmds; + + for(std::vector::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(ss, ", ")); + if (!Commands().empty()) + ss << Commands().back(); + ss << "}"; + throw std::invalid_argument(ss.str()); + } + + AngleForCommands(std::map {{command, angle}}); +} + +void iServoActuator::AngleFromJson(std::string json_commands) +{ + std::vector> 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> 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> 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>::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(*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 _as = it.value(); + ref.AddCommand(it.key(), _as.unit); + } + + /* Return a string */ + return jsrs.dump(); +} diff --git a/src/core/iServoActuator.hpp b/src/core/iServoActuator.hpp new file mode 100644 index 00000000..089c62c0 --- /dev/null +++ b/src/core/iServoActuator.hpp @@ -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 commands) = 0; + + virtual void AngleFromJson(std::string json_commands); + + private: + static std::string _DeserializeAngleCommands(iUpmObject * inst); + }; +} diff --git a/src/core/iServoActuator.i b/src/core/iServoActuator.i new file mode 100644 index 00000000..c9efb38b --- /dev/null +++ b/src/core/iServoActuator.i @@ -0,0 +1,2 @@ +%import (module="upm.pyupm_core") ".iServoActuator.i" +%include ".core.i" diff --git a/src/core/iTemperatureSensor.cxx b/src/core/iTemperatureSensor.cxx new file mode 100644 index 00000000..e39b64e6 --- /dev/null +++ b/src/core/iTemperatureSensor.cxx @@ -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 iTemperatureSensor::TemperatureAll () +{return TemperatureForSources(Sources());} + +float iTemperatureSensor::TemperatureForSource (std::string source) +{ + std::map vals = TemperatureForSources(std::vector(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(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(*inst); + + std::map data = ref.TemperatureAll(); + + for (std::map::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(*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> sources = jsrs; + + /* Assign to this instance */ + ref._temp_sources = sources; + + /* Add all sources to iSensorType's source vector */ + for (std::map>::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(); +} diff --git a/src/core/iTemperatureSensor.hpp b/src/core/iTemperatureSensor.hpp new file mode 100644 index 00000000..94680226 --- /dev/null +++ b/src/core/iTemperatureSensor.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include +#include + +#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 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 TemperatureForSources(std::vector 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> _temp_sources; + + }; +} diff --git a/src/core/iTemperatureSensor.i b/src/core/iTemperatureSensor.i new file mode 100644 index 00000000..3768edd1 --- /dev/null +++ b/src/core/iTemperatureSensor.i @@ -0,0 +1,2 @@ +%import (module="upm.pyupm_core") ".iTemperatureSensor.i" +%include ".core.i" diff --git a/src/core/iUpmObject.cxx b/src/core/iUpmObject.cxx new file mode 100644 index 00000000..a72992c2 --- /dev/null +++ b/src/core/iUpmObject.cxx @@ -0,0 +1,287 @@ +#include +#include +#include +#include +#include +#include +#include + + +#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(t)), + std::istreambuf_iterator()); + + /* 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::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-.so, using: " << basename; + + //THROW_RUNTIME("Could not get base library name. UPM library name does not follow the libupm-.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 .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(t)), + std::istreambuf_iterator()); + + 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; } diff --git a/src/core/iUpmObject.hpp b/src/core/iUpmObject.hpp new file mode 100644 index 00000000..f22f1f37 --- /dev/null +++ b/src/core/iUpmObject.hpp @@ -0,0 +1,121 @@ +#pragma once + +#include + +#include +#include + +#include +#include +#include + +#if !defined(NDEBUG) +#include +#endif + +#ifndef SWIG +/* Forward declare the basic_json class */ +namespace nlohmann +{ + template + struct adl_serializer; + + template class ObjectType, + template class ArrayType, + class StringType, + class BooleanType, + class NumberIntegerType, + class NumberUnsignedType, + class NumberFloatType, + template class AllocatorType, + template class JSONSerializer> + class basic_json; + + using json = basic_json; +} +#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 _child_value_serializers; + + /** + * Used by child classes for child-to-parent proxy call + */ + std::map _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; + }; +} diff --git a/src/core/iUpmObject.i b/src/core/iUpmObject.i new file mode 100644 index 00000000..2d348e6b --- /dev/null +++ b/src/core/iUpmObject.i @@ -0,0 +1,2 @@ +%import (module="upm.pyupm_core") "iUpmObject.hpp" +%include ".iUpmObject.i" diff --git a/src/core/iUpmObject_generated.cxx.in b/src/core/iUpmObject_generated.cxx.in new file mode 100644 index 00000000..5227a3f5 --- /dev/null +++ b/src/core/iUpmObject_generated.cxx.in @@ -0,0 +1 @@ +const char* DATA_DIRECTORY = "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_DATADIR@"; diff --git a/src/ds1808lc/CMakeLists.txt b/src/ds1808lc/CMakeLists.txt index 70cf93b5..f1e855e5 100644 --- a/src/ds1808lc/CMakeLists.txt +++ b/src/ds1808lc/CMakeLists.txt @@ -2,4 +2,4 @@ set (libname "ds1808lc") set (libdescription "Lighting Controller") set (module_src ${libname}.cxx mraa-utils.cxx) set (module_hpp ${libname}.hpp) -upm_module_init(interfaces mraa) +upm_module_init(core mraa) diff --git a/src/ds1808lc/ds1808lc.cxx b/src/ds1808lc/ds1808lc.cxx index 4e001102..0668d5ce 100644 --- a/src/ds1808lc/ds1808lc.cxx +++ b/src/ds1808lc/ds1808lc.cxx @@ -54,7 +54,7 @@ int DS1808LC::getBrightness() return getPercentBrightness(values[0], values[1]); } else - UPM_THROW("i2c read error"); + throw std::runtime_error(std::string(__FUNCTION__) + " : i2c read error"); } @@ -65,7 +65,7 @@ void DS1808LC::setBrightness(int dutyPercent) values[1] = getPot2Value(dutyPercent); status = i2c->write(values, 2); if (status != mraa::SUCCESS) - UPM_THROW("i2c write error"); + throw std::runtime_error(std::string(__FUNCTION__) + " : i2c write error"); } // diff --git a/src/ds1808lc/ds1808lc.hpp b/src/ds1808lc/ds1808lc.hpp index e6f3c7c1..c25ebbf5 100644 --- a/src/ds1808lc/ds1808lc.hpp +++ b/src/ds1808lc/ds1808lc.hpp @@ -57,7 +57,6 @@ public: DS1808LC(int gpioPower, int i2cBus); ~DS1808LC(); - const char* getModuleName() { return "ds1808lc"; } bool isPowered(); void setPowerOn(); void setPowerOff(); diff --git a/src/ds1808lc/ds1808lc.i b/src/ds1808lc/ds1808lc.i index e68e58b4..711c9a69 100644 --- a/src/ds1808lc/ds1808lc.i +++ b/src/ds1808lc/ds1808lc.i @@ -1,30 +1,15 @@ %include "../common_top.i" +%include "iLightController.i" /* BEGIN Java syntax ------------------------------------------------------- */ #ifdef SWIGJAVA %include "arrays_java.i"; %include "../java_buffer.i" -%typemap(javaimports) SWIGTYPE %{import upm_interfaces.*;%} -%import "../interfaces/javaupm_iLightController.i" JAVA_JNI_LOADLIBRARY(javaupm_ds1808lc) #endif /* END Java syntax */ -/* BEGIN Javascript syntax ------------------------------------------------- */ -#ifdef SWIGJAVASCRIPT -%include "iModuleStatus.hpp" -%include "iLightController.hpp" -#endif -/* END Javascript syntax */ - -/* BEGIN Python syntax ----------------------------------------------------- */ -#ifdef SWIGPYTHON -%include "iModuleStatus.hpp" -%include "iLightController.hpp" -#endif -/* END Python syntax */ - /* BEGIN Common SWIG syntax ------------------------------------------------- */ %{ #include "ds1808lc.hpp" diff --git a/src/ds1808lc/mraa-utils.cxx b/src/ds1808lc/mraa-utils.cxx index 369dce10..1a12352c 100644 --- a/src/ds1808lc/mraa-utils.cxx +++ b/src/ds1808lc/mraa-utils.cxx @@ -46,7 +46,7 @@ void MraaUtils::setGpio(int pin, int level) mraa::Gpio gpio(pin); gpio.dir(mraa::DIR_OUT); if (gpio.write(level) != mraa::SUCCESS) - UPM_THROW("gpio write failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : gpio write failed"); } diff --git a/src/groups.md b/src/groups.md index 3aaef271..4a0f1278 100644 --- a/src/groups.md +++ b/src/groups.md @@ -202,9 +202,9 @@ and is not meant to be installed anywhere. ### Groups for the various Sensor C++ Interfaces ### -@defgroup ilightsensor ILightSensor +@defgroup ilightsensor iLightSensor @ingroup byif -@brief Implements ILightSensor +@brief Implements iLightSensor @defgroup ilightcontroller ILightController @@ -212,19 +212,19 @@ and is not meant to be installed anywhere. @brief Implements ILightController -@defgroup ipressuresensor IPressureSensor +@defgroup ipressuresensor iPressureSensor @ingroup byif -@brief Implements IPressureSensor +@brief Implements iPressureSensor -@defgroup itemperaturesensor ITemperatureSensor +@defgroup itemperaturesensor iTemperatureSensor @ingroup byif -@brief Implements ITemperatureSensor +@brief Implements iTemperatureSensor -@defgroup iadc IADC +@defgroup iadc iADC @ingroup byif -@brief Implements IADC +@brief Implements iADC @defgroup ico2sensor ICOSensor diff --git a/src/hlg150h/CMakeLists.txt b/src/hlg150h/CMakeLists.txt index ee975d4b..f2bbcff0 100644 --- a/src/hlg150h/CMakeLists.txt +++ b/src/hlg150h/CMakeLists.txt @@ -2,4 +2,4 @@ set (libname "hlg150h") set (libdescription "150W Constant Voltage/current LED Driver") set (module_src ${libname}.cxx mraa-utils.cxx) set (module_hpp ${libname}.hpp) -upm_module_init(mraa interfaces) +upm_module_init(mraa core) diff --git a/src/hlg150h/hlg150h.cxx b/src/hlg150h/hlg150h.cxx index bfc8cd6f..35ad12e7 100644 --- a/src/hlg150h/hlg150h.cxx +++ b/src/hlg150h/hlg150h.cxx @@ -18,7 +18,7 @@ HLG150H::HLG150H(int pinRelay, int pinPWM) status = pwmBrightness->enable(true); status = pwmBrightness->period_us(PWM_PERIOD); if (status != mraa::SUCCESS) - UPM_THROW("pwm config failed."); + throw std::runtime_error(std::string(__FUNCTION__) + " : pwm config failed."); dutyPercent = getBrightness(); isPoweredShadow = dutyPercent > 10; } @@ -65,7 +65,7 @@ void HLG150H::setBrightness(int dutyPercent) status = pwmBrightness->pulsewidth_us(dutyUs); // std::cout << "Brightness = " << dutyPercent << "%, duty = " << dutyUs << "us" << std::endl; if (status != mraa::SUCCESS) - UPM_THROW("setBrightness failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : setBrightness failed"); } diff --git a/src/hlg150h/hlg150h.hpp b/src/hlg150h/hlg150h.hpp index 9d03a16d..e4d113cc 100644 --- a/src/hlg150h/hlg150h.hpp +++ b/src/hlg150h/hlg150h.hpp @@ -22,7 +22,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "interfaces/iLightController.hpp" +#include "iLightController.hpp" // #include "mraa/gpio.hpp" #include "mraa/pwm.hpp" @@ -60,7 +60,6 @@ public: ~HLG150H(); virtual int getBrightness(); - const char* getModuleName() { return "hlg150h"; } void setPowerOn(); void setPowerOff(); bool isPowered(); diff --git a/src/hlg150h/hlg150h.i b/src/hlg150h/hlg150h.i index 84b58cb6..46b3a572 100644 --- a/src/hlg150h/hlg150h.i +++ b/src/hlg150h/hlg150h.i @@ -1,11 +1,10 @@ %include "../common_top.i" +%include "iLightController.i" /* BEGIN Java syntax ------------------------------------------------------- */ #ifdef SWIGJAVA %include "arrays_java.i"; %include "../java_buffer.i" -%typemap(javaimports) SWIGTYPE %{import upm_interfaces.*;%} -%import "../interfaces/javaupm_iLightController.i" JAVA_JNI_LOADLIBRARY(javaupm_hlg150h) #endif diff --git a/src/hlg150h/mraa-utils.cxx b/src/hlg150h/mraa-utils.cxx index 2176b2a0..248ceb8f 100644 --- a/src/hlg150h/mraa-utils.cxx +++ b/src/hlg150h/mraa-utils.cxx @@ -35,7 +35,7 @@ void MraaUtils::setGpio(int pin, int level) mraa::Gpio gpio(pin); gpio.dir(mraa::DIR_OUT); if (gpio.write(level) != mraa::SUCCESS) - UPM_THROW("gpio write failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : gpio write failed"); } diff --git a/src/ims/CMakeLists.txt b/src/ims/CMakeLists.txt index 816b478e..ba023f6e 100644 --- a/src/ims/CMakeLists.txt +++ b/src/ims/CMakeLists.txt @@ -6,4 +6,4 @@ upm_mixed_module_init (NAME ims CPP_SRC ims.cxx FTI_SRC ims_fti.c CPP_WRAPS_C - REQUIRES mraa utilities-c) + REQUIRES mraa core utilities-c) diff --git a/src/ims/ims.cxx b/src/ims/ims.cxx index 58c1f869..4a21e2db 100644 --- a/src/ims/ims.cxx +++ b/src/ims/ims.cxx @@ -22,6 +22,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include #include #include @@ -29,12 +30,74 @@ using namespace upm; +/* Optional serializer */ +static std::string OptionalData(IMS * inst) +{ + if (inst == NULL) return ""; + + std::stringstream ss; + ss << "\"ims version\" : \"" << inst->get_version() << "\""; + return ""; +} + +IMS::IMS(std::string init_str): iMraa(init_str) +{ +} + IMS::IMS(int16_t i2c_bus, int16_t i2c_address) : _dev(ims_init(i2c_bus, i2c_address)) { if (_dev == NULL) throw std::runtime_error(std::string(__FUNCTION__) + ": failed to initialize sensor, check syslog"); + + /* Added for interface implementation */ + AddSource("light", "normalized (0.0->1.0)"); + AddSource("temperature", "c"); + AddSource("moisture", "normalized (0.0->1.0)"); + + /* Option for interface implementation, can be used to add + * additional JsonDefinition serializer methods for this class*/ + _child_value_serializers[(t_getJson)&OptionalData] = this; +} + +/* Added for interface implementation */ +std::map IMS::LightForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "light") != sources.end()) + { + uint16_t val = get_light(); + ret["light"] = (float)val/std::numeric_limits::max(); + } + + return ret; +} + +/* Added for interface implementation */ +std::map IMS::TemperatureForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "temperature") != sources.end()) + ret["temperature"] = get_temperature(); + + return ret; +} + +/* Added for interface implementation */ +std::map IMS::MoistureForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "moisture") != sources.end()) + { + uint16_t val = get_moisture(); + ret["light"] = (float)val/std::numeric_limits::max(); + } + + return ret; } uint16_t IMS::get_version() diff --git a/src/ims/ims.hpp b/src/ims/ims.hpp index 91be9a09..c1924a5c 100644 --- a/src/ims/ims.hpp +++ b/src/ims/ims.hpp @@ -24,7 +24,13 @@ #pragma once +#include + #include "ims.h" +#include "iMraa.hpp" +#include "iLightSensor.hpp" +#include "iMoistureSensor.hpp" +#include "iTemperatureSensor.hpp" namespace upm { /** @@ -55,7 +61,12 @@ namespace upm { * @snippet ims.cxx Interesting */ -class IMS { +class IMS : + public virtual iMraa, + public virtual iLightSensor, + public virtual iMoistureSensor, + public virtual iTemperatureSensor +{ public: /** * I2C Moisture Sensor constructor @@ -68,11 +79,20 @@ class IMS { */ IMS(int16_t i2c_bus, int16_t i2c_address = IMS_ADDRESS_DEFAULT); + IMS(std::string init_str); + /** * IMS destructor */ virtual ~IMS() {}; + virtual std::string Name () {return "IMS";} + virtual std::string Description () {return "Catnip Electronics I2C moisture sensor";} + + virtual std::map LightForSources(std::vector sources); + virtual std::map TemperatureForSources(std::vector sources); + virtual std::map MoistureForSources(std::vector sources); + /** * Write I2C Moisture Sensor registers * @param cmd Write command diff --git a/src/ims/ims.i b/src/ims/ims.i index 2ccc2fa5..35081217 100644 --- a/src/ims/ims.i +++ b/src/ims/ims.i @@ -1,4 +1,8 @@ %include "../common_top.i" +%include "iMraa.i" +%include "iLightSensor.i" +%include "iMoistureSensor.i" +%include "iTemperatureSensor.i" /* BEGIN Java syntax ------------------------------------------------------- */ #ifdef SWIGJAVA diff --git a/src/interfaces/CMakeLists.txt b/src/interfaces/CMakeLists.txt deleted file mode 100644 index c26d3248..00000000 --- a/src/interfaces/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -set (libname "interfaces") -set (libdescription "CXX Interface Library") -set (module_src ${libname}.cxx) - -upm_module_init() - -# Add a PUBLIC include directory to the CMAKE src dir -target_include_directories (${libname} PUBLIC ${CMAKE_SOURCE_DIR}/src) - -# Don't add the hpp files with upm_module_init, this allows -# them to be installed separately -set (module_hpp iADC.hpp - iCO2Sensor.hpp - iHumiditySensor.hpp - iLightController.hpp - iLightSensor.hpp - iModuleStatus.hpp - iPressureSensor.hpp - iTemperatureSensor.hpp) -# Install interfaces headers a bit differently -install (FILES ${module_hpp} DESTINATION include/upm/${libname} - COMPONENT ${CMAKE_PROJECT_NAME}) diff --git a/src/interfaces/iCO2Sensor.hpp b/src/interfaces/iCO2Sensor.hpp deleted file mode 100644 index 1b00e12b..00000000 --- a/src/interfaces/iCO2Sensor.hpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Author: Henry Bruce - * 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 "iModuleStatus.hpp" - -namespace upm -{ -/** - * @brief Interface for CO Sensor - */ - - class ICO2Sensor : virtual public IModuleStatus - { - public: - virtual uint16_t getPpm() = 0; - virtual ~ICO2Sensor() {} - }; - -} - diff --git a/src/interfaces/iHumiditySensor.hpp b/src/interfaces/iHumiditySensor.hpp deleted file mode 100644 index 48077d5a..00000000 --- a/src/interfaces/iHumiditySensor.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Author: Henry Bruce - * 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 "iModuleStatus.hpp" - -namespace upm -{ -/** - * @brief Interface for Humidity Sensors - */ - - class IHumiditySensor : virtual public IModuleStatus - { - public: - virtual int getHumidityRelative () = 0; - virtual ~IHumiditySensor() {} - }; - -} - diff --git a/src/interfaces/iLightSensor.hpp b/src/interfaces/iLightSensor.hpp deleted file mode 100644 index 31d34196..00000000 --- a/src/interfaces/iLightSensor.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Author: Henry Bruce - * 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 -#include "iModuleStatus.hpp" - -namespace upm -{ -/** - * @brief ILightSensor Interface for Light Sensors - */ - -/** - * - * @brief Interface for Light Sensors - - * This interface is used to represent light sensors - - * @snippet light-sensor.cxx Interesting - */ - - class ILightSensor : virtual public IModuleStatus - { - public: - - /** - * Get visible illuminance in Lux. - * - * @return double visible illuminance in Lux - */ - virtual double getVisibleLux() = 0; - - - virtual ~ILightSensor() {} - }; -} - diff --git a/src/interfaces/iModuleStatus.hpp b/src/interfaces/iModuleStatus.hpp deleted file mode 100644 index 1ba8ca77..00000000 --- a/src/interfaces/iModuleStatus.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Author: Henry Bruce - * 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 - -#include - -namespace upm -{ -/** - * @brief Interface for Module Status. Sensor and Actuactor Interfaces Derive from this Interface. - */ - -#define UPM_THROW(msg) throw std::runtime_error(std::string(__FUNCTION__) + ": " + (msg)) - -class IModuleStatus -{ -public: - /** - * Returns name of module. This is the string in library name after libupm_ - - * @return name of module - */ - virtual const char* getModuleName() = 0; - - virtual ~IModuleStatus() {} -}; - -} - - - diff --git a/src/interfaces/iPressureSensor.hpp b/src/interfaces/iPressureSensor.hpp deleted file mode 100644 index 7a5eebf8..00000000 --- a/src/interfaces/iPressureSensor.hpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Author: Henry Bruce - * 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 -#include -#include "iModuleStatus.hpp" - -namespace upm -{ -/* - * @brief Interface for Pressue Sensors - */ - - class IPressureSensor : virtual public IModuleStatus - { - public: - virtual int getPressurePa() = 0; - virtual ~IPressureSensor() {} - }; - -} - diff --git a/src/interfaces/iTemperatureSensor.hpp b/src/interfaces/iTemperatureSensor.hpp deleted file mode 100644 index bea30aed..00000000 --- a/src/interfaces/iTemperatureSensor.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Author: Henry Bruce - * 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 "iModuleStatus.hpp" - -namespace upm -{ -/** - * @brief Interface for Temperature Sensors - */ - - class ITemperatureSensor : virtual public IModuleStatus - { - public: - virtual int getTemperatureCelsius () = 0; - virtual ~ITemperatureSensor() {} - }; - -} - diff --git a/src/interfaces/interfaces.cxx b/src/interfaces/interfaces.cxx deleted file mode 100644 index 5b0912d5..00000000 --- a/src/interfaces/interfaces.cxx +++ /dev/null @@ -1 +0,0 @@ -#include "iLightSensor.hpp" diff --git a/src/interfaces/interfaces.i b/src/interfaces/interfaces.i deleted file mode 100644 index 3f77d902..00000000 --- a/src/interfaces/interfaces.i +++ /dev/null @@ -1,18 +0,0 @@ -%include "../common_top.i" - -/* BEGIN Java syntax ------------------------------------------------------- */ -#ifdef SWIGJAVA -%import "../_upm.i" - -%include javaupm_iModuleStatus.i -%include javaupm_iADC.i -%include javaupm_iCO2Sensor.i -%include javaupm_iHumiditySensor.i -%include javaupm_iLightController.i -%include javaupm_iLightSensor.i -%include javaupm_iPressureSensor.i -%include javaupm_iTemperatureSensor.i - -JAVA_JNI_LOADLIBRARY(javaupm_interfaces) -#endif -/* END Java syntax */ diff --git a/src/interfaces/javaupm_iADC.i b/src/interfaces/javaupm_iADC.i deleted file mode 100644 index e50806b7..00000000 --- a/src/interfaces/javaupm_iADC.i +++ /dev/null @@ -1,11 +0,0 @@ -#if SWIG_VERSION >= 0x030009 - %include - %interface_impl(upm::IADC); -#endif -%include "interfaces.i" -%include "javaupm_iModuleStatus.i" - -%include "iADC.hpp" -%{ - #include "iADC.hpp" -%} diff --git a/src/interfaces/javaupm_iCO2Sensor.i b/src/interfaces/javaupm_iCO2Sensor.i deleted file mode 100644 index 237690ff..00000000 --- a/src/interfaces/javaupm_iCO2Sensor.i +++ /dev/null @@ -1,12 +0,0 @@ -#if SWIG_VERSION >= 0x030009 - %include - %interface_impl(upm::ICO2Sensor); -#endif -%include "stdint.i" -%include "interfaces.i" -%include "javaupm_iModuleStatus.i" - -%include "iCO2Sensor.hpp" -%{ - #include "iCO2Sensor.hpp" -%} diff --git a/src/interfaces/javaupm_iHumiditySensor.i b/src/interfaces/javaupm_iHumiditySensor.i deleted file mode 100644 index 1b680ded..00000000 --- a/src/interfaces/javaupm_iHumiditySensor.i +++ /dev/null @@ -1,11 +0,0 @@ -#if SWIG_VERSION >= 0x030009 - %include - %interface_impl(upm::IHumiditySensor); -#endif -%include "interfaces.i" -%include "javaupm_iModuleStatus.i" - -%include "iHumiditySensor.hpp" -%{ - #include "iHumiditySensor.hpp" -%} diff --git a/src/interfaces/javaupm_iLightController.i b/src/interfaces/javaupm_iLightController.i deleted file mode 100644 index 3c47d1db..00000000 --- a/src/interfaces/javaupm_iLightController.i +++ /dev/null @@ -1,11 +0,0 @@ -#if SWIG_VERSION >= 0x030009 - %include - %interface_impl(upm::ILightController); -#endif -%include "interfaces.i" -%include "javaupm_iModuleStatus.i" - -%{ -#include "iLightController.hpp" -%} -%include "iLightController.hpp" diff --git a/src/interfaces/javaupm_iLightSensor.i b/src/interfaces/javaupm_iLightSensor.i deleted file mode 100644 index 429e18a8..00000000 --- a/src/interfaces/javaupm_iLightSensor.i +++ /dev/null @@ -1,11 +0,0 @@ -#if SWIG_VERSION >= 0x030009 - %include - %interface_impl(upm::ILightSensor); -#endif -%include "interfaces.i" -%include "javaupm_iModuleStatus.i" - -%include "iLightSensor.hpp" -%{ - #include "iLightSensor.hpp" -%} diff --git a/src/interfaces/javaupm_iModuleStatus.i b/src/interfaces/javaupm_iModuleStatus.i deleted file mode 100644 index f8286767..00000000 --- a/src/interfaces/javaupm_iModuleStatus.i +++ /dev/null @@ -1,8 +0,0 @@ -#if SWIG_VERSION >= 0x030009 - %include - %interface_impl(upm::IModuleStatus); -#endif -%include "iModuleStatus.hpp" -%{ - #include "iModuleStatus.hpp" -%} diff --git a/src/interfaces/javaupm_iPressureSensor.i b/src/interfaces/javaupm_iPressureSensor.i deleted file mode 100644 index 67ef7f66..00000000 --- a/src/interfaces/javaupm_iPressureSensor.i +++ /dev/null @@ -1,11 +0,0 @@ -#if SWIG_VERSION >= 0x030009 - %include - %interface_impl(upm::IPressureSensor); -#endif -%include "interfaces.i" -%include "javaupm_iModuleStatus.i" - -%include "iPressureSensor.hpp" -%{ - #include "iPressureSensor.hpp" -%} diff --git a/src/interfaces/javaupm_iTemperatureSensor.i b/src/interfaces/javaupm_iTemperatureSensor.i deleted file mode 100644 index 6da971af..00000000 --- a/src/interfaces/javaupm_iTemperatureSensor.i +++ /dev/null @@ -1,11 +0,0 @@ -#if SWIG_VERSION >= 0x030009 - %include - %interface_impl(upm::ITemperatureSensor); -#endif -%include "interfaces.i" -%include "javaupm_iModuleStatus.i" - -%include "iTemperatureSensor.hpp" -%{ - #include "iTemperatureSensor.hpp" -%} diff --git a/src/lp8860/CMakeLists.txt b/src/lp8860/CMakeLists.txt index 2c1e4cf0..9353a82a 100644 --- a/src/lp8860/CMakeLists.txt +++ b/src/lp8860/CMakeLists.txt @@ -2,4 +2,4 @@ set (libname "lp8860") set (libdescription "LED Lighting Controller") set (module_src ${libname}.cxx mraa-utils.cxx) set (module_hpp ${libname}.hpp) -upm_module_init(mraa interfaces) +upm_module_init(mraa core) diff --git a/src/lp8860/lp8860.cxx b/src/lp8860/lp8860.cxx index da1ddeb0..abaed261 100644 --- a/src/lp8860/lp8860.cxx +++ b/src/lp8860/lp8860.cxx @@ -111,7 +111,7 @@ LP8860::LP8860(int gpioPower, int i2cBus) if (isAvailable()) status = mraa::SUCCESS; if (status != mraa::SUCCESS) - UPM_THROW("i2c config failed."); + throw std::runtime_error(std::string(__FUNCTION__) + " : i2c config failed."); } LP8860::~LP8860() @@ -242,7 +242,7 @@ void LP8860::i2cWriteByte(int reg, int value) { status = i2c->writeReg(static_cast(reg), static_cast(value)); if (status != mraa::SUCCESS) - UPM_THROW("i2cWriteByte failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : i2cWriteByte failed"); } @@ -250,7 +250,7 @@ uint8_t LP8860::i2cReadByte(uint8_t reg) { uint8_t value; if (i2c->readBytesReg(reg, &value, 1) != 1) - UPM_THROW("i2cReadByte failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : i2cReadByte failed"); return value; } @@ -268,13 +268,13 @@ void LP8860::i2cWriteBuffer(int reg, uint8_t* buf, int length) else status = mraa::ERROR_INVALID_PARAMETER; if (status != mraa::SUCCESS) - UPM_THROW("i2cWriteBuffer failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : i2cWriteBuffer failed"); } void LP8860::i2cReadBuffer(int reg, uint8_t* buf, int length) { if (i2c->readBytesReg(reg, buf, length) != length) - UPM_THROW("i2cReadBuffer failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : i2cReadBuffer failed"); } diff --git a/src/lp8860/lp8860.hpp b/src/lp8860/lp8860.hpp index 99dac61f..80154027 100644 --- a/src/lp8860/lp8860.hpp +++ b/src/lp8860/lp8860.hpp @@ -22,7 +22,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "interfaces/iLightController.hpp" +#include "iLightController.hpp" #include "mraa/i2c.hpp" namespace upm @@ -56,7 +56,6 @@ class LP8860 : public upm::ILightController public: LP8860(int gpioPower, int i2cBus); ~LP8860(); - virtual const char* getModuleName() { return "lp8860"; } bool isPowered(); void setPowerOn(); void setPowerOff(); diff --git a/src/lp8860/lp8860.i b/src/lp8860/lp8860.i index 6b638ffe..000461b6 100644 --- a/src/lp8860/lp8860.i +++ b/src/lp8860/lp8860.i @@ -1,10 +1,8 @@ %include "../common_top.i" +%include "iLightController.i" /* BEGIN Java syntax ------------------------------------------------------- */ #ifdef SWIGJAVA -%typemap(javaimports) SWIGTYPE %{import upm_interfaces.*;%} -%import "../interfaces/javaupm_iLightController.i" - JAVA_JNI_LOADLIBRARY(javaupm_lp8860) #endif /* END Java syntax */ diff --git a/src/lp8860/mraa-utils.cxx b/src/lp8860/mraa-utils.cxx index 4d235106..fcb7bbd2 100644 --- a/src/lp8860/mraa-utils.cxx +++ b/src/lp8860/mraa-utils.cxx @@ -45,7 +45,7 @@ void MraaUtils::setGpio(int pin, int level) mraa::Gpio gpio(pin); gpio.dir(mraa::DIR_OUT); if (gpio.write(level) != mraa::SUCCESS) - UPM_THROW("gpio write failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : gpio write failed"); } diff --git a/src/max44009/CMakeLists.txt b/src/max44009/CMakeLists.txt index 7ab5b1fa..2519fdd2 100644 --- a/src/max44009/CMakeLists.txt +++ b/src/max44009/CMakeLists.txt @@ -1,5 +1,5 @@ -set (libname "max44009") -set (libdescription "I2C Low-power Digital Ambient Light Sensor") -set (module_src ${libname}.cxx) -set (module_hpp ${libname}.hpp) -upm_module_init(mraa interfaces) +upm_mixed_module_init (NAME max44009 + DESCRIPTION "I2C Low-power Digital Ambient Light Sensor" + CPP_HDR max44009.hpp + CPP_SRC max44009.cxx + REQUIRES mraa core) diff --git a/src/max44009/max44009.cxx b/src/max44009/max44009.cxx index 84e99f88..19e35798 100644 --- a/src/max44009/max44009.cxx +++ b/src/max44009/max44009.cxx @@ -33,6 +33,8 @@ using namespace upm; MAX44009::MAX44009 (int bus, int devAddr) { + AddSource("light", "lux"); + m_maxControlAddr = devAddr; i2c = new mraa::I2c(bus); i2c->address(m_maxControlAddr); @@ -41,7 +43,8 @@ MAX44009::MAX44009 (int bus, int devAddr) { status = mraa::SUCCESS; reset(); if (status != mraa::SUCCESS) - UPM_THROW("config failure"); + throw std::runtime_error(std::string(__FUNCTION__) + + ": config failure"); } MAX44009::~MAX44009() { @@ -70,11 +73,22 @@ MAX44009::getVisibleRaw() { int length = i2c->readBytesReg(MAX44009_LUX_START_ADDR, data, MAX44009_LUX_LENGTH); if(length != MAX44009_LUX_LENGTH) - UPM_THROW("Read error"); + throw std::runtime_error(std::string(__FUNCTION__) + ": Read error"); return *value; } +std::map MAX44009::LightForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "light") != sources.end()) + { + ret["light"] = getVisibleLux(); + } + + return ret; +} double MAX44009::getVisibleLux() { @@ -86,7 +100,7 @@ MAX44009::getVisibleLux() { // Check for overrange condition if(exponent == MAX44009_OVERRANGE_CONDITION) - UPM_THROW("Overrange error"); + throw std::runtime_error(std::string(__FUNCTION__) + ": Overrange error"); return pow((double)2,(double)exponent) * mantissa * 0.045; } diff --git a/src/max44009/max44009.hpp b/src/max44009/max44009.hpp index 0b78b90f..6264b59b 100644 --- a/src/max44009/max44009.hpp +++ b/src/max44009/max44009.hpp @@ -26,7 +26,7 @@ #include #include -#include "interfaces/iLightSensor.hpp" +#include "iLightSensor.hpp" /* ADDRESS AND NOT_FOUND VALUE */ #define MAX44009_ADDRESS ( 0x4A ) @@ -106,10 +106,10 @@ namespace upm { * @snippet max44009.cxx Interesting * */ -class MAX44009 : public ILightSensor { +class MAX44009 : public virtual iLightSensor { public: /** - * Instanciates a MAX44009 object + * Instantiate a MAX44009 object * * @param bus number of used bus * @param devAddr address of used i2c device @@ -131,7 +131,9 @@ class MAX44009 : public ILightSensor { */ double getVisibleLux(); - virtual const char* getModuleName() { return "max44009"; } + virtual std::string Name() {return "max44009";} + virtual std::string Description() {return "I2C Low-power Digital Ambient Light Sensor";} + virtual std::map LightForSources(std::vector sources); private: /* Disable implicit copy and assignment operators */ diff --git a/src/max44009/max44009.i b/src/max44009/max44009.i index 21c139e9..f3ae1682 100644 --- a/src/max44009/max44009.i +++ b/src/max44009/max44009.i @@ -1,11 +1,9 @@ -%include "../common_top.i" +%include "iLightSensor.i" /* BEGIN Java syntax ------------------------------------------------------- */ #ifdef SWIGJAVA %include "arrays_java.i"; %include "../java_buffer.i" -%typemap(javaimports) SWIGTYPE %{import upm_interfaces.*;%} -%import "../interfaces/javaupm_iLightSensor.i" JAVA_JNI_LOADLIBRARY(javaupm_max44009) #endif diff --git a/src/ms5611/CMakeLists.txt b/src/ms5611/CMakeLists.txt index 14ec6244..d3d01266 100644 --- a/src/ms5611/CMakeLists.txt +++ b/src/ms5611/CMakeLists.txt @@ -2,4 +2,4 @@ set (libname "ms5611") set (libdescription "Barometric Pressure and Temperature Sensor") set (module_src ${libname}.cxx) set (module_hpp ${libname}.hpp) -upm_module_init(mraa interfaces) +upm_module_init(mraa core) diff --git a/src/ms5611/ms5611.cxx b/src/ms5611/ms5611.cxx index b3b34c09..4b185a1e 100644 --- a/src/ms5611/ms5611.cxx +++ b/src/ms5611/ms5611.cxx @@ -53,18 +53,21 @@ using namespace upm; MS5611::MS5611(int i2cBus, int address) { + AddSource("temperature", "C"); + AddSource("pressure", "Pa"); + i2c = new mraa::I2c(i2cBus); this->address = address; i2c->address(address); prom = new uint16_t[MS5611_PROM_SIZE]; if (i2c->writeByte(MS5611_CMD_RESET != mraa::SUCCESS)) - UPM_THROW("Reset failed."); + throw std::runtime_error(std::string(__FUNCTION__) + " : Reset failed."); delayms(5); for (int i = 0; i < MS5611_PROM_SIZE; ++i) { uint8_t buf[2]; int bytesRead = i2c->readBytesReg(MS5611_CMD_READ_PROM + 2*i, buf, 2); if (bytesRead != 2) - UPM_THROW("PROM address failed."); + throw std::runtime_error(std::string(__FUNCTION__) + " : PROM address failed."); prom[i] = buf[0] << 8; prom[i] |= buf[1]; // printf("Read PROM entry %d = %04x\n", i, prom[i]); @@ -72,7 +75,7 @@ MS5611::MS5611(int i2cBus, int address) // printf("CRC = %X\n", promCrc4()); if (promCrc4() != (prom[7] & 0x000F)) - UPM_THROW("PROM checksum error."); + throw std::runtime_error(std::string(__FUNCTION__) + " : PROM checksum error."); setOverSampling(ULTRA_HIGH_RES); } @@ -153,11 +156,11 @@ uint32_t MS5611::readADC(int adcReg) uint32_t value; uint8_t buf[3]; if (i2c->writeByte(adcReg + osr) != mraa::SUCCESS) - UPM_THROW("Convert D2 failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : Convert D2 failed"); delayms(100); int bytesRead = i2c->readBytesReg(MS5611_CMD_ADC_READ, buf, 3); if (bytesRead != 3) - UPM_THROW("ADC read failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : ADC read failed"); // printf("%02X%02X%02X\n", buf[0], buf[1], buf[2]); value = ((uint32_t)buf[0] << 16) | ((uint32_t)buf[1] << 8) | buf[2]; return value; @@ -208,3 +211,23 @@ int MS5611::getPressurePa() return pressure; } +std::map MS5611::TemperatureForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "temperature") != sources.end()) + ret["temperature"] = getTemperatureCelsius(); + + return ret; +} + +std::map MS5611::PressureForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "pressure") != sources.end()) + ret["pressure"] = getPressurePa(); + + return ret; +} + diff --git a/src/ms5611/ms5611.hpp b/src/ms5611/ms5611.hpp index b2025285..bf37d9c9 100644 --- a/src/ms5611/ms5611.hpp +++ b/src/ms5611/ms5611.hpp @@ -22,8 +22,8 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "interfaces/iPressureSensor.hpp" -#include "interfaces/iTemperatureSensor.hpp" +#include "iPressureSensor.hpp" +#include "iTemperatureSensor.hpp" #include "mraa/i2c.hpp" namespace upm @@ -58,7 +58,7 @@ namespace upm * @snippet ms5611.cxx Interesting */ -class MS5611 : public IPressureSensor, public ITemperatureSensor +class MS5611 : public iPressureSensor, public iTemperatureSensor { public: enum OsrMode @@ -68,11 +68,22 @@ public: MS5611(int i2cBus = 0, int address = MS5611_ADDRESS); ~MS5611(); - virtual const char* getModuleName() { return "ms5611"; } void setOverSampling(OsrMode osrMode); int getTemperatureCelsius(); int getPressurePa(); + /** Return the name of this device */ + virtual std::string Name () {return "ms5611";} + + /** Return the description of this device */ + virtual std::string Description () {return "Barometric pressure and temperature sensor";} + + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map TemperatureForSources(std::vector sources); + + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map PressureForSources(std::vector sources); + private: /* Disable implicit copy and assignment operators */ MS5611(const MS5611&) = delete; diff --git a/src/ms5611/ms5611.i b/src/ms5611/ms5611.i index e02dde16..1b4c92e6 100644 --- a/src/ms5611/ms5611.i +++ b/src/ms5611/ms5611.i @@ -1,11 +1,9 @@ %include "../common_top.i" +%include "iPressureSensor.i" +%include "iTemperatureSensor.i" /* BEGIN Java syntax ------------------------------------------------------- */ #ifdef SWIGJAVA -%import "../interfaces/javaupm_iTemperatureSensor.i" -%import "../interfaces/javaupm_iPressureSensor.i" -%typemap(javaimports) SWIGTYPE %{import upm_interfaces.*;%} - JAVA_JNI_LOADLIBRARY(javaupm_ms5611) #endif /* END Java syntax */ diff --git a/src/noelstemplightreader/CMakeLists.txt b/src/noelstemplightreader/CMakeLists.txt new file mode 100644 index 00000000..42580469 --- /dev/null +++ b/src/noelstemplightreader/CMakeLists.txt @@ -0,0 +1,5 @@ +upm_mixed_module_init (NAME noelstemplightreader + DESCRIPTION "Short, Title-Case Description from the NoelsTempLightReader Datasheet" + CPP_HDR noelstemplightreader.hpp + CPP_SRC noelstemplightreader.cxx + REQUIRES mraa core) diff --git a/src/noelstemplightreader/noelstemplightreader.cxx b/src/noelstemplightreader/noelstemplightreader.cxx new file mode 100644 index 00000000..177c2b05 --- /dev/null +++ b/src/noelstemplightreader/noelstemplightreader.cxx @@ -0,0 +1,29 @@ +#include "noelstemplightreader.hpp" + +#include + +using namespace upm; + +std::map NoelsTempLightReader::LightForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "light0") != sources.end()) + ret["light0"] = 1.1; + if (std::find(sources.begin(), sources.end(), "light1") != sources.end()) + ret["light1"] = 2.2; + + return ret; +} + +std::map NoelsTempLightReader::TemperatureForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "temperature0") != sources.end()) + ret["temperature0"] = 10.1; + if (std::find(sources.begin(), sources.end(), "temperature1") != sources.end()) + ret["temperature1"] = 20.2; + + return ret; +} diff --git a/src/noelstemplightreader/noelstemplightreader.hpp b/src/noelstemplightreader/noelstemplightreader.hpp new file mode 100644 index 00000000..4430a7a0 --- /dev/null +++ b/src/noelstemplightreader/noelstemplightreader.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include + +#include "iMraa.hpp" +#include "iLightSensor.hpp" +#include "iTemperatureSensor.hpp" + +namespace upm +{ + /** + * Example class to show multiple inheritance of sensor interfaces. + * + * This sensor provides light, temperature, and uses MRAA. + */ + class NoelsTempLightReader : + public virtual iLightSensor, + public virtual iTemperatureSensor, + public virtual iMraa + { + public: + static std::string AdditionalSerializer(NoelsTempLightReader * inst) + { + return "\"some other field\" : \"value\""; + } + + /** + * Add the source:units map values for this sensor + */ + NoelsTempLightReader() + { + AddSource("light0", "lux"); + AddSource("light1", "lux"); + AddSource("temperature0", "c"); + AddSource("temperature1", "c"); + _child_value_serializers[(t_getJson)&AdditionalSerializer] = this; + } + + /* Provide the sensor name */ + virtual std::string Name () {return "LightTemp9000";} + + /* Provide a brief sensor description */ + virtual std::string Description () {return "This is the best light and temperature sensor ever";} + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map LightForSources(std::vector sources); + + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map TemperatureForSources(std::vector sources); + }; +} diff --git a/src/noelstemplightreader/noelstemplightreader.i b/src/noelstemplightreader/noelstemplightreader.i new file mode 100644 index 00000000..628ab9e1 --- /dev/null +++ b/src/noelstemplightreader/noelstemplightreader.i @@ -0,0 +1,17 @@ +%include "../common_top.i" +%include "iMraa.i" +%include "iLightSensor.i" +%include "iTemperatureSensor.i" + +/* BEGIN Java syntax ------------------------------------------------------- */ +#ifdef SWIGJAVA +JAVA_JNI_LOADLIBRARY(javaupm_noelstemplightreader) +#endif +/* END Java syntax */ + +/* BEGIN Common SWIG syntax ------------------------------------------------- */ +%{ +#include "noelstemplightreader.hpp" +%} +%include "noelstemplightreader.hpp" +/* END Common SWIG syntax */ diff --git a/src/rhusb/CMakeLists.txt b/src/rhusb/CMakeLists.txt index 0aaa9f1a..69f07612 100644 --- a/src/rhusb/CMakeLists.txt +++ b/src/rhusb/CMakeLists.txt @@ -1,6 +1,5 @@ -set (libname "rhusb") -set (libdescription "Omega RH-USB Temperature and Humidity Sensor") -set (module_src ${libname}.cxx) -set (module_hpp ${libname}.hpp) -upm_module_init(mraa) - +upm_mixed_module_init (NAME rhusb + DESCRIPTION "Omega RH-USB Temperature and Humidity Sensor" + CPP_HDR rhusb.hpp + CPP_SRC rhusb.cxx + REQUIRES mraa core) diff --git a/src/rhusb/rhusb.cxx b/src/rhusb/rhusb.cxx index e6e5fa7a..bb7ac23b 100644 --- a/src/rhusb/rhusb.cxx +++ b/src/rhusb/rhusb.cxx @@ -51,10 +51,10 @@ RHUSB::RHUSB(std::string device) : m_temperature = 0.0; m_humidity = 0.0; -} -RHUSB::~RHUSB() -{ + /* Setup the sources available for this sensor */ + //AddSource("temperature", "C"); + //AddSource("humidity-relative", "%"); } void RHUSB::update() @@ -171,3 +171,26 @@ string RHUSB::getFirmwareID() return resp; } + +std::map RHUSB::TemperatureForSources(std::vector sources) +{ + std::map ret; + + update(); + if (std::find(sources.begin(), sources.end(), "temperature") != sources.end()) + ret["temperature"] = getTemperature(false); + + return ret; +} + +std::map RHUSB::HumidityForSources(std::vector sources) +{ + std::map ret; + + update(); + if (std::find(sources.begin(), sources.end(), "humidity-relative") != sources.end()) + ret["humidity-relative"] = getHumidity(); + + return ret; +} + diff --git a/src/rhusb/rhusb.hpp b/src/rhusb/rhusb.hpp index ba3d08f0..66059bb1 100644 --- a/src/rhusb/rhusb.hpp +++ b/src/rhusb/rhusb.hpp @@ -26,6 +26,10 @@ #include #include +#include "iTemperatureSensor.hpp" +#include "iHumiditySensor.hpp" +#include "iMraa.hpp" + namespace upm { /** @@ -53,7 +57,10 @@ namespace upm { * @snippet rhusb.cxx Interesting */ - class RHUSB { + class RHUSB : + public virtual iTemperatureSensor, + public virtual iHumiditySensor +{ public: /** * RHUSB constructor @@ -65,7 +72,13 @@ namespace upm { /** * RHUSB Destructor */ - ~RHUSB(); + virtual ~RHUSB() {}; + + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map TemperatureForSources(std::vector sources); + + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map HumidityForSources(std::vector sources); /** * Read current values from the sensor and update internal stored @@ -116,3 +129,8 @@ namespace upm { float m_humidity; }; } + +upm::RHUSB* upm_create(const std::string& init_str) +{ + return new upm::RHUSB(init_str); +} diff --git a/src/rhusb/rhusb.i b/src/rhusb/rhusb.i index f1e69d89..db2c3079 100644 --- a/src/rhusb/rhusb.i +++ b/src/rhusb/rhusb.i @@ -1,4 +1,5 @@ -%include "../common_top.i" +%include "iHumiditySensor.i" +%include "iTemperatureSensor.i" /* BEGIN Java syntax ------------------------------------------------------- */ #ifdef SWIGJAVA @@ -8,6 +9,14 @@ JAVA_JNI_LOADLIBRARY(javaupm_rhusb) #endif /* END Java syntax */ +/* BEGIN Javascript syntax ------------------------------------------------- */ +#ifdef SWIGJAVASCRIPT +INHERIT_IUPMOBJECT(upm::RHUSB); +INHERIT_IHUMIDITYSENSOR(upm::RHUSB); +INHERIT_ITEMPERATURESENSOR(upm::RHUSB); +#endif +/* END Javascript syntax */ + /* BEGIN Common SWIG syntax ------------------------------------------------- */ %{ #include "rhusb.hpp" diff --git a/src/rhusb/rhusb.json b/src/rhusb/rhusb.json index 2bbbab25..357cc027 100644 --- a/src/rhusb/rhusb.json +++ b/src/rhusb/rhusb.json @@ -15,6 +15,20 @@ "Node.js": ["rhusb.js"], "C++": ["rhusb.cxx"] }, + "Sources" : { + "temperature": { + "unit": "C", + "min" : -17, + "max" : 49, + "accuracy" : 1 + }, + "humidity-relative": { + "unit": "%", + "min" : 2, + "max" : 98, + "accuracy" : 3 + } + }, "Specifications": { "Vsource": { "unit": "V", @@ -25,36 +39,12 @@ "unit": "°C", "min": -40, "max": 85 - }, - "Temperature": { - "Effective Range": { - "unit": "°C", - "min" : -17, - "max" : 49 - }, - "Accuracy": { - "unit": "°C", - "min" : -1, - "max" : 1 - } - }, - "Relative Humidity": { - "Effective Range": { - "unit": "RH", - "min" : "2%", - "max" : "98%" - }, - "Accuracy": { - "unit": "RH", - "min" : "-3%", - "max" : "3%" - } } - }, - "Urls": { - "Product Pages": ["http://www.omega.com/pptst/RH-USB.html"], - "Datasheets": ["http://www.omega.com/das/pdf/RH-USB.pdf"] } + }, + "Urls": { + "Product Pages": ["http://www.omega.com/pptst/RH-USB.html"], + "Datasheets": ["http://www.omega.com/das/pdf/RH-USB.pdf"] } } } diff --git a/src/servo/CMakeLists.txt b/src/servo/CMakeLists.txt index 592c33dc..91800bd8 100644 --- a/src/servo/CMakeLists.txt +++ b/src/servo/CMakeLists.txt @@ -6,4 +6,4 @@ upm_mixed_module_init (NAME servo CPP_SRC servo.cxx es08a.cxx es9257.cxx FTI_SRC es08a_fti.c es9257_fti.c CPP_WRAPS_C - REQUIRES mraa utilities-c) + REQUIRES mraa utilities-c core) diff --git a/src/servo/es08a.cxx b/src/servo/es08a.cxx index eab14c9f..ceab6e02 100644 --- a/src/servo/es08a.cxx +++ b/src/servo/es08a.cxx @@ -29,13 +29,27 @@ using namespace upm; -ES08A::ES08A (int pin) : Servo(pin) { - m_name = "ES08A"; - m_maxAngle = 180.0; - m_minPulseWidth = 600; - m_maxPulseWidth = 2200; + +ES08A::ES08A (std::string init_str): Servo(init_str) +{ + DEBUG_MSG("XXX"); + + m_min_pw_us = 600; + m_max_pw_us = 2200; + m_period_us = 20000; + m_max_angle = 180; + + /* iMraa string constructor parses Mraa types, left-overs need + * additional parsing */ + if (_pwm.empty()) + throw std::runtime_error(std::string(__FUNCTION__) + + ": One PWM pin is required."); +} + +ES08A::ES08A (int pin) : ES08A(std::to_string(pin)) { + DEBUG_MSG("XXX"); } ES08A::~ES08A() { - + DEBUG_MSG("XXX"); } diff --git a/src/servo/es08a.hpp b/src/servo/es08a.hpp index 856c820a..06db0ce4 100644 --- a/src/servo/es08a.hpp +++ b/src/servo/es08a.hpp @@ -52,6 +52,8 @@ namespace upm { */ class ES08A : public Servo { public: + ES08A (std::string); + /** * Instantiates an ES08A object * @@ -65,4 +67,9 @@ namespace upm { ~ES08A (); }; +ES08A * es08a_create(const char* init_str) +{ + return new ES08A(init_str); +} + } diff --git a/src/servo/es9257.cxx b/src/servo/es9257.cxx index 6f55d451..921787e5 100644 --- a/src/servo/es9257.cxx +++ b/src/servo/es9257.cxx @@ -29,13 +29,15 @@ using namespace upm; -ES9257::ES9257 (int pin) : Servo(pin) { - m_name = "ES9257"; - m_maxAngle = 180.0; - m_minPulseWidth = 475; - m_maxPulseWidth = 2100; -} +ES9257::ES9257 (int pin) : Servo(pin, 475, 2100) {} -ES9257::~ES9257() { +ES9257::~ES9257() {} +ES9257::ES9257 (const char* init_str): Servo(init_str) +{ + /* iMraa string constructor parses Mraa types, left-overs need + * additional parsing */ + if (_pwm.empty()) + throw std::runtime_error(std::string(__FUNCTION__) + + ": One PWM pin is required."); } diff --git a/src/servo/es9257.hpp b/src/servo/es9257.hpp index 793dde88..7b779148 100644 --- a/src/servo/es9257.hpp +++ b/src/servo/es9257.hpp @@ -47,7 +47,7 @@ namespace upm { * * @image html es9257.jpg */ - class ES9257 : public Servo { +class ES9257 : public Servo { public: /** * Instantiates an ES9257 object @@ -56,10 +56,17 @@ namespace upm { */ ES9257 (int pin); + ES9257(const char* init_str); + /** * ES9257 object destructor */ ~ES9257 (); }; +ES9257 * es9257_create(const char* init_str) +{ + return new ES9257(init_str); +} + } diff --git a/src/servo/servo.cxx b/src/servo/servo.cxx index 9ed031db..8dd976a6 100644 --- a/src/servo/servo.cxx +++ b/src/servo/servo.cxx @@ -34,21 +34,27 @@ using namespace upm; -Servo::Servo (int pin) { - init(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH, DEFAULT_WAIT_DISABLE_PWM); +Servo::Servo (std::string mraa_init_str):iMraa(mraa_init_str) { + DEBUG_MSG("XXX"); } -Servo::Servo (int pin, int minPulseWidth, int maxPulseWidth) { - init(pin, minPulseWidth, maxPulseWidth, DEFAULT_WAIT_DISABLE_PWM); +Servo::Servo (int pin, int min_pw_us, int max_pw_us, + int period_us, float max_angle): Servo("p:" + std::to_string(pin)) { + DEBUG_MSG("XXX"); + + m_min_pw_us = min_pw_us; + m_max_pw_us = max_pw_us; + m_period_us = period_us; + m_max_angle = max_angle; } -Servo::Servo (int pin, int minPulseWidth, int maxPulseWidth, int waitAndDisablePwm) { - init(pin, minPulseWidth, maxPulseWidth, waitAndDisablePwm); -} Servo::~Servo () { - haltPwm(); - mraa_pwm_close (m_pwmServoContext); + DEBUG_MSG("XXX"); + + /* On a clean exit, disable the target PWM */ + if (!_pwm.empty()) + _pwm.front()->enable(false); } /* @@ -57,14 +63,14 @@ Servo::~Servo () { * X usec * _______ * |_______________________________________ - * m_period usec + * m_period_us usec * * */ mraa_result_t Servo::setAngle (int angle) { - if (angle > m_maxAngle || angle < 0) { + if (angle > m_max_angle || angle < 0) { // C++11 std::to_string() would be nice, but... std::ostringstream str; - str << m_maxAngle; + str << m_max_angle; throw std::out_of_range(std::string(__FUNCTION__) + ": angle must be between 0 and " + str.str()); @@ -72,21 +78,21 @@ mraa_result_t Servo::setAngle (int angle) { return MRAA_ERROR_UNSPECIFIED; } - mraa_pwm_enable (m_pwmServoContext, 1); - mraa_pwm_period_us (m_pwmServoContext, m_period); - mraa_pwm_pulsewidth_us (m_pwmServoContext, calcPulseTraveling(angle)); + _pwm.front()->enable(true); + _pwm.front()->period_us(m_period_us); + _pwm.front()->pulsewidth_us(calcPulseTraveling(angle)); - if (m_waitAndDisablePwm) { - sleep(1); // we must make sure that we don't turn off PWM before the servo is done moving. - haltPwm(); - } - - m_currAngle = angle; return MRAA_SUCCESS; } -mraa_result_t Servo::haltPwm () { - return mraa_pwm_enable (m_pwmServoContext, 0); +void Servo::AngleForCommands(std::map commands) +{ + for(std::map::const_iterator it = commands.begin(); + it != commands.end(); ++it) + { + if (std::find(Commands().begin(), Commands().end(), it->first) != Commands().end()) + setAngle(it->second); + } } /* @@ -94,71 +100,45 @@ mraa_result_t Servo::haltPwm () { * */ int Servo::calcPulseTraveling (int value) { // if bigger than the boundaries - if (value > m_maxAngle) { - return m_maxPulseWidth; + if (value > m_max_angle) { + return m_max_pw_us; } // if less than the boundaries if (value < 0) { - return m_minPulseWidth; + return m_min_pw_us; } // the conversion - return (int) ((float)m_minPulseWidth + ((float)value / m_maxAngle) * ((float)m_maxPulseWidth - (float)m_minPulseWidth)); + return (int) ((float)m_min_pw_us + ((float)value / m_max_angle) * ((float)m_max_pw_us - (float)m_min_pw_us)); } void Servo::setMinPulseWidth (int width) { - m_minPulseWidth = width; + m_min_pw_us = width; } void Servo::setMaxPulseWidth (int width) { - m_maxPulseWidth = width; + m_max_pw_us = width; } void Servo::setPeriod (int period) { - m_period = period; + m_period_us = period; } int Servo::getMinPulseWidth () { - return m_minPulseWidth; + return m_min_pw_us; } int Servo::getMaxPulseWidth () { - return m_maxPulseWidth; + return m_max_pw_us; } int Servo::getPeriod () { - return m_period; -} - -/** - * private mathod: would like to use delegating constructors instead but that requires C++11 - */ -void -Servo::init (int pin, int minPulseWidth, int maxPulseWidth, int waitAndDisablePwm) { - m_minPulseWidth = minPulseWidth; - m_maxPulseWidth = maxPulseWidth; - m_period = PERIOD; - - m_waitAndDisablePwm = waitAndDisablePwm; - - m_maxAngle = 180.0; - m_servoPin = pin; - - if ( !(m_pwmServoContext = mraa_pwm_init (m_servoPin)) ) - { - throw std::invalid_argument(std::string(__FUNCTION__) + - ": mraa_pwm_init() failed, invalid pin?"); - return; - } - - m_currAngle = 180; - - setAngle (0); + return m_period_us; } diff --git a/src/servo/servo.hpp b/src/servo/servo.hpp index 490789ae..806e0015 100644 --- a/src/servo/servo.hpp +++ b/src/servo/servo.hpp @@ -24,18 +24,16 @@ #pragma once #include -#include + +#include "iMraa.hpp" +#include "iServoActuator.hpp" namespace upm { -#define MIN_PULSE_WIDTH 600 -#define MAX_PULSE_WIDTH 2500 -#define PERIOD 20000 - #define HIGH 1 #define LOW 0 -#define DEFAULT_WAIT_DISABLE_PWM 0 +#define DEFAULT_WAIT_DISABLE_PWM false /** * @brief Servo Library @@ -47,34 +45,24 @@ namespace upm { * @defgroup servo libupm-servo * @ingroup seeed emax pwm servos gsk */ -class Servo { +class Servo : public iServoActuator, public iMraa { public: - /** - * Instantiates a Servo object - * - * @param pin Servo pin number - */ - Servo (int pin); + + /* Default constructor */ + Servo(std::string mraa_init_str); /** * Instantiates a Servo object * * @param pin Servo pin number - * @param minPulseWidth Minimum pulse width, in microseconds - * @param maxPulseWidth Maximum pulse width, in microseconds + * @param min_pw_us Minimum pulse width, in microseconds + * @param max_pw_us Maximum pulse width, in microseconds */ - Servo (int pin, int minPulseWidth, int maxPulseWidth); - - /** - * Instantiates a Servo object - * - * @param pin Servo pin number - * @param minPulseWidth Minimum pulse width, in microseconds - * @param maxPulseWidth Maximum pulse width, in microseconds - * @param waitAndDisablePwm If 1, PWM is enabled only during the setAngle() execution - * for a period of 1 second, and then turned back off. If 0, PWM remains on afterward. - */ - Servo (int pin, int minPulseWidth, int maxPulseWidth, int waitAndDisablePwm); + Servo (int pin, + int min_pw_us = 600, + int max_pw_us = 2500, + int period_us = 20000, + float max_angle = 180.0); /** * Servo object destructor @@ -89,20 +77,7 @@ class Servo { */ mraa_result_t setAngle (int angle); - /** - * Halts PWM for this servo and allows it to move freely. - */ - mraa_result_t haltPwm (); - - /** - * Returns the name of the component - * - * @return Name of the component - */ - std::string name() - { - return m_name; - } + virtual void AngleForCommands(std::map commands); /** * Sets the minimum pulse width @@ -125,6 +100,11 @@ class Servo { */ void setPeriod (int period); + void setMaxAngle(float angle_degrees) + { + m_max_angle = angle_degrees; + } + /** * Returns the minimum pulse width * @@ -149,20 +129,9 @@ class Servo { protected: int calcPulseTraveling (int value); - std::string m_name; - int m_servoPin; - float m_maxAngle; - mraa_pwm_context m_pwmServoContext; - int m_currAngle; - - int m_minPulseWidth; - int m_maxPulseWidth; - int m_period; - - int m_waitAndDisablePwm; - - private: - void init (int pin, int minPulseWidth, int maxPulseWidth, int waitAndDisablePwm); + int m_min_pw_us; + int m_max_pw_us; + int m_period_us; + float m_max_angle; }; - } diff --git a/src/servo/servo.i b/src/servo/servo.i index b9ed6354..9643aff7 100644 --- a/src/servo/servo.i +++ b/src/servo/servo.i @@ -1,4 +1,5 @@ -%include "../common_top.i" +%include "iMraa.i" +%include "iServoActuator.i" /* BEGIN Java syntax ------------------------------------------------------- */ #ifdef SWIGJAVA @@ -8,8 +9,8 @@ JAVA_JNI_LOADLIBRARY(javaupm_servo) /* BEGIN Common SWIG syntax ------------------------------------------------- */ %{ -#include "es08a.hpp" #include "servo.hpp" +#include "es08a.hpp" #include "es9257.hpp" %} %include "servo.hpp" diff --git a/src/servo/servo.json b/src/servo/servo.json index f2d8cfd9..5b87970b 100644 --- a/src/servo/servo.json +++ b/src/servo/servo.json @@ -18,6 +18,14 @@ "Node.js": ["es08a.js"], "C++": ["servo-es08a.cxx"] }, + "Commands" : { + "axis0": { + "unit": "degrees", + "min" : 0.0, + "max" : 180.0, + "accuracy" : 1.0 + } + }, "Specifications": { "Vsource": { "unit": "V", @@ -62,6 +70,13 @@ "Node.js": ["es08a.js"], "C++": ["servo-es08a.cxx"] }, + "Commands" : { + "axis0": { + "unit": "degrees", + "min" : 0.0, + "max" : 180.0 + } + }, "Specifications": { "Vsource": { "unit": "V", @@ -89,7 +104,7 @@ "Product Pages": ["https://www.seeedstudio.com/EMAX-ES9257-2.5kg%26amp%3B-.05-sec-Micro-Digital-3D-Tail-Servo-p-762.html"] } }, - "servo": { + "Servo": { "Name": "Servo library", "Description": "This is the UPM Module for the Servo library. The base Servo class provides routines for setting the angle of the shaft as well as setting and getting the minimum and maximum pulse width and the maximum period.", "Aliases": ["servo"], diff --git a/src/si1132/CMakeLists.txt b/src/si1132/CMakeLists.txt index bada7ce4..22699393 100644 --- a/src/si1132/CMakeLists.txt +++ b/src/si1132/CMakeLists.txt @@ -2,4 +2,4 @@ set (libname "si1132") set (libdescription "UV and Ambient Light Sensor") set (module_src ${libname}.cxx) set (module_hpp ${libname}.hpp) -upm_module_init(mraa interfaces) +upm_module_init(mraa core) diff --git a/src/si1132/si1132.cxx b/src/si1132/si1132.cxx index 541d39d7..75be535e 100644 --- a/src/si1132/si1132.cxx +++ b/src/si1132/si1132.cxx @@ -81,7 +81,9 @@ SI1132::SI1132 (int bus) { // Reset chip to defaults status = reset(); if (status != mraa::SUCCESS) - UPM_THROW("config failure"); + throw std::runtime_error(std::string(__FUNCTION__) + " : config failure"); + + AddSource("light", "lux"); } SI1132::~SI1132() { @@ -138,7 +140,7 @@ mraa::Result SI1132::reset() { uint16_t SI1132::getVisibleRaw() { status = runCommand(SI1132_COMMAND_ALS_FORCE); if (status != mraa::SUCCESS) - UPM_THROW("command failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : command failed"); return i2c->readWordReg(SI1132_REG_ALS_VIS_DATA0); } @@ -221,3 +223,13 @@ void SI1132::sleepMs(int mseconds) // value of the seconds parameter while ( ( nanosleep( &sleepTime, &sleepTime ) != 0 ) && ( errno == EINTR ) ); } + +std::map SI1132::LightForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "light") != sources.end()) + ret["light"] = getVisibleLux(); + + return ret; +} diff --git a/src/si1132/si1132.hpp b/src/si1132/si1132.hpp index 29524def..029878a8 100644 --- a/src/si1132/si1132.hpp +++ b/src/si1132/si1132.hpp @@ -25,7 +25,7 @@ #include #include "mraa/i2c.hpp" -#include "interfaces/iLightSensor.hpp" +#include "iLightSensor.hpp" namespace upm { @@ -56,7 +56,7 @@ namespace upm { * * @snippet si1132.cxx Interesting */ -class SI1132 : public ILightSensor { +class SI1132 : public iLightSensor { public: /** * Instanciates a Si1132 object @@ -80,7 +80,14 @@ class SI1132 : public ILightSensor { */ double getVisibleLux(); - virtual const char* getModuleName() { return "si1132"; } + /** Return the name of this device */ + virtual std::string Name () {return "SI1132";} + + /** Return the description of this device */ + virtual std::string Description () {return "UV and ambient light sensor";} + + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map LightForSources(std::vector sources); private: /* Disable implicit copy and assignment operators */ diff --git a/src/si1132/si1132.i b/src/si1132/si1132.i index 94f0d4b7..a6e47dc0 100644 --- a/src/si1132/si1132.i +++ b/src/si1132/si1132.i @@ -1,4 +1,5 @@ %include "../common_top.i" +%include "iLightSensor.i" /* BEGIN Java syntax ------------------------------------------------------- */ #ifdef SWIGJAVA @@ -6,9 +7,6 @@ %module(directors="1") javaupm_si1132 #endif -%typemap(javaimports) SWIGTYPE %{import upm_interfaces.*;%} -%import "../interfaces/javaupm_iLightSensor.i" - JAVA_JNI_LOADLIBRARY(javaupm_si1132) #endif /* END Java syntax */ diff --git a/src/si7005/CMakeLists.txt b/src/si7005/CMakeLists.txt index 770c6d4b..9c5a6299 100644 --- a/src/si7005/CMakeLists.txt +++ b/src/si7005/CMakeLists.txt @@ -1,5 +1,5 @@ -set (libname "si7005") -set (libdescription "Digital I2C Humidity and Temperature Sensor") -set (module_src ${libname}.cxx mraa-utils.cxx) -set (module_hpp ${libname}.hpp) -upm_module_init(mraa interfaces) +upm_mixed_module_init (NAME si7005 + DESCRIPTION "Digital I2C Humidity and Temperature Sensor" + CPP_HDR si7005.hpp + CPP_SRC si7005.cxx + REQUIRES mraa core utilities-c) diff --git a/src/si7005/mraa-utils.cxx b/src/si7005/mraa-utils.cxx index 4d235106..fcb7bbd2 100644 --- a/src/si7005/mraa-utils.cxx +++ b/src/si7005/mraa-utils.cxx @@ -45,7 +45,7 @@ void MraaUtils::setGpio(int pin, int level) mraa::Gpio gpio(pin); gpio.dir(mraa::DIR_OUT); if (gpio.write(level) != mraa::SUCCESS) - UPM_THROW("gpio write failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : gpio write failed"); } diff --git a/src/si7005/si7005.cxx b/src/si7005/si7005.cxx index 7f6765ba..e338df46 100644 --- a/src/si7005/si7005.cxx +++ b/src/si7005/si7005.cxx @@ -69,24 +69,27 @@ using namespace upm; -SI7005::SI7005 (int bus, int pin) { +SI7005::SI7005 (const std::string &init_string): + iMraa(init_string), + config_reg(SI7005_CONFIG_RESET), + last_temperature(25) +{ + /* Test for the correct resources */ + if (_i2c.size() < 1) + throw std::runtime_error(std::string(__FUNCTION__) + + " : this devices requires 1 I2c bus. " + Connections()); - m_controlAddr = SI7005_ADDRESS; - m_bus = bus; - m_pin = pin; - last_temperature = 25.0; - config_reg = SI7005_CONFIG_RESET; + if (_gpio.size() < 1) + throw std::runtime_error(std::string(__FUNCTION__) + + " : this devices requires 1 Gpio pin. " + Connections()); - // Disable chip until we need to do something with it - MraaUtils::setGpio(m_pin, 1); - m_i2c = new mraa::I2c(m_bus); - status = m_i2c->address(m_controlAddr); + /* Test to see if the sensor responds */ if (!isAvailable()) - UPM_THROW("config failure"); -} + throw std::runtime_error(std::string(__FUNCTION__) + " : device is not available"); -SI7005::~SI7005() { - delete m_i2c; + /* Setup the sources available for this sensor */ + AddSource("temperature", "C"); + AddSource("humidity-relative", "%"); } uint16_t @@ -125,31 +128,31 @@ uint16_t SI7005::getMeasurement(uint8_t configValue) { uint8_t measurementStatus; // Enable the sensor - MraaUtils::setGpio(m_pin, 0); + _gpio[0]->write(0); // Wait for sensor to wake up usleep(SI7005_WAKE_UP_TIME); // Setup config register - status = m_i2c->writeReg(SI7005_REG_CONFIG, SI7005_CONFIG_START | configValue | config_reg); + status = _i2c[0]->writeReg(SI7005_REG_CONFIG, SI7005_CONFIG_START | configValue | config_reg); // FIXME: readReg() returns 0 on failure which is same as "reading ready" status // FIXME: no timeout if device never gets to "reading ready" status // Wait for the measurement to finish measurementStatus = SI7005_STATUS_NOT_READY; while ( measurementStatus == SI7005_STATUS_NOT_READY ) { - measurementStatus = m_i2c->readReg(SI7005_REG_STATUS); + measurementStatus = _i2c[0]->readReg(SI7005_REG_STATUS); } // Read data registers - int length = m_i2c->readBytesReg(SI7005_REG_DATA_START, data, SI7005_REG_DATA_LENGTH); + int length = _i2c[0]->readBytesReg(SI7005_REG_DATA_START, data, SI7005_REG_DATA_LENGTH); // Disable the sensor - MraaUtils::setGpio(m_pin, 1); + _gpio[0]->write(1); // Check we got the data we need if(length != SI7005_REG_DATA_LENGTH) - UPM_THROW("read error"); + throw std::runtime_error(std::string(__FUNCTION__) + " : read error"); // Merge MSB and LSB rawData = ((uint16_t)( data[SI7005_REG_DATA_LOW] & 0xFFFF )) + ( (uint16_t)(( data[SI7005_REG_DATA_HIGH] & 0xFFFF ) << 8 )); @@ -162,16 +165,24 @@ bool SI7005::isAvailable( ) { // Enable the sensor - MraaUtils::setGpio(m_pin, 0); + _gpio[0]->write(0); // Wait for sensor to wake up usleep(SI7005_WAKE_UP_TIME); // Read id register - uint8_t deviceID = m_i2c->readReg(SI7005_REG_ID); + uint8_t deviceID = 0; + try { deviceID = _i2c[0]->readReg(SI7005_REG_ID); } + catch (...) + { + std::cerr << "Failed to read from SI7005 device ID register" << std::endl; + // Disable the sensor + _gpio[0]->write(1); + return false; + } // Disable the sensor - MraaUtils::setGpio(m_pin, 1); + _gpio[0]->write(1); return (( deviceID & SI7005_ID) == SI7005_ID ); } @@ -199,3 +210,24 @@ SI7005::disableFastConversionMode( ) { config_reg ^= SI7005_CONFIG_FAST; } + +std::map SI7005::TemperatureForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "temperature") != sources.end()) + ret["temperature"] = getTemperatureCelsius(); + + return ret; +} + +std::map SI7005::HumidityForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "humidity-relative") != sources.end()) + ret["humidity-relative"] = getHumidityRelative(); + + return ret; +} + diff --git a/src/si7005/si7005.hpp b/src/si7005/si7005.hpp index a121f721..187ebf28 100644 --- a/src/si7005/si7005.hpp +++ b/src/si7005/si7005.hpp @@ -25,8 +25,9 @@ #include -#include "interfaces/iTemperatureSensor.hpp" -#include "interfaces/iHumiditySensor.hpp" +#include "iTemperatureSensor.hpp" +#include "iHumiditySensor.hpp" +#include "iMraa.hpp" /* ADDRESS AND NOT_FOUND VALUE */ #define SI7005_ADDRESS ( 0x40 ) @@ -59,20 +60,37 @@ namespace upm { * * @snippet si7005.cxx Interesting */ -class SI7005 : public ITemperatureSensor, public IHumiditySensor { +class SI7005 : + public virtual iMraa, + public virtual iTemperatureSensor, + public virtual iHumiditySensor { public: + SI7005(const std::string &init_string); + /** * Instantiates a SI7005 object * - * @param bus number of used bus * @param pin gpio number for chip select pin + * @param bus I2c bus number + * @param addr (optional) I2c address, defaults to SI7005_ADDRESS */ - SI7005 (int bus, int pin); + SI7005(int pin, int bus, int addr = SI7005_ADDRESS): + SI7005("g:" + std::to_string(pin) + ":out," + + "i:" + std::to_string(bus) + ":" + std::to_string(addr)) {} - /** - * SI7005 object destructor. - */ - ~SI7005 (); + virtual ~SI7005() {} + + /** Return the name of this device */ + virtual std::string Name () {return "SI7005";} + + /** Return the description of this device */ + virtual std::string Description () {return "Digital I2C humidity and temperature sensor";} + + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map TemperatureForSources(std::vector sources); + + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map HumidityForSources(std::vector sources); /** * Get temperature measurement. @@ -95,12 +113,10 @@ class SI7005 : public ITemperatureSensor, public IHumiditySensor { int getHumidityRelative (); /** - * Returns sensor module name - */ - virtual const char* getModuleName() { return "si7005"; } - - /** - * Detects the sensor to ensure it is connected as required. + * Reads from the device ID register as a means to verify the + * sensor is connected. + * + * @return true if sensor ID register read succeeds, false otherwise */ bool isAvailable(); @@ -129,10 +145,6 @@ class SI7005 : public ITemperatureSensor, public IHumiditySensor { SI7005(const SI7005&) = delete; SI7005 &operator=(const SI7005&) = delete; - int m_controlAddr; - int m_bus; - int m_pin; - mraa::I2c* m_i2c; mraa::Result status; uint8_t config_reg; float last_temperature; diff --git a/src/si7005/si7005.i b/src/si7005/si7005.i index cf15e116..ca7fa8a2 100644 --- a/src/si7005/si7005.i +++ b/src/si7005/si7005.i @@ -1,14 +1,12 @@ %include "../common_top.i" +%include "iMraa.i" +%include "iHumiditySensor.i" +%include "iTemperatureSensor.i" /* BEGIN Java syntax ------------------------------------------------------- */ #ifdef SWIGJAVA %include "arrays_java.i"; %include "../java_buffer.i" -%typemap(javaimports) SWIGTYPE %{import upm_interfaces.*;%} - -%import "../interfaces/javaupm_iTemperatureSensor.i" -%import "../interfaces/javaupm_iHumiditySensor.i" - JAVA_JNI_LOADLIBRARY(javaupm_si7005) #endif /* END Java syntax */ diff --git a/src/t6713/CMakeLists.txt b/src/t6713/CMakeLists.txt index 339ad915..3198686f 100644 --- a/src/t6713/CMakeLists.txt +++ b/src/t6713/CMakeLists.txt @@ -2,4 +2,4 @@ set (libname "t6713") set (libdescription "I2C/UART High Accuracy CO2 Sensor") set (module_src ${libname}.cxx) set (module_hpp ${libname}.hpp) -upm_module_init(mraa interfaces) +upm_module_init(mraa core) diff --git a/src/t6713/t6713.cxx b/src/t6713/t6713.cxx index eb23f5c9..2c6ee9bc 100644 --- a/src/t6713/t6713.cxx +++ b/src/t6713/t6713.cxx @@ -56,7 +56,9 @@ T6713::T6713 (int bus) : i2c(bus) status = i2c.address(T6713_ADDR); uint16_t firmwareRevision = getFirmwareRevision(); if (firmwareRevision != mraa::SUCCESS) - UPM_THROW("config failure"); + throw std::runtime_error(std::string(__FUNCTION__) + " : config failure"); + + AddSource("CO2", "ppm"); } uint16_t T6713::getFirmwareRevision() @@ -76,16 +78,16 @@ uint16_t T6713::getSensorData (MODBUS_COMMANDS cmd) switch(currStatus = getStatus()) /* handle error conditions */ { case ERROR_CONDITION: - UPM_THROW ("error condition"); + throw std::runtime_error(std::string(__FUNCTION__) + " : error condition"); break; case FLASH_ERROR: - UPM_THROW ("flash error"); + throw std::runtime_error(std::string(__FUNCTION__) + " : flash error"); break; case CALIBRATION_ERROR: - UPM_THROW ("calibration error"); + throw std::runtime_error(std::string(__FUNCTION__) + " : calibration error"); break; case WARMUP_MODE: - //UPM_THROW ("warmup mode"); + //throw std::runtime_error(std::string(__FUNCTION__) + " : warmup mode"); break; case RS232: //printf("\nRS232 mode set\n "); @@ -101,7 +103,7 @@ uint16_t T6713::getSensorData (MODBUS_COMMANDS cmd) RESPONSE response; if((readBytes = i2c.read((uint8_t*)(&response), sizeof(RESPONSE) ) != sizeof(RESPONSE))) { - UPM_THROW("I2C read failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : I2C read failed"); // TODO } if(response.function_code == READ_INPUT_REGISTERS) @@ -149,7 +151,7 @@ mraa::Result T6713::runCommand(MODBUS_COMMANDS cmd) if((ret = i2c.write((const uint8_t*) (&cmdPacket), sizeof(COMMAND))) != mraa::SUCCESS) { - UPM_THROW("I2C write failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : I2C write failed"); } @@ -172,7 +174,7 @@ mraa::Result T6713::runCommand(MODBUS_COMMANDS cmd) if((ret = i2c.write((const uint8_t*) (&cmdPacket), sizeof(COMMAND))) != mraa::SUCCESS) { - UPM_THROW("I2C write failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : I2C write failed"); } break; @@ -189,7 +191,7 @@ STATUS T6713::getStatus() runCommand(T6713_COMMAND_STATUS); if((readBytes = i2c.read((uint8_t*) (&response), sizeof(RESPONSE)) != sizeof(RESPONSE))) { - UPM_THROW("I2C read failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : I2C read failed"); } if(response.function_code == READ_INPUT_REGISTERS) @@ -200,13 +202,13 @@ STATUS T6713::getStatus() } else { - UPM_THROW("I2C read failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : I2C read failed"); } } else { - UPM_THROW("MODBUS function code failed"); + throw std::runtime_error(std::string(__FUNCTION__) + " : MODBUS function code failed"); } if(responseStatus & 0x0001) @@ -242,3 +244,13 @@ STATUS T6713::getStatus() return I2C; } } + +std::map T6713::CO2ForSources(std::vector sources) +{ + std::map ret; + + if (std::find(sources.begin(), sources.end(), "CO2") != sources.end()) + ret["CO2"] = getPpm(); + + return ret; +} diff --git a/src/t6713/t6713.hpp b/src/t6713/t6713.hpp index 9f4533d0..b73bdce6 100644 --- a/src/t6713/t6713.hpp +++ b/src/t6713/t6713.hpp @@ -24,7 +24,7 @@ #include "mraa/i2c.hpp" -#include "interfaces/iCO2Sensor.hpp" +#include "iCO2Sensor.hpp" namespace upm { /** @@ -104,7 +104,7 @@ namespace t6713_co2 }FUNCTION_CODES; }//namespace t6713_co2 -class T6713 : public ICO2Sensor { +class T6713 : public iCO2Sensor { public: /** * Instantiates a T6713 object @@ -118,11 +118,6 @@ class T6713 : public ICO2Sensor { */ virtual ~T6713 () {}; - /** - * Returns sensor module name - */ - virtual const char* getModuleName() { return "t6713"; } - /** * Get relative humidity measurement. */ @@ -132,6 +127,14 @@ class T6713 : public ICO2Sensor { */ uint16_t getFirmwareRevision(); + /** Return the name of this device */ + virtual std::string Name () {return "T6713";} + + /** Return the description of this device */ + virtual std::string Description () {return "I2C/UART high accuracy CO2 sensor";} + + /* Provide an implementation of a method to get sensor values by source */ + virtual std::map CO2ForSources(std::vector sources); private: mraa::Result runCommand(t6713_co2::MODBUS_COMMANDS command); diff --git a/src/t6713/t6713.i b/src/t6713/t6713.i index 56db9741..89306f11 100644 --- a/src/t6713/t6713.i +++ b/src/t6713/t6713.i @@ -1,12 +1,10 @@ %include "../common_top.i" +%include "iCO2Sensor.i" /* BEGIN Java syntax ------------------------------------------------------- */ #ifdef SWIGJAVA %include "arrays_java.i"; %include "../java_buffer.i" -%typemap(javaimports) SWIGTYPE %{import upm_interfaces.*;%} -%import "../interfaces/javaupm_iCO2Sensor.i" - JAVA_JNI_LOADLIBRARY(javaupm_t6713) #endif /* END Java syntax */ diff --git a/src/upm_exception.i b/src/upm_exception.i index 2d12fe35..20cbd2c5 100644 --- a/src/upm_exception.i +++ b/src/upm_exception.i @@ -4,8 +4,11 @@ * specific. */ -%{#include %} -%include "exception.i" +%include + +%{ +#include +%} %exception { try { @@ -13,51 +16,51 @@ try { } catch (std::invalid_argument& e) { std::string s1("UPM Invalid Argument: "), s2(e.what()); s1 = s1 + s2; - SWIG_exception(SWIG_ValueError, s1.c_str()); + SWIG_exception_fail(SWIG_ValueError, s1.c_str()); } catch (std::domain_error& e) { std::string s1("UPM Domain Error: "), s2(e.what()); s1 = s1 + s2; - SWIG_exception(SWIG_ValueError, s1.c_str() ); + SWIG_exception_fail(SWIG_ValueError, s1.c_str() ); } catch (std::overflow_error& e) { std::string s1("UPM Overflow Error: "), s2(e.what()); s1 = s1 + s2; - SWIG_exception(SWIG_OverflowError, s1.c_str() ); + SWIG_exception_fail(SWIG_OverflowError, s1.c_str() ); } catch (std::out_of_range& e) { std::string s1("UPM Out of Range: "), s2(e.what()); s1 = s1 + s2; - SWIG_exception(SWIG_IndexError, s1.c_str() ); + SWIG_exception_fail(SWIG_IndexError, s1.c_str() ); } catch (std::length_error& e) { std::string s1("UPM Length Error: "), s2(e.what()); s1 = s1 + s2; - SWIG_exception(SWIG_IndexError, s1.c_str() ); + SWIG_exception_fail(SWIG_IndexError, s1.c_str() ); } catch (std::logic_error& e) { std::string s1("UPM Logic Error: "), s2(e.what()); s1 = s1 + s2; - SWIG_exception(SWIG_RuntimeError, s1.c_str() ); + SWIG_exception_fail(SWIG_RuntimeError, s1.c_str() ); } catch (std::bad_alloc& e) { /* for an allocation exception, don't try to create a string... */ - SWIG_exception(SWIG_MemoryError, e.what() ); + SWIG_exception_fail(SWIG_MemoryError, e.what() ); } catch (std::runtime_error& e) { /* catch other std::runtime_error exceptions here */ std::string s1("UPM Runtime Error: "), s2(e.what()); s1 = s1 + s2; - SWIG_exception(SWIG_RuntimeError, s1.c_str()); + SWIG_exception_fail(SWIG_RuntimeError, s1.c_str()); } catch (std::exception& e) { /* catch other std::exceptions here */ std::string s1("UPM Error: "), s2(e.what()); s1 = s1 + s2; - SWIG_exception(SWIG_SystemError, s1.c_str() ); + SWIG_exception_fail(SWIG_SystemError, s1.c_str() ); } catch (...) { /* catch everything else */ - SWIG_exception(SWIG_UnknownError, "UPM Unknown exception" ); + SWIG_exception_fail(SWIG_UnknownError, "UPM Unknown exception" ); } } diff --git a/src/upm_library_globals.cxx b/src/upm_library_globals.cxx new file mode 100644 index 00000000..63d42ec8 --- /dev/null +++ b/src/upm_library_globals.cxx @@ -0,0 +1,134 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "upm_library_globals.hpp" + +#define xstr(s) xxstr(s) +#define xxstr(s) #s + + +#define concat(A, B) A##B +#define define_upm_create(libname, blah) \ + void* concat(upm_create_,libname)(const char * init_str) \ +{ \ + return NULL; \ +} +define_upm_create(UPM_LIBRARY_BASE_NAME, someotherblah); + +/* + const char* LibraryBaseName() + { + return xstr(UPM_LIBRARY_BASE_NAME); + } + */ + +static std::string _libraryBaseName; +const char* LibraryBaseName() +{ + /* Has the library base name already been returned? */ + if (!_libraryBaseName.empty()) + return _libraryBaseName.c_str(); + + std::cmatch cm; + if (!std::regex_search(LibraryAbsolutePath(), cm, std::regex("libupm-(\\S+)\\.so"))) + return NULL; + + std::stringstream ss; + _libraryBaseName = cm.str(1); + + return _libraryBaseName.c_str(); +} + + +const char* LibraryVersion() +{ + return xstr(UPM_VERSION_STRING); +} + +static std::map _static_LibraryAbsolutePath; + +const char* LibraryAbsolutePathForType(void *Type) +{ + const std::type_info &this_type = typeid(&Type); + + /* If this has already been called, return the previous value */ + if (!_static_LibraryAbsolutePath[this_type.name()].empty()) + return _static_LibraryAbsolutePath[this_type.name()].c_str(); + + Dl_info info; + + /* Returns 0 on failure */ + if (!dladdr((const void*)&this_type, &info)) + return NULL; + + /* Attempt a realpath */ + _static_LibraryAbsolutePath[this_type.name()] = realpath(info.dli_fname, NULL); + + /* Let this method return a NULL */ + if (_static_LibraryAbsolutePath[this_type.name()].empty()) + return NULL; + + return _static_LibraryAbsolutePath[this_type.name()].c_str(); +} + +const char* LibraryAbsolutePath() +{ + return LibraryAbsolutePathForType((void*)LibraryAbsolutePath); +} + +std::string LibraryLocation() +{ + /* Split out the path */ + std::string full_path = LibraryAbsolutePath(); + std::size_t found = full_path.find_last_of("/\\"); + return full_path.substr(0,found); +} + +std::string DataDirectory() +{ + std::string lib_loc = LibraryLocation(); + + /* Is the library in the build directory or installed on the system? */ + if (lib_loc.find("build/src/" + std::string(LibraryBaseName())) != std::string::npos) + return lib_loc.substr(0, lib_loc.find("build/src/" + std::string(LibraryBaseName()))) + + "src/"; + else + return lib_loc.substr(0, lib_loc.find_last_of("/\\")) + "/share/upm"; +} + +static bool exists(const std::string& filename) +{ + std::ifstream f(filename.c_str()); + return f.good(); +} + +static std::string json_str; +const char* LibraryJson() +{ + /* Is there a library JSON definition? */ + std::string datadir = DataDirectory(); + + /* Let this method return a NULL */ + if (datadir.empty()) + return NULL; + + /* Attempt to build the path to the library JSON file */ + std::string json_file = datadir + std::string("/") + LibraryBaseName() + + std::string("/") + LibraryBaseName() + std::string(".json"); + + /* Make sure the file exists */ + if (!exists(json_file)) + return NULL; + + std::ifstream t(json_file); + json_str.assign((std::istreambuf_iterator(t)), + std::istreambuf_iterator()); + + return json_str.c_str(); +} diff --git a/src/upm_library_globals.hpp b/src/upm_library_globals.hpp new file mode 100644 index 00000000..3224c560 --- /dev/null +++ b/src/upm_library_globals.hpp @@ -0,0 +1,15 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char* LibraryBaseName(); +extern const char* LibraryVersion(); +extern const char* LibraryJson(); +extern const char* LibraryAbsolutePath(); +extern const char* LibraryAbsolutePathForType(void *Type); + +#ifdef __cplusplus +} +#endif diff --git a/src/vcap/CMakeLists.txt b/src/vcap/CMakeLists.txt index 83964db5..538f02b4 100644 --- a/src/vcap/CMakeLists.txt +++ b/src/vcap/CMakeLists.txt @@ -1,10 +1,7 @@ -set (libname "vcap") -set (libdescription "Video Frame Capture and Image Save Utility") -set (module_src ${libname}.cxx) -set (module_hpp ${libname}.hpp) - if (JPEG_FOUND) - set (reqlibname "jpeg") - upm_module_init() - target_link_libraries(${libname} jpeg) + upm_mixed_module_init (NAME vcap + DESCRIPTION "Video Frame Capture and Image Save Utility" + CPP_HDR vcap.hpp + CPP_SRC vcap.cxx + REQUIRES jpeg) endif() diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index e9878b1d..d30ff6f8 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -18,10 +18,29 @@ target_link_libraries(json_tests GTest::GTest GTest::Main) target_include_directories(json_tests PRIVATE "${UPM_COMMON_HEADER_DIRS}/") gtest_add_tests(json_tests "" AUTO) +# Unit tests - core library +add_executable(core_tests + core/iUpmObject_tests.cxx + + core/iSensortType_tests.cxx + + core/iActuatorType_tests.cxx + core/iServoActuator_tests.cxx + + core/sensortype_example.json + core/actuatortype_example.json) + +configure_file(core/sensortype_example.json sensortype_example.json COPYONLY) +configure_file(core/actuatortype_example.json actuatortype_example.json COPYONLY) + +target_link_libraries(core_tests core GTest::GTest GTest::Main) +gtest_add_tests(core_tests "" AUTO) + # Add a custom target for unit tests add_custom_target(tests-unit ALL DEPENDS utilities_tests json_tests + core_tests COMMENT "UPM unit test collection") diff --git a/tests/unit/core/actuatortype_example.json b/tests/unit/core/actuatortype_example.json new file mode 100644 index 00000000..25deb04d --- /dev/null +++ b/tests/unit/core/actuatortype_example.json @@ -0,0 +1,39 @@ +{ + "Library": "core_tests", + "Description": "Unit test JSON example", + "Sensor Class": { + "ServoTest": { + "Name": "This is a name", + "Description": "This is a description", + "Aliases": ["Alias blibbity", "Alias blah"], + "Categories": ["servo"], + "Connections": ["uart"], + "Project Type": ["industrial", "commercial"], + "Manufacturers": ["Omega"], + "Commands" : { + "axis0": { + "unit": "degrees", + "min" : 0.0, + "max" : 180.0, + "accuracy" : 1.0 + } + }, + "Specifications": { + "Vsource": { + "unit": "V", + "min": 5.0, + "max": 5.0 + }, + "Operating Temperature": { + "unit": "°C", + "min": -40, + "max": 85 + } + } + }, + "Urls": { + "Product Pages": ["http://www.omega.com/pptst/RH-USB.html"], + "Datasheets": ["http://www.omega.com/das/pdf/RH-USB.pdf"] + } + } +} diff --git a/tests/unit/core/iActuatorType_tests.cxx b/tests/unit/core/iActuatorType_tests.cxx new file mode 100644 index 00000000..fe2dd6b8 --- /dev/null +++ b/tests/unit/core/iActuatorType_tests.cxx @@ -0,0 +1,41 @@ +#include "gtest/gtest.h" +#include "iUpmObject.hpp" +#include "iActuatorType.hpp" +#include "iServoActuator.hpp" +#include "external/json/json.hpp" +#include + +/* Interfaces test fixture */ +class iActuatorType_unit : public ::testing::Test, public virtual upm::iActuatorType +{ +protected: + /* One-time setup logic if needed */ + iActuatorType_unit() + { + this->initFromJsonLibDesc("./actuatortype_example.json"); + } + + /* One-time tear-down logic if needed */ + virtual ~iActuatorType_unit() {} + + /* Per-test setup logic if needed */ + virtual void SetUp() {} + + /* Per-test tear-down logic if needed */ + virtual void TearDown() {} +}; + + +TEST_F(iActuatorType_unit, test_commands_deserialize) +{ + /* Deserialize the JSON to a map of commands */ + std::map> commands = + LibraryJson()["Sensor Class"]["ServoTest"]["Commands"]; + + ASSERT_EQ(1, commands.size()); + + ASSERT_TRUE(commands.find("axis0") != commands.end()); + ASSERT_EQ("degrees", commands["axis0"].unit); + ASSERT_EQ(0.0, commands["axis0"].min); + ASSERT_EQ(180.0, commands["axis0"].max); +} diff --git a/tests/unit/core/iSensortType_tests.cxx b/tests/unit/core/iSensortType_tests.cxx new file mode 100644 index 00000000..1f3d29c5 --- /dev/null +++ b/tests/unit/core/iSensortType_tests.cxx @@ -0,0 +1,70 @@ +#include "gtest/gtest.h" +#include "iUpmObject.hpp" +#include "iSensorType.hpp" +#include "iTemperatureSensor.hpp" +#include "external/json/json.hpp" +#include + + +/* Interfaces test fixture */ +class iSensorType_unit : public ::testing::Test, public virtual upm::iSensorType +{ +protected: + /* One-time setup logic if needed */ + iSensorType_unit() + { + this->initFromJsonLibDesc("./sensortype_example.json"); + } + + /* One-time tear-down logic if needed */ + virtual ~iSensorType_unit() {} + + /* Per-test setup logic if needed */ + virtual void SetUp() {} + + /* Per-test tear-down logic if needed */ + virtual void TearDown() {} + + //TestSensorClass& obj; +}; + + +TEST_F(iSensorType_unit, test_sources_deserialize) +{ + /* Deserialize the JSON to a map of sources */ + std::map> sources = + LibraryJson()["Sensor Class"]["TestSensorClass"]["Sources"]; + + ASSERT_EQ(2, sources.size()); + + ASSERT_TRUE(sources.find("temperature") != sources.end()); + ASSERT_TRUE(sources.find("humidity-relative") != sources.end()); + ASSERT_EQ("C", sources["temperature"].unit); + ASSERT_EQ(-17.0, sources["temperature"].min); + ASSERT_EQ(49.0, sources["temperature"].max); + ASSERT_EQ(1.0, sources["temperature"].accuracy); +} + + +TEST_F(iSensorType_unit, test_iTemperatureSensor) +{ + /* Mock RHUSB class */ + class RHUSB : public virtual upm::iTemperatureSensor + { + std::map TemperatureForSources(std::vector sources) + { + std::map fake_temps; + + if (std::find(sources.begin(), sources.end(), "temperature") != sources.end()) + fake_temps["temperature"] = 25.5; + + return fake_temps; + } + }; + + RHUSB ts; + ts.initFromJsonLibDesc("../../../src/rhusb/rhusb.json"); + + ASSERT_EQ(2, ts.Sources().size()); + ASSERT_EQ(25.5, ts.TemperatureForSource("temperature")); +} diff --git a/tests/unit/core/iServoActuator_tests.cxx b/tests/unit/core/iServoActuator_tests.cxx new file mode 100644 index 00000000..999e9c39 --- /dev/null +++ b/tests/unit/core/iServoActuator_tests.cxx @@ -0,0 +1,104 @@ +#include "gtest/gtest.h" +#include "iUpmObject.hpp" +#include "iServoActuator.hpp" +#include "external/json/json.hpp" +#include +#include + +/* Use the string literal operator from nlohmann */ +using namespace nlohmann; + +/* Mock ServoTest class */ +class ES08A : public virtual upm::iServoActuator +{ +public: + std::map sinks; + + ES08A() + { + sinks["axis0"] = 0.0; + sinks["axis1"] = 0.0; + + /* Add a second command for testing */ + AddCommand("axis1", "degrees"); + } + + void AngleForCommands(std::map commands) + { + for(std::map::const_iterator it = commands.begin(); it != commands.end(); ++it) + { +#ifndef NDEBUG + std::cout << "Received set angle command for: " << it->first << " value: " << it->second << std::endl; +#endif + + std::map::iterator sit = sinks.find(it->first); + + if (sit == sinks.end()) + throw std::invalid_argument("Servo axis: " + it->first + " not found"); + + sit->second = it->second; + } + } +}; + +/* Interfaces test fixture */ +class iServoActuator_unit : public ::testing::Test +{ +protected: + iServoActuator_unit() {} + virtual ~iServoActuator_unit() {} + virtual void SetUp() + { + /* Initialize from servo.json */ + sref.initFromJsonLibDesc("../../../src/servo/servo.json"); + } + virtual void TearDown() {} + + ES08A sref; +}; + +TEST_F(iServoActuator_unit, test_iServoActuator_basic) +{ + ASSERT_EQ(2, sref.Commands().size()); +} + +TEST_F(iServoActuator_unit, test_iServoActuator_serialize_command) +{ + upm::ActuatorCommand acmd; + acmd.command = "axis0"; + acmd.unit = "degrees"; + acmd.value = 30.0; + json jcmd = acmd; + + ASSERT_EQ("{\"command\":\"axis0\",\"unit\":\"degrees\",\"value\":30.0}", jcmd.dump()); +} + +TEST_F(iServoActuator_unit, test_iServoActuator_deserialize_command) +{ + json jcmd = "{\"command\":\"axis0\",\"unit\":\"degrees\",\"value\":30.0}"_json; + upm::ActuatorCommand acmd = jcmd; +} + +TEST_F(iServoActuator_unit, test_iServoActuator_run_command) +{ + sref.AngleFromJson("{\"command\":\"axis0\",\"unit\":\"radians\",\"value\":3.14159}"); + + ASSERT_FLOAT_EQ(3.14159, sref.sinks["axis0"]); +} + +TEST_F(iServoActuator_unit, test_iServoActuator_run_command_invalid_command) +{ + ASSERT_THROW(sref.AngleFromJson("{\"command\":\"axis_doesn't_exist\",\"unit\":\"radians\",\"value\":3.14159}"), + std::invalid_argument); +} + +TEST_F(iServoActuator_unit, test_iServoActuator_run_command_fail_deserialization) +{ + ASSERT_THROW(sref.AngleFromJson("This is not }{ a valid JSON string"), + std::invalid_argument); +} + +TEST_F(iServoActuator_unit, test_iServoActuator_run_commands) +{ + sref.AngleFromJson("[{\"command\":\"axis0\",\"unit\":\"degrees\",\"value\":30.0},{\"command\":\"axis1\",\"unit\":\"radians\",\"value\":3.1}]"); +} diff --git a/tests/unit/core/iUpmObject_tests.cxx b/tests/unit/core/iUpmObject_tests.cxx new file mode 100644 index 00000000..fdb2a978 --- /dev/null +++ b/tests/unit/core/iUpmObject_tests.cxx @@ -0,0 +1,55 @@ +#include "gtest/gtest.h" +#include "iUpmObject.hpp" +#include "iSensorType.hpp" + +class TestSensorClass : public virtual upm::iUpmObject +{ +}; + +/* Interfaces test fixture */ +class iUpmObject_unit : public ::testing::Test +{ + protected: + /* One-time setup logic if needed */ + iUpmObject_unit() + { + /* Load a specific JSON library descriptor file */ + obj.initFromJsonLibDesc("./sensortype_example.json"); + } + + /* One-time tear-down logic if needed */ + virtual ~iUpmObject_unit() {} + + /* Per-test setup logic if needed */ + virtual void SetUp() {} + + /* Per-test tear-down logic if needed */ + virtual void TearDown() {} + + /* Instance of the test class */ + TestSensorClass obj; +}; + +TEST_F(iUpmObject_unit, test_json_basic) +{ + /* Basic checking */ + ASSERT_EQ(obj.DerivedClassName(), "TestSensorClass"); + ASSERT_EQ(obj.Description(), "This is a description"); + ASSERT_EQ(obj.LibraryBaseName(), "core_tests"); + ASSERT_EQ(obj.Name(), "TestSensorClass"); +} + +TEST_F(iUpmObject_unit, test_json_deserialize_basic) +{ + /* Basic checking */ + ASSERT_EQ(obj.Name(), "TestSensorClass"); + ASSERT_EQ(obj.Description(), "This is a description"); +} + +/* Currently no need for a custom main (use gtest's) +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +*/ diff --git a/tests/unit/core/sensortype_example.json b/tests/unit/core/sensortype_example.json new file mode 100644 index 00000000..f1cbf0b9 --- /dev/null +++ b/tests/unit/core/sensortype_example.json @@ -0,0 +1,45 @@ +{ + "Library": "core_tests", + "Description": "Unit test JSON example", + "Sensor Class": { + "TestSensorClass": { + "Name": "This is a name", + "Description": "This is a description", + "Aliases": ["Alias blibbity", "Alias blah"], + "Categories": ["humidity", "temperature"], + "Connections": ["uart"], + "Project Type": ["industrial", "commercial"], + "Manufacturers": ["Omega"], + "Sources" : { + "temperature": { + "unit": "C", + "min" : -17, + "max" : 49, + "accuracy" : 1 + }, + "humidity-relative": { + "unit": "%", + "min" : 2, + "max" : 98, + "accuracy" : 3 + } + }, + "Specifications": { + "Vsource": { + "unit": "V", + "min": 5.0, + "max": 5.0 + }, + "Operating Temperature": { + "unit": "°C", + "min": -40, + "max": 85 + } + } + }, + "Urls": { + "Product Pages": ["http://www.omega.com/pptst/RH-USB.html"], + "Datasheets": ["http://www.omega.com/das/pdf/RH-USB.pdf"] + } + } +}