diff --git a/docs/images/ims.png b/docs/images/ims.png new file mode 100644 index 00000000..744cc064 Binary files /dev/null and b/docs/images/ims.png differ diff --git a/doxy/samples.mapping.txt b/doxy/samples.mapping.txt index 843d4dea..492c9673 100644 --- a/doxy/samples.mapping.txt +++ b/doxy/samples.mapping.txt @@ -24,6 +24,7 @@ hcsr04.cxx HCSR04Sample.java hcsr04.js hcsr04.py hm11.cxx HM11Sample.java hm11.js hm11.py hmc5883l.cxx Hmc5883lSample.java hmc5883l.js hmc5883l.py htu21d.cxx HTU21DSample.java htu21d.js htu21d.py +ims.cxx IMS_Example.java ims.js ims.py itg3200.cxx Itg3200Sample.java itg3200.js itg3200.py jhd1313m1-lcd.cxx Jhd1313m1_lcdSample.java jhd1313m1-lcd.js jhd1313m1-lcd.py joystick12.cxx Joystick12Sample.java joystick12.js joystick12.py diff --git a/examples/c++/CMakeLists.txt b/examples/c++/CMakeLists.txt index 9d44cef3..f89462f5 100644 --- a/examples/c++/CMakeLists.txt +++ b/examples/c++/CMakeLists.txt @@ -322,6 +322,7 @@ add_example (dfrorp) add_example (dfrec) add_example (sht1x) add_example (ms5803) +add_example (ims) # These are special cases where you specify example binary, source file and module(s) include_directories (${PROJECT_SOURCE_DIR}/src) diff --git a/examples/c++/ims.cxx b/examples/c++/ims.cxx new file mode 100644 index 00000000..2e7db6d3 --- /dev/null +++ b/examples/c++/ims.cxx @@ -0,0 +1,69 @@ +/* + * Author: Noel Eck + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "ims.hpp" + +using namespace upm; + +int shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + +int main(int argc, char **argv) +{ + signal(SIGINT, sig_handler); + //! [Interesting] + + // Instantiate a IMS instance using i2c bus 0 and default address + upm::IMS sensor(0); + + while (shouldRun) + { + std::cout << "Version: " + << sensor.get_version() + << " light: " + << sensor.get_light() + << " moisture: " + << sensor.get_moisture() + << " temp: " + << sensor.get_temperature() + << " C" + << std::endl; + + sleep(1); + } + //! [Interesting] + + std::cout << "Exiting..." << std::endl; + + return 0; +} diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index bfd4a2b7..ddbda942 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -23,7 +23,7 @@ macro(add_custom_example example_bin example_src example_module_list) set(found_all_modules FALSE) endif() if (MODULE_LIST) - list(FIND MODULE_LIST ${module}-c index) + list(FIND MODULE_LIST ${module} index) if (${index} EQUAL -1) set(found_all_modules FALSE) endif() @@ -139,6 +139,7 @@ add_example (button) add_example (button_intr) add_example (my9221) add_example (ms5803) +add_example (ims) # Custom examples add_custom_example (nmea_gps_i2c-example-c nmea_gps_i2c.c nmea_gps) diff --git a/examples/c/ims.c b/examples/c/ims.c new file mode 100644 index 00000000..23e4a716 --- /dev/null +++ b/examples/c/ims.c @@ -0,0 +1,75 @@ +/* + * Author: Noel Eck + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +#include "ims.h" +#include "upm_utilities.h" + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + +int main() +{ + signal(SIGINT, sig_handler); + + //! [Interesting] + ims_context* sensor = ims_init(0, IMS_ADDRESS_DEFAULT); + + if (!sensor) + { + printf("ims_init() failed\n"); + return 1; + } + + // Every second, sample the sensor outputs + while (shouldRun) + { + uint16_t version, light, moisture, temp; + + if (ims_get_version(sensor, &version) == UPM_SUCCESS && + ims_get_light(sensor, &light) == UPM_SUCCESS && + ims_get_moisture(sensor, &moisture) == UPM_SUCCESS && + ims_get_temperature(sensor, &temp) == UPM_SUCCESS) + printf("Version: %d light: 0x%04x moisture: 0x%04x temp: %3.2f C\n", + version, light, moisture, temp/10.0); + else + break; + + upm_delay(1); + } + + //! [Interesting] + printf("Exiting\n"); + ims_close(sensor); + + return 0; +} diff --git a/examples/java/IMS_Example.java b/examples/java/IMS_Example.java new file mode 100644 index 00000000..0db81b72 --- /dev/null +++ b/examples/java/IMS_Example.java @@ -0,0 +1,53 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import upm_ims.IMS; + +public class IMS_Example +{ + public static void main(String[] args) throws InterruptedException + { + // ! [Interesting] + + // Instantiate a IMS instance using bus 0 and default i2c address + IMS sensor = new IMS(0); + + while (true) + { + System.out.println("Version: " + + sensor.get_version() + + " light: " + + sensor.get_light() + + " moisture: " + + sensor.get_moisture() + + " temp: " + + sensor.get_temperature() + + " C"); + + Thread.sleep(1000); + } + + // ! [Interesting] + } +} diff --git a/examples/javascript/ims.js b/examples/javascript/ims.js new file mode 100644 index 00000000..e8d1bde6 --- /dev/null +++ b/examples/javascript/ims.js @@ -0,0 +1,51 @@ +/* + * Author: Noel Eck + * Copyright (c) 2016 Intel Corporation. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +var sensorObj = require('jsupm_ims'); + +// Instantiate a IMS instance using bus 0 and default i2c address +var sensor = new sensorObj.IMS(0); + +setInterval(function() +{ + console.log("Version: " + + sensor.get_version() + + " light: " + + sensor.get_light() + + " moisture: " + + sensor.get_moisture() + + " temp: " + + sensor.get_temperature().toFixed(2) + + " C"); +}, 1000); + +// exit on ^C +process.on('SIGINT', function() +{ + sensor = null; + sensorObj.cleanUp(); + sensorObj = null; + console.log("Exiting."); + process.exit(0); +}); diff --git a/examples/python/ims.py b/examples/python/ims.py new file mode 100755 index 00000000..1f4f6b29 --- /dev/null +++ b/examples/python/ims.py @@ -0,0 +1,44 @@ +#!/usr/bin/python +# Author: Noel Eck +# Copyright (c) 2016 Intel Corporation. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function +import time, sys, signal, atexit +from upm import pyupm_ims + +def main(): + # Create an instance of the I2C Moisture Sensor + # I2C bus 0, default address = 0x20 + ims = pyupm_ims.IMS(0) + + print ('I2C moisture sensor example...') + while (1): + try: + print ('Version: %d light: 0x%04x moisture: 0x%04x temp: %3.2f C' \ + % (ims.get_version(), ims.get_light(), ims.get_moisture(), + ims.get_temperature())) + time.sleep(1) + except KeyboardInterrupt: + break + +if __name__ == '__main__': + main() diff --git a/src/ims/CMakeLists.txt b/src/ims/CMakeLists.txt new file mode 100644 index 00000000..f559602b --- /dev/null +++ b/src/ims/CMakeLists.txt @@ -0,0 +1,9 @@ +upm_mixed_module_init (NAME ims + DESCRIPTION "Catnip Electronics I2C moisture sensor" + C_HDR ims.h + C_SRC ims.c + CPP_HDR ims.hpp + CPP_SRC ims.cxx + FTI_SRC ims_fti.c + CPP_WRAPS_C + REQUIRES mraa) diff --git a/src/ims/ims.c b/src/ims/ims.c new file mode 100644 index 00000000..1eea5608 --- /dev/null +++ b/src/ims/ims.c @@ -0,0 +1,207 @@ +/* + * Author: Noel Eck + * 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. + */ + +#include +#include + +#include "ims.h" + +ims_context* ims_init(int16_t i2c_bus, int16_t i2c_address) +{ + /* Allocate space for the sensor structure */ + ims_context* dev = (ims_context*) malloc(sizeof(ims_context)); + if(dev == NULL) + { + syslog(LOG_CRIT, "%s: malloc() failed\n", __FUNCTION__); + goto ims_init_fail; + } + + /* Initilize mraa */ + mraa_result_t result = mraa_init(); + if (result != MRAA_SUCCESS) + { + syslog(LOG_ERR, "%s: mraa_init() failed (%d)\n", __FUNCTION__, result); + goto ims_init_fail; + } + + /* Init i2c */ + dev->_i2c_context = mraa_i2c_init(i2c_bus); + if(dev->_i2c_context == NULL) + { + syslog(LOG_ERR, "%s: mraa_i2c_init() failed\n", __FUNCTION__); + goto ims_init_fail; + } + + /* Set the i2c slave address for this device */ + if (mraa_i2c_address(dev->_i2c_context, i2c_address) != MRAA_SUCCESS) + { + syslog(LOG_ERR, "%s: mraa_i2c_address() failed\n", __FUNCTION__); + goto ims_init_fail; + } + + /* This device must run at 100kHz */ + if (mraa_i2c_frequency(dev->_i2c_context, MRAA_I2C_STD)) + { + syslog(LOG_ERR, "%s: mraa_i2c_frequency() failed\n", __FUNCTION__); + goto ims_init_fail; + } + + return dev; + +/* Handle all failing cases here */ +ims_init_fail: + /* Free structure memory if allocated */ + if (dev != NULL) + free(dev); + return NULL; +} + +void ims_close(ims_context* dev) +{ + if (dev == NULL) return; + + /* Cleanup the I2C context */ + mraa_i2c_stop(dev->_i2c_context); + free(dev); +} + +upm_result_t ims_read(const ims_context* dev, IMS_RD_COMMAND cmd, uint16_t* rd_data) +{ + int32_t val = 0; + uint8_t readbuf[2] = {0, 0}; + switch (cmd) + { + /* One byte reads */ + case IMS_GET_ADDRESS: + case IMS_GET_VERSION: + case IMS_GET_BUSY: + val = mraa_i2c_read_bytes_data(dev->_i2c_context, cmd, readbuf, 1); + *rd_data = readbuf[0]; + break; + /* Two byte reads */ + case IMS_GET_CAPACITANCE: + case IMS_GET_LIGHT: + case IMS_GET_TEMPERATURE: + val = mraa_i2c_read_bytes_data(dev->_i2c_context, cmd, readbuf, 2); + *rd_data = readbuf[1]; + *rd_data += ((uint16_t)readbuf[0] << 8) & 0xFF00; + break; + default: + syslog(LOG_ERR, "%s: Invalid read command: 0x%02x\n", __FUNCTION__, cmd); + return UPM_ERROR_INVALID_PARAMETER; + } + + /* val will be < 0 on failing case */ + if (val < 0) + { + syslog(LOG_ERR, "%s: mraa_i2c_read_byte/word_data() failed\n", __FUNCTION__); + return UPM_ERROR_NO_DATA; + } + + return UPM_SUCCESS; +} + +upm_result_t ims_write(const ims_context* dev, IMS_WR_COMMAND cmd, uint8_t wr_data) +{ + mraa_result_t mr; + switch (cmd) + { + /* One byte write */ + case IMS_SET_ADDRESS: + mr = mraa_i2c_write_byte_data(dev->_i2c_context, wr_data, cmd); + break; + /* Zero byte write */ + case IMS_MEASURE_LIGHT: + case IMS_RESET: + case IMS_SLEEP: + mr = mraa_i2c_write(dev->_i2c_context, (const uint8_t *)&cmd, 1); + break; + default: + syslog(LOG_ERR, "%s: Invalid read command: 0x%02x\n", __FUNCTION__, cmd); + return UPM_ERROR_INVALID_PARAMETER; + } + + if (mr != MRAA_SUCCESS) return UPM_ERROR_OPERATION_FAILED; + + return UPM_SUCCESS; +} + +upm_result_t ims_get_version(const ims_context* dev, uint16_t* rd_data) +{ + return ims_read(dev, IMS_GET_VERSION, rd_data); +} + +upm_result_t ims_get_moisture(const ims_context* dev, uint16_t* rd_data) +{ + return ims_read(dev, IMS_GET_CAPACITANCE, rd_data); +} + +upm_result_t ims_get_light(const ims_context* dev, uint16_t* rd_data) +{ + /* Initiate a light measurement */ + upm_result_t res = ims_write(dev, IMS_MEASURE_LIGHT, 0); + if (res != UPM_SUCCESS) return res; + + /* Technical data for the ISM specifies a 3 second wait. Check the BUSY + * command every 100 ms for 3 seconds. The sensor will return quickly in + * bright light and much slower in less light. */ + int retry = 30; + *rd_data = 1; + while ((retry-- > 0) && (*rd_data != 0)) + { + // Always delay at least 100 ms + upm_delay_ms(100); + res = ims_read(dev, IMS_GET_BUSY, rd_data); + if (res != UPM_SUCCESS) return res; + } + + /* If the sensor is STILL not ready, go ahead and perform the read. + * From testing, this appears to happen only in complete darkness, + * at which point the sensor get light read returns 0xffff anyway.*/ + + return ims_read(dev, IMS_GET_LIGHT, rd_data); +} + +upm_result_t ims_get_temperature(const ims_context* dev, uint16_t* rd_data) +{ + return ims_read(dev, IMS_GET_TEMPERATURE, rd_data); +} + +upm_result_t ims_reset(const ims_context* dev) +{ + return ims_write(dev, IMS_RESET, 0); +} + +upm_result_t ims_reset_i2c_address(const ims_context* dev, uint8_t address_new) +{ + upm_result_t res = ims_write(dev, IMS_SET_ADDRESS, address_new); + if (res != UPM_SUCCESS) return res; + + return ims_reset(dev); +} + +upm_result_t ims_sleep(const ims_context* dev) +{ + return ims_write(dev, IMS_SLEEP, 0); +} diff --git a/src/ims/ims.cxx b/src/ims/ims.cxx new file mode 100644 index 00000000..1831f88f --- /dev/null +++ b/src/ims/ims.cxx @@ -0,0 +1,110 @@ +/* + * Author: Noel Eck + * 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. + */ + +#include + +#include "ims.hpp" + +using namespace upm; + +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"); +} + +uint16_t IMS::get_version() +{ + uint16_t retval; + if (ims_get_version(_dev, &retval) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + + ": ims_get_version command failed"); + return retval; +} + +uint16_t IMS::get_moisture() +{ + uint16_t retval; + if (ims_get_moisture(_dev, &retval) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + + ": ims_get_moisture command failed"); + return retval; +} + +uint16_t IMS::get_light() +{ + uint16_t retval; + if (ims_get_light(_dev, &retval) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + + ": ims_get_light command failed"); + return retval; +} + +float IMS::get_temperature() +{ + uint16_t retval; + if (ims_get_temperature(_dev, &retval) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + + ": ims_get_temperature command failed"); + return static_cast(retval)/10.0; +} + +void IMS::reset_i2c_address(uint8_t address_new) +{ + if (ims_reset_i2c_address(_dev, address_new) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + + ": reset_i2c_address command failed"); +} + +void IMS::reset() +{ + if ( ims_write(_dev, IMS_RESET, 1) != UPM_SUCCESS ) + throw std::runtime_error(std::string(__FUNCTION__) + + ": ims_write command failed"); +} + +uint16_t IMS::read(IMS_RD_COMMAND cmd) +{ + uint16_t retval; + if (ims_read(_dev, cmd, &retval) != UPM_SUCCESS) + throw std::runtime_error(std::string(__FUNCTION__) + + ": ims_read command failed"); + return retval; +} + +void IMS::write(IMS_WR_COMMAND cmd, uint8_t value) +{ + if ( ims_write(_dev, cmd, value) != UPM_SUCCESS ) + throw std::runtime_error(std::string(__FUNCTION__) + + ": ims_write command failed"); +} + +void IMS::sleep() +{ + if ( ims_sleep(_dev) != UPM_SUCCESS ) + throw std::runtime_error(std::string(__FUNCTION__) + + ": ims_sleep command failed"); +} diff --git a/src/ims/ims.h b/src/ims/ims.h new file mode 100644 index 00000000..07af1302 --- /dev/null +++ b/src/ims/ims.h @@ -0,0 +1,178 @@ +/* + * Author: Noel Eck + * 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 + +#include "mraa/i2c.h" +#include "upm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define IMS_ADDRESS_DEFAULT 0x20 + + /* @brief Moisture sensor I2C READ commands */ +typedef enum _IMS_RD_COMMAND { + /* Read capacitance (moisture) register */ + IMS_GET_CAPACITANCE = 0x00, /* (r) 2 */ + /* Read I2C address register */ + IMS_GET_ADDRESS = 0x02, /* (r) 1 */ + /* Read light register (requires write to IMS_MEASURE_LIGHT) */ + IMS_GET_LIGHT = 0x04, /* (r) 2 */ + /* Read temperature register */ + IMS_GET_TEMPERATURE = 0x05, /* (r) 2 */ + /* Read version register */ + IMS_GET_VERSION = 0x07, /* (r) 1 */ + /* Read busy register (0 = ready, 1 = sampling) */ + IMS_GET_BUSY = 0x09, /* (r) 1 */ +} IMS_RD_COMMAND; + + /* @brief Moisture sensor I2C WRITE commands */ +typedef enum { + /* Write I2C address register (latched w/IMS_RESET) */ + IMS_SET_ADDRESS = 0x01, /* (w) 1 */ + /* Initiate light measurement */ + IMS_MEASURE_LIGHT = 0x03, /* (w) 0 */ + /* Reset device */ + IMS_RESET = 0x06, /* (w) 0 */ + /* Sleep microcontroller, wake on any I2C request */ + IMS_SLEEP = 0x08, /* (w) 0 */ +} IMS_WR_COMMAND; + +/** + * @file ims.h + * @library ims + * @brief C API for the Catnip Electronics I2C moisture sensor. This sensor + * must run at 100 kHz. + * + * @include ims.c + */ + +/** + * device context + */ +typedef struct { + /* mraa i2c context */ + mraa_i2c_context _i2c_context; +} ims_context; + +/** + * Initialize sensor + * @param i2c_bus Target I2C bus + * @param i2c_address Target I2C address (default is 0x20) + * @return sensor context pointer + */ +ims_context* ims_init(int16_t i2c_bus, int16_t i2c_address); + +/** + * Sensor close method. + * Cleans up any memory held by this device + * @param sensor context pointer + */ +void ims_close(ims_context* dev); + +/** + * Read I2C Moisture Sensor registers + * @param dev Sensor context pointer + * @param cmd Read command + * @param rd_data Data returned from sensor (1 or 2 bytes depending on cmd) + * @return Function result code + */ +upm_result_t ims_read(const ims_context* dev, IMS_RD_COMMAND cmd, uint16_t* rd_data); + +/** + * Write I2C Moisture Sensor registers + * @param dev Sensor context pointer + * @param cmd Write command + * @param wr_data Target data to write (only used for IMS_SET_ADDRESS) + * @return Function result code + */ +upm_result_t ims_write(const ims_context* dev, IMS_WR_COMMAND cmd, uint8_t wr_data); + +/** + * Get sensor version + * @param dev Sensor context pointer + * @param rd_data Sensor version + * @return Function result code + */ +upm_result_t ims_get_version(const ims_context* dev, uint16_t* rd_data); + +/** + * Get moisture reading from sensor + * @param dev Sensor context pointer + * @param rd_data Unitless, relative capacitance value (used to determine moisture) + * @return Function result code + */ +upm_result_t ims_get_moisture(const ims_context* dev, uint16_t* rd_data); + +/** + * Get light reading from LED on device. The technical data for the I2C + * moisture sensor specifies a 3 second wait. Loop for 3 seconds checking + * the GET_BUSY register. IF the sensor is NOT ready after 3 seconds, + * assume there is NO light and return a max uint16_t (dark) value. + * @param dev Sensor context pointer + * @param rd_data Unitless, relative value for brightness + * dark (0xFFFF) ---> light (0x0000) + * @return Function result code + */ +upm_result_t ims_get_light(const ims_context* dev, uint16_t* rd_data); + +/** + * Get temperature reading from device + * @param dev Sensor context pointer + * @param rd_data Temperature in degrees Celsius * 10 + * ie, 256 = 25.6 C + * @return Function result code + */ +upm_result_t ims_get_temperature(const ims_context* dev, uint16_t* rd_data); + +/** + * Reset sensor + * @param dev Sensor context pointer + * @return Function result code + */ +upm_result_t ims_reset(const ims_context* dev); + +/** + * Set I2C address AND reset sensor + * @param dev Sensor context pointer + * @param address_new New I2C for device + * @return Function result code + */ +upm_result_t ims_reset_i2c_address(const ims_context* dev, uint8_t address_new); + +/** + * Put device into low-power mode. Device wakes on any I2C command. + * @param dev Sensor context pointer + * @return Function result code + */ +upm_result_t ims_sleep(const ims_context* dev); + +#ifdef __cplusplus +} +#endif diff --git a/src/ims/ims.hpp b/src/ims/ims.hpp new file mode 100644 index 00000000..a9c1b299 --- /dev/null +++ b/src/ims/ims.hpp @@ -0,0 +1,148 @@ +/* + * Author: Noel Eck + * 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 "mraa/i2c.h" +#include "ims.h" + +namespace upm { +/** + * @brief Catnip Electronics I2C moisture sensor + * @defgroup ims libupm-ims + * @ingroup catnip i2c liquid light temp + */ + +/** + * @library ims + * @sensor ims + * @comname Catnip Electronics I2C moisture sensor + * @type liquid light temp + * @man catnip + * @web https://www.tindie.com/products/miceuz/i2c-soil-moisture-sensor/ + * @con i2c + * + * @brief API for the Catnip Electronics I2C moisture sensor + * + * I2C sensor which can be used to read: + * moisture + * light + * temperature + * + * This sensor must run at 100 kHz + * + * @image html ims.png + * @snippet ims.cxx Interesting + */ + +class IMS { + public: + /** + * I2C Moisture Sensor constructor + * + * Initialize I2C Moisture Sensor + * @param i2c_bus Target I2C bus + * @param i2c_address Target I2C address (default is 0x20) + * @return sensor context pointer + * @throws std::runtime_error if sensor initializate fails + */ + IMS(int16_t i2c_bus, int16_t i2c_address = IMS_ADDRESS_DEFAULT); + + /** + * IMS destructor + */ + virtual ~IMS() {}; + + /** + * Write I2C Moisture Sensor registers + * @param cmd Write command + * @param wr_data Target data to write (only used for IMS_SET_ADDRESS) + * @throws std::runtime_error if I2C write command fails + */ + void write(IMS_WR_COMMAND cmd, uint8_t wr_data); + + /** + * Read I2C Moisture Sensor registers + * @param cmd Read command + * @return Data returned from sensor (1 or 2 bytes depending on CMD) + * @throws std::runtime_error if I2C read command fails + */ + uint16_t read(IMS_RD_COMMAND cmd); + + /** + * Get sensor version + * @return Sensor version + * @throws std::runtime_error if I2C read command fails + */ + uint16_t get_version(); + + /** + * Get moisture reading from sensor + * @return Unitless, relative capacitance value (moisture) + * @throws std::runtime_error if I2C read command fails + */ + uint16_t get_moisture(); + + /** + * Get light reading from LED on device. The technical data for the I2C + * moisture sensor specifies a 3 second wait. Loop for 3 seconds + * checking the GET_BUSY register. IF the sensor is NOT ready after 3 + * seconds, assume there is NO light and return a max uint16_t (dark) + * value. + * @return rd_data Unitless, relative value for brightness + * dark (0xFFFF) ---> light (0x0000) + * @throws std::runtime_error if I2C write/read command fails + */ + uint16_t get_light(); + + /** + * Get temperature reading from device + * @return rd_data Temperature in degrees Celsius + * @throws std::runtime_error if I2C read command fails + */ + float get_temperature(); + + /** + * Reset sensor + * @throws std::runtime_error if I2C write command fails + */ + void reset(); + + /** + * Set I2C address AND reset sensor + * @param address_new New I2C for device + * @throws std::runtime_error if I2C write command fails + */ + void reset_i2c_address(uint8_t address_new); + + /** + * Put device into low-power mode. Device wakes on any I2C command. + * @throws std::runtime_error if I2C write command fails + */ + void sleep(); + private: + /* device context struct */ + ims_context* _dev; +}; +} diff --git a/src/ims/ims_fti.c b/src/ims/ims_fti.c new file mode 100644 index 00000000..5d761928 --- /dev/null +++ b/src/ims/ims_fti.c @@ -0,0 +1,118 @@ +/* + * Author: Noel Eck + * 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. + */ + +#include +#include + +#include "ims.h" +#include "upm_fti.h" +#include "fti/upm_sensor.h" + +/** + * This file implements the Function Table Interface (FTI) for this sensor + */ + +const char upm_ims_name[] = "IMS"; +const char upm_ims_description[] = "Analog pH Meter Pro"; +const upm_protocol_t upm_ims_protocol[] = {UPM_ANALOG}; +const upm_sensor_t upm_ims_category[] = {UPM_PH}; + +// forward declarations +const void* upm_ims_get_ft(upm_sensor_t sensor_type); +void* upm_ims_init_str(const char* protocol, const char* params); +void upm_ims_close(void* dev); +const upm_sensor_descriptor_t upm_ims_get_descriptor(); +upm_result_t upm_ims_set_offset(const void* dev, float offset); +upm_result_t upm_ims_set_scale(const void* dev, float scale); +upm_result_t upm_ims_get_value(const void* dev, float *value); + +/* This sensor implementes 2 function tables */ +/* 1. Generic base function table */ +static const upm_sensor_ft ft_gen = +{ + .upm_sensor_init_name = &upm_ims_init_str, + .upm_sensor_close = &upm_ims_close, + .upm_sensor_get_descriptor = &upm_ims_get_descriptor +}; + +/* 2. PH function table */ +static const upm_ph_ft ft_ph = +{ + .upm_ph_set_offset = &upm_ims_set_offset, + .upm_ph_set_scale = &upm_ims_set_scale, + .upm_ph_get_value = &upm_ims_get_value +}; + +const void* upm_ims_get_ft(upm_sensor_t sensor_type) +{ + switch(sensor_type) + { + case UPM_SENSOR: + return &ft_gen; + case UPM_PH: + return &ft_ph; + default: + return NULL; + } +} + +void* upm_ims_init_str(const char* protocol, const char* params) +{ + fprintf(stderr, "String initialization - not implemented, using ain0: %s\n", __FILENAME__); + return ims_init(0); +} + +void upm_ims_close(void* dev) +{ + ims_close(dev); +} + +const upm_sensor_descriptor_t upm_ims_get_descriptor() +{ + /* Fill in the descriptor */ + upm_sensor_descriptor_t usd; + usd.name = upm_ims_name; + usd.description = upm_ims_description; + usd.protocol_size = 1; + usd.protocol = upm_ims_protocol; + usd.category_size = 1; + usd.category = upm_ims_category; + + return usd; +} + +upm_result_t upm_ims_set_offset(const void* dev, float offset) +{ + return ims_set_offset((ims_context)dev, offset); +} + +upm_result_t upm_ims_set_scale(const void* dev, float scale) +{ + return ims_set_scale((ims_context)dev, scale); +} + +upm_result_t upm_ims_get_value(const void* dev, float *value) +{ + return ims_get_ph((ims_context)dev, value); +} diff --git a/src/ims/javaupm_ims.i b/src/ims/javaupm_ims.i new file mode 100644 index 00000000..c48a1142 --- /dev/null +++ b/src/ims/javaupm_ims.i @@ -0,0 +1,19 @@ +%module javaupm_ims +%include "../upm.i" + +%{ + #include "ims.hpp" +%} + +%include "ims.hpp" + +%pragma(java) jniclasscode=%{ + static { + try { + System.loadLibrary("javaupm_ims"); + } catch (UnsatisfiedLinkError e) { + System.err.println("Native code library failed to load. \n" + e); + System.exit(1); + } + } +%} diff --git a/src/ims/jsupm_ims.i b/src/ims/jsupm_ims.i new file mode 100644 index 00000000..5c06329a --- /dev/null +++ b/src/ims/jsupm_ims.i @@ -0,0 +1,8 @@ +%module jsupm_ims +%include "../upm.i" + +%{ + #include "ims.hpp" +%} + +%include "ims.hpp" diff --git a/src/ims/pyupm_ims.i b/src/ims/pyupm_ims.i new file mode 100644 index 00000000..c1c32535 --- /dev/null +++ b/src/ims/pyupm_ims.i @@ -0,0 +1,13 @@ +// Include doxygen-generated documentation +%include "pyupm_doxy2swig.i" +%module pyupm_ims +%include "../upm.i" + +%feature("autodoc", "3"); + +%{ + #include "ims.hpp" +%} + +%include "ims.h" +%include "ims.hpp"