From da18bac925f4db757b1889fb20010f8720e00a6a Mon Sep 17 00:00:00 2001 From: Noel Eck Date: Wed, 31 May 2017 14:15:33 -0700 Subject: [PATCH] ims: Updated IMS sensor addressing The IMS library will now change its I2C address after resetting the HW to a new address. It will attempt to close the mraa context and re-init each time. Signed-off-by: Noel Eck --- examples/c++/ims.cxx | 12 +++++-- examples/c/ims.c | 13 ++++++++ src/ims/ims.c | 76 ++++++++++++++++++++++++++++---------------- src/ims/ims.h | 4 ++- 4 files changed, 73 insertions(+), 32 deletions(-) diff --git a/examples/c++/ims.cxx b/examples/c++/ims.cxx index 2e7db6d3..6d96ab56 100644 --- a/examples/c++/ims.cxx +++ b/examples/c++/ims.cxx @@ -46,19 +46,25 @@ int main(int argc, char **argv) // Instantiate a IMS instance using i2c bus 0 and default address upm::IMS sensor(0); + int i2c_addr_cur = IMS_ADDRESS_DEFAULT + 1; while (shouldRun) { - std::cout << "Version: " + std::cout << std::hex << "Version: 0x" << sensor.get_version() - << " light: " + << " light: 0x" << sensor.get_light() - << " moisture: " + << " moisture: 0x" << sensor.get_moisture() << " temp: " << sensor.get_temperature() << " C" << std::endl; + // Change the address and continue + if (i2c_addr_cur >= 128) i2c_addr_cur = 1; + std::cout << "Changing device address to 0x" << i2c_addr_cur + << std::endl; + sensor.reset_i2c_address(i2c_addr_cur++); sleep(1); } //! [Interesting] diff --git a/examples/c/ims.c b/examples/c/ims.c index 23e4a716..654bdfac 100644 --- a/examples/c/ims.c +++ b/examples/c/ims.c @@ -50,6 +50,8 @@ int main() return 1; } + int i2c_addr_cur = IMS_ADDRESS_DEFAULT + 1; + // Every second, sample the sensor outputs while (shouldRun) { @@ -62,8 +64,19 @@ int main() printf("Version: %d light: 0x%04x moisture: 0x%04x temp: %3.2f C\n", version, light, moisture, temp/10.0); else + { + printf("Failed to read IMS sensor data...\n"); break; + } + // Change the address and continue + if (i2c_addr_cur >= 128) i2c_addr_cur = 1; + printf("Changing device address to 0x%02x\n", i2c_addr_cur); + if (ims_reset_i2c_address(sensor, i2c_addr_cur++) != UPM_SUCCESS) + { + printf("Failed to change IMS I2C address...\n"); + break; + } upm_delay(1); } diff --git a/src/ims/ims.c b/src/ims/ims.c index 9eecf75a..15cc649c 100644 --- a/src/ims/ims.c +++ b/src/ims/ims.c @@ -28,37 +28,25 @@ #include "ims.h" #include "upm_utilities.h" -ims_context* ims_init(int16_t i2c_bus, int16_t i2c_address) +static upm_result_t i2c_init(ims_context* dev, 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; - } - - /* Initialize 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; - } + /* Attempt to stop the i2c device context if previously initialized */ + if (dev->_i2c_context != NULL) + mraa_i2c_stop(dev->_i2c_context); /* 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; + return UPM_ERROR_OPERATION_FAILED; } /* 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; + return UPM_ERROR_OPERATION_FAILED; } /* This device must run at 100kHz */ @@ -67,17 +55,41 @@ ims_context* ims_init(int16_t i2c_bus, int16_t i2c_address) syslog(LOG_ERR, "%s: mraa_i2c_frequency() failed. %s\n", __FUNCTION__, "This device requires I2C standard mode (100 kb/s)"); - goto ims_init_fail; + return UPM_ERROR_OPERATION_FAILED; + } + /* Save the new bus */ + dev->_i2c_bus = i2c_bus; + + return UPM_SUCCESS; +} + +ims_context* ims_init(int16_t i2c_bus, int16_t i2c_address) +{ + /* Allocate space for the sensor structure */ + ims_context* dev = (ims_context*) calloc(1, sizeof(ims_context)); + if(dev == NULL) + { + syslog(LOG_CRIT, "%s: malloc() failed\n", __FUNCTION__); + return NULL; + } + + /* Initialize mraa */ + mraa_result_t result = mraa_init(); + if (result != MRAA_SUCCESS) + { + syslog(LOG_ERR, "%s: mraa_init() failed (%d)\n", __FUNCTION__, result); + free(dev); + return NULL; + } + + /* Setup the I2C bus */ + if (i2c_init(dev, i2c_bus, i2c_address) != UPM_SUCCESS) + { + free(dev); + return NULL; } 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) @@ -196,12 +208,20 @@ 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 ims_reset_i2c_address(ims_context* dev, uint8_t address_new) { + /* Set the new address */ upm_result_t res = ims_write(dev, IMS_SET_ADDRESS, address_new); if (res != UPM_SUCCESS) return res; - return ims_reset(dev); + /* Reset the device to load the new I2C address */ + res = ims_reset(dev); + if (res != UPM_SUCCESS) return res; + + /* Re-init the I2C bus */ + res = i2c_init(dev, dev->_i2c_bus, address_new); + + return res; } upm_result_t ims_sleep(const ims_context* dev) diff --git a/src/ims/ims.h b/src/ims/ims.h index f02d76ab..5a3348c7 100644 --- a/src/ims/ims.h +++ b/src/ims/ims.h @@ -51,6 +51,8 @@ extern "C" { typedef struct { /* mraa i2c context */ mraa_i2c_context _i2c_context; + /* Save the I2C bus (used when changing the device address) */ + int16_t _i2c_bus; } ims_context; /** @@ -136,7 +138,7 @@ upm_result_t ims_reset(const ims_context* dev); * @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); +upm_result_t ims_reset_i2c_address(ims_context* dev, uint8_t address_new); /** * Put device into low-power mode. Device wakes on any I2C command.