diff --git a/examples/c++/hmc5883l.cxx b/examples/c++/hmc5883l.cxx index 7dbf700b..7c686a95 100644 --- a/examples/c++/hmc5883l.cxx +++ b/examples/c++/hmc5883l.cxx @@ -32,16 +32,17 @@ main(int argc, char **argv) //! [Interesting] // Instantiate on I2C upm::Hmc5883l* compass = new upm::Hmc5883l(0); - int16_t *pos; - compass->set_declination(0.2749); // Set your declination from true north in radians + compass->set_declination(0.2749); // Set your declination from + // true north in radians // Print out the coordinates, heading, and direction every second while(true){ compass->update(); // Update the coordinates - pos = compass->coordinates(); + const int16_t *pos = compass->coordinates(); fprintf(stdout, "coor: %5d %5d %5d ", pos[0], pos[1], pos[2]); - fprintf(stdout, "heading: %5.2f direction: %3.2f\n", compass->heading(), compass->direction()); + fprintf(stdout, "heading: %5.2f direction: %3.2f\n", + compass->heading(), compass->direction()); sleep(1); } //! [Interesting] diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt index 1107c46e..cee92d2c 100644 --- a/examples/c/CMakeLists.txt +++ b/examples/c/CMakeLists.txt @@ -145,6 +145,7 @@ add_example (mcp2515) add_example (max30100) add_example (speaker) add_example (cjq4435) +add_example (hmc5883l) # Custom examples add_custom_example (nmea_gps_i2c-example-c nmea_gps_i2c.c nmea_gps) diff --git a/examples/c/hmc5883l.c b/examples/c/hmc5883l.c new file mode 100644 index 00000000..afd1bfb8 --- /dev/null +++ b/examples/c/hmc5883l.c @@ -0,0 +1,82 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * Ported based on original C++ code by: + * Author: Brendan Le Foll + * Contributions: Mihai Tudor Panu + * 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. + */ + +#include +#include +#include + +#include + +#include "hmc5883l.h" + +bool shouldRun = true; + +void sig_handler(int signo) +{ + if (signo == SIGINT) + shouldRun = false; +} + +int main(int argc, char **argv) +{ + signal(SIGINT, sig_handler); + +//! [Interesting] + // Instantiate an HMC8883L on I2C bus 0 + hmc5883l_context sensor = hmc5883l_init(0); + + if (!sensor) + { + printf("%s: hmc5883l_init() failed\n", __FUNCTION__); + return 1; + } + + hmc5883l_set_declination(sensor, 0.2749); // Set your declination + // from true north in + // radians + + // Print out the coordinates, heading, and direction every second + while (shouldRun) + { + hmc5883l_update(sensor); // Update the coordinates + const int16_t *pos = hmc5883l_coordinates(sensor); + + printf("coor: %5d %5d %5d ", pos[0], pos[1], pos[2]); + printf("heading: %5.2f direction: %3.2f\n", + hmc5883l_heading(sensor), hmc5883l_direction(sensor)); + + upm_delay(1); + } + + hmc5883l_close(sensor); + +//! [Interesting] + + return 0; +} diff --git a/include/fti/upm_compass.h b/include/fti/upm_compass.h new file mode 100644 index 00000000..7a0124cc --- /dev/null +++ b/include/fti/upm_compass.h @@ -0,0 +1,43 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 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. + */ +#ifndef UPM_COMPASS_H_ +#define UPM_COMPASS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// Compass function table +typedef struct _upm_compass_ft { + upm_result_t (*upm_compass_set_scale) (void* dev, float scale); + upm_result_t (*upm_compass_set_offset) (void* dev, float offset); + // returns a heading in degrees + upm_result_t (*upm_compass_get_value) (void* dev, float *value); +} upm_compass_ft; + +#ifdef __cplusplus +} +#endif + +#endif /* UPM_COMPASS_H_ */ diff --git a/include/upm_fti.h b/include/upm_fti.h index 9b34506c..83fd9416 100644 --- a/include/upm_fti.h +++ b/include/upm_fti.h @@ -125,6 +125,7 @@ typedef struct _upm_sensor_ft* (*func_get_upm_sensor_ft)(upm_sensor_t sensor_typ #include #include #include +#include #ifdef __cplusplus } diff --git a/src/hmc5883l/CMakeLists.txt b/src/hmc5883l/CMakeLists.txt index 4ce609b0..85a5aef6 100644 --- a/src/hmc5883l/CMakeLists.txt +++ b/src/hmc5883l/CMakeLists.txt @@ -1,5 +1,11 @@ -set (libname "hmc5883l") -set (libdescription "Digital Compass") -set (module_src ${libname}.cxx) -set (module_hpp ${libname}.hpp) -upm_module_init() +upm_mixed_module_init (NAME hmc5883l + DESCRIPTION "3-axis Digital Compass" + C_HDR hmc5883l.h + C_SRC hmc5883l.c + CPP_HDR hmc5883l.hpp + CPP_SRC hmc5883l.cxx + CPP_WRAPS_C + FTI_SRC hmc5883l_fti.c + REQUIRES mraa) + +target_link_libraries(${libnamec} m) diff --git a/src/hmc5883l/hmc5883l.c b/src/hmc5883l/hmc5883l.c new file mode 100644 index 00000000..50599dd0 --- /dev/null +++ b/src/hmc5883l/hmc5883l.c @@ -0,0 +1,246 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * Ported based on original C++ code by: + * Author: Brendan Le Foll + * Contributions: Mihai Tudor Panu + * 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. + */ + +#include +#include +#include + +#include "math.h" +#include "hmc5883l.h" + +#define MAX_BUFFER_LENGTH 6 +#define HMC5883L_I2C_ADDR 0x1E + +// configuration registers +#define HMC5883L_CONF_REG_A 0x00 +#define HMC5883L_CONF_REG_B 0x01 + +// mode register +#define HMC5883L_MODE_REG 0x02 + +// data register +#define HMC5883L_X_MSB_REG 0 +#define HMC5883L_X_LSB_REG 1 +#define HMC5883L_Z_MSB_REG 2 +#define HMC5883L_Z_LSB_REG 3 +#define HMC5883L_Y_MSB_REG 4 +#define HMC5883L_Y_LSB_REG 5 +#define DATA_REG_SIZE 6 + +// status register +#define HMC5883L_STATUS_REG 0x09 + +// ID registers +#define HMC5883L_ID_A_REG 0x0A +#define HMC5883L_ID_B_REG 0x0B +#define HMC5883L_ID_C_REG 0x0C + +// mode +#define HMC5883L_CONT_MODE 0x00 +// start of data registers (MSB/LSB for X, Z, and Y axis) +#define HMC5883L_DATA_REG 0x03 + +// scales +#define GA_0_88_REG 0x00 << 5 +#define GA_1_3_REG 0x01 << 5 +#define GA_1_9_REG 0x02 << 5 +#define GA_2_5_REG 0x03 << 5 +#define GA_4_0_REG 0x04 << 5 +#define GA_4_7_REG 0x05 << 5 +#define GA_5_6_REG 0x06 << 5 +#define GA_8_1_REG 0x07 << 5 + +// scale factors +#define SCALE_0_73_MG 0.73 +#define SCALE_0_92_MG 0.92 +#define SCALE_1_22_MG 1.22 +#define SCALE_1_52_MG 1.52 +#define SCALE_2_27_MG 2.27 +#define SCALE_2_56_MG 2.56 +#define SCALE_3_03_MG 3.03 +#define SCALE_4_35_MG 4.35 + +hmc5883l_context hmc5883l_init(int bus) +{ + // make sure MRAA is initialized + int mraa_rv; + if ((mraa_rv = mraa_init()) != MRAA_SUCCESS) + { + printf("%s: mraa_init() failed (%d).\n", __FUNCTION__, mraa_rv); + return NULL; + } + + hmc5883l_context dev = + (hmc5883l_context)malloc(sizeof(struct _hmc5883l_context)); + + if (!dev) + return NULL; + + // zero out context + memset((void *)dev, 0, sizeof(struct _hmc5883l_context)); + + if (!(dev->i2c = mraa_i2c_init(bus))) + { + printf("%s: mraa_i2c_init() failed.\n", __FUNCTION__); + hmc5883l_close(dev); + return NULL; + } + + // apparently only one address supported... + if (mraa_i2c_address(dev->i2c, HMC5883L_I2C_ADDR)) + { + printf("%s: mraa_i2c_address() failed.\n", __FUNCTION__); + hmc5883l_close(dev); + return NULL; + } + + // I guess we only support a single configuration... + uint8_t buf[2]; + + buf[0] = HMC5883L_CONF_REG_B; + buf[1] = GA_1_3_REG; // should be 1.2 according to DS + if (mraa_i2c_write(dev->i2c, buf, 2)) + { + printf("%s: mraa_i2c_write(HMC5883L_CONF_REG_B) failed.\n", + __FUNCTION__); + hmc5883l_close(dev); + return NULL; + } + + // ... and we only support continuous mode. + buf[0] = HMC5883L_MODE_REG; + buf[1] = HMC5883L_CONT_MODE; + if (mraa_i2c_write(dev->i2c, buf, 2)) + { + printf("%s: mraa_i2c_write(HMC5883L_MODE_REG) failed.\n", + __FUNCTION__); + hmc5883l_close(dev); + return NULL; + } + + // do an initial update + if (hmc5883l_update(dev)) + { + printf("%s: hmc5883l_update() failed.\n", __FUNCTION__); + hmc5883l_close(dev); + return NULL; + } + + return dev; +} + +void hmc5883l_close(hmc5883l_context dev) +{ + assert(dev != NULL); + + if (dev->i2c) + mraa_i2c_stop(dev->i2c); + + free(dev); +} + +upm_result_t hmc5883l_update(const hmc5883l_context dev) +{ + assert(dev != NULL); + + // set device reg address + if (mraa_i2c_write_byte(dev->i2c, HMC5883L_DATA_REG)) + { + printf("%s: mraa_i2c_write_byte(HMC5883L_DATA_REG) failed.\n", + __FUNCTION__); + return UPM_ERROR_OPERATION_FAILED; + } + + uint8_t buf[DATA_REG_SIZE]; + + // now read the data (6 bytes) + int rb; + if ((rb = mraa_i2c_read(dev->i2c, buf, DATA_REG_SIZE)) != DATA_REG_SIZE) + { + printf("%s: mraa_i2c_read() failed. Got %d bytes, expected %d.\n", + __FUNCTION__, rb, DATA_REG_SIZE); + return UPM_ERROR_OPERATION_FAILED; + } + + // The device stores the data in X, Z, Y order, however, we + // store them in X, Y, Z order. + + // x + dev->coords[0] = (buf[HMC5883L_X_MSB_REG] << 8 ) + | buf[HMC5883L_X_LSB_REG]; + // z + dev->coords[2] = (buf[HMC5883L_Z_MSB_REG] << 8 ) + | buf[HMC5883L_Z_LSB_REG]; + // y + dev->coords[1] = (buf[HMC5883L_Y_MSB_REG] << 8 ) + | buf[HMC5883L_Y_LSB_REG]; + + return UPM_SUCCESS; +} + +float hmc5883l_direction(const hmc5883l_context dev) +{ + assert(dev != NULL); + + // we seem to only support a single scale :( + return atan2(dev->coords[1] * SCALE_0_92_MG, + dev->coords[0] * SCALE_0_92_MG) + dev->declination; +} + +float hmc5883l_heading(const hmc5883l_context dev) +{ + assert(dev != NULL); + + float dir = hmc5883l_direction(dev) * 180/M_PI; + if (dir < 0) + dir += 360.0; + + return dir; +} + +const int16_t *hmc5883l_coordinates(const hmc5883l_context dev) +{ + assert(dev != NULL); + + return dev->coords; +} + +void hmc5883l_set_declination(const hmc5883l_context dev, float dec) +{ + assert(dev != NULL); + + dev->declination = dec; +} + +float hmc5883l_get_declination(const hmc5883l_context dev) +{ + assert(dev != NULL); + + return dev->declination; +} diff --git a/src/hmc5883l/hmc5883l.cxx b/src/hmc5883l/hmc5883l.cxx index fc8f690b..5b90ac48 100644 --- a/src/hmc5883l/hmc5883l.cxx +++ b/src/hmc5883l/hmc5883l.cxx @@ -1,4 +1,8 @@ /* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * Ported based on original C++ code by: * Author: Brendan Le Foll * Contributions: Mihai Tudor Panu * Copyright (c) 2014 Intel Corporation. @@ -26,146 +30,52 @@ #include #include -#include "math.h" #include "hmc5883l.hpp" -#define MAX_BUFFER_LENGTH 6 -#define HMC5883L_I2C_ADDR 0x1E - -//configuration registers -#define HMC5883L_CONF_REG_A 0x00 -#define HMC5883L_CONF_REG_B 0x01 - -//mode register -#define HMC5883L_MODE_REG 0x02 - -//data register -#define HMC5883L_X_MSB_REG 0 -#define HMC5883L_X_LSB_REG 1 -#define HMC5883L_Z_MSB_REG 2 -#define HMC5883L_Z_LSB_REG 3 -#define HMC5883L_Y_MSB_REG 4 -#define HMC5883L_Y_LSB_REG 5 -#define DATA_REG_SIZE 6 - -//status register -#define HMC5883L_STATUS_REG 0x09 - -//ID registers -#define HMC5883L_ID_A_REG 0x0A -#define HMC5883L_ID_B_REG 0x0B -#define HMC5883L_ID_C_REG 0x0C - -#define HMC5883L_CONT_MODE 0x00 -#define HMC5883L_DATA_REG 0x03 - -//scales -#define GA_0_88_REG 0x00 << 5 -#define GA_1_3_REG 0x01 << 5 -#define GA_1_9_REG 0x02 << 5 -#define GA_2_5_REG 0x03 << 5 -#define GA_4_0_REG 0x04 << 5 -#define GA_4_7_REG 0x05 << 5 -#define GA_5_6_REG 0x06 << 5 -#define GA_8_1_REG 0x07 << 5 - -//digital resolutions -#define SCALE_0_73_MG 0.73 -#define SCALE_0_92_MG 0.92 -#define SCALE_1_22_MG 1.22 -#define SCALE_1_52_MG 1.52 -#define SCALE_2_27_MG 2.27 -#define SCALE_2_56_MG 2.56 -#define SCALE_3_03_MG 3.03 -#define SCALE_4_35_MG 4.35 using namespace upm; +using namespace std; -Hmc5883l::Hmc5883l(int bus) : m_i2c(bus) +Hmc5883l::Hmc5883l(int bus) : + m_hmc5883l(hmc5883l_init(bus)) { - mraa::Result error; - error = m_i2c.address(HMC5883L_I2C_ADDR); - if(error != mraa::SUCCESS){ - throw std::invalid_argument(std::string(__FUNCTION__) + - ": i2c.address() failed"); - return; - } - m_rx_tx_buf[0] = HMC5883L_CONF_REG_B; - m_rx_tx_buf[1] = GA_1_3_REG; - error = m_i2c.write(m_rx_tx_buf, 2); - if(error != mraa::SUCCESS){ - throw std::runtime_error(std::string(__FUNCTION__) + - ": i2c.write() configuration failed"); - return; - } - - error = m_i2c.address(HMC5883L_I2C_ADDR); - if(error != mraa::SUCCESS){ - throw std::invalid_argument(std::string(__FUNCTION__) + - ": i2c.address() failed"); - return; - } - m_rx_tx_buf[0] = HMC5883L_MODE_REG; - m_rx_tx_buf[1] = HMC5883L_CONT_MODE; - error = m_i2c.write(m_rx_tx_buf, 2); - if(error != mraa::SUCCESS){ - throw std::runtime_error(std::string(__FUNCTION__) + - ": i2c.write() mode failed"); - return; - } - - Hmc5883l::update(); + if (!m_hmc5883l) + throw std::runtime_error(string(__FUNCTION__) + + ": hmc5883l_init() failed"); } -mraa::Result -Hmc5883l::update(void) +upm_result_t Hmc5883l::update(void) { - m_i2c.address(HMC5883L_I2C_ADDR); - m_i2c.writeByte(HMC5883L_DATA_REG); + if (hmc5883l_update(m_hmc5883l)) + throw std::runtime_error(string(__FUNCTION__) + + ": hmc5883l_update() failed"); - m_i2c.address(HMC5883L_I2C_ADDR); - m_i2c.read(m_rx_tx_buf, DATA_REG_SIZE); - - // x - m_coor[0] = (m_rx_tx_buf[HMC5883L_X_MSB_REG] << 8 ) | m_rx_tx_buf[HMC5883L_X_LSB_REG]; - // z - m_coor[2] = (m_rx_tx_buf[HMC5883L_Z_MSB_REG] << 8 ) | m_rx_tx_buf[HMC5883L_Z_LSB_REG]; - // y - m_coor[1] = (m_rx_tx_buf[HMC5883L_Y_MSB_REG] << 8 ) | m_rx_tx_buf[HMC5883L_Y_LSB_REG]; - - return mraa::SUCCESS; + // kind of pointless, but want to maintain some compatibility with + // original code. + return UPM_SUCCESS; } -float -Hmc5883l::direction(void) +float Hmc5883l::direction(void) { - return atan2(m_coor[1] * SCALE_0_92_MG, m_coor[0] * SCALE_0_92_MG) + m_declination; + return hmc5883l_direction(m_hmc5883l); } -float -Hmc5883l::heading(void) +float Hmc5883l::heading(void) { - float dir = Hmc5883l::direction() * 180/M_PI; - if(dir < 0){ - dir += 360.0; - } - return dir; + return hmc5883l_heading(m_hmc5883l); } -int16_t* -Hmc5883l::coordinates(void) +const int16_t *Hmc5883l::coordinates(void) { - return &m_coor[0]; + return hmc5883l_coordinates(m_hmc5883l); } -void -Hmc5883l::set_declination(float dec) +void Hmc5883l::set_declination(float dec) { - m_declination = dec; + return hmc5883l_set_declination(m_hmc5883l, dec); } -float -Hmc5883l::get_declination() +float Hmc5883l::get_declination() { - return m_declination; + return hmc5883l_get_declination(m_hmc5883l); } diff --git a/src/hmc5883l/hmc5883l.h b/src/hmc5883l/hmc5883l.h new file mode 100644 index 00000000..2edb07f4 --- /dev/null +++ b/src/hmc5883l/hmc5883l.h @@ -0,0 +1,132 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * Ported based on original C++ code by: + * Author: Brendan Le Foll + * Contributions: Mihai Tudor Panu + * 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 +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @file hmc5883l.h + * @library hmc5883l + * @brief HMC5883L 3-Axis Digital Compass + * + */ + + /** + * Device context + */ + typedef struct _hmc5883l_context { + mraa_i2c_context i2c; + + int16_t coords[3]; + float declination; + } *hmc5883l_context; + + + /** + * Initialize an Hmc5883l device + * + * @param bus Number of the used I2C bus + * @return Device context, or NULL on error + */ + hmc5883l_context hmc5883l_init(int bus); + + /** + * Close the device + * + * @param Device context + */ + void hmc5883l_close(hmc5883l_context dev); + + /** + * Updates the values by reading from I2C + * + * @param Device context + * @return UPM result + */ + upm_result_t hmc5883l_update(const hmc5883l_context dev); + + /* + * Returns the direction. hmc5883l_update() must have been called + * prior to calling this function. + * + * @param Device context + * @return Direction + */ + float hmc5883l_direction(const hmc5883l_context dev); + + /* + * Returns the heading. hmc5883l_update() must have been called + * prior to calling this function. + * + * @param Device context + * @return Heading + */ + float hmc5883l_heading(const hmc5883l_context dev); + + /** + * Returns a pointer to an int[3] that contains the coordinates as + * integers. hmc5883l_update() must have been called prior to calling + * this function. + * + * @param Device context + * @return *int to an int[3] (X, Y, Z) + */ + const int16_t *hmc5883l_coordinates(const hmc5883l_context dev); + + /** + * Sets the magnetic declination for better accuracy. + * hmc5883l_update() must have been called prior to calling this + * function. + * + * @param Device context + * @param dec The magnetic declination + */ + void hmc5883l_set_declination(const hmc5883l_context dev, float dec); + + /** + * Gets the current magnetic declination value. hmc5883l_update() + * must have been called prior to calling this function. + * + * @param Device context + * @return Magnetic declination as a floating-point value + */ + float hmc5883l_get_declination(const hmc5883l_context dev); + +#ifdef __cplusplus +} +#endif diff --git a/src/hmc5883l/hmc5883l.hpp b/src/hmc5883l/hmc5883l.hpp index 3bd8b764..edbd5e89 100644 --- a/src/hmc5883l/hmc5883l.hpp +++ b/src/hmc5883l/hmc5883l.hpp @@ -1,4 +1,8 @@ /* + * Author: Jon Trulson + * Copyright (c) 2017 Intel Corporation. + * + * Ported based on original C++ code by: * Author: Brendan Le Foll * Contributions: Mihai Tudor Panu * Copyright (c) 2014 Intel Corporation. @@ -24,88 +28,87 @@ */ #pragma once -#include - -#define MAX_BUFFER_LENGTH 6 +#include "hmc5883l.h" namespace upm { -/** - * @brief HMC5883L Magnometer library - * @defgroup hmc5883l libupm-hmc5883l - * @ingroup seeed i2c compass robok - */ - -/** - * @library hmc5883l - * @sensor hmc5883l - * @comname HMC5883L 3-Axis Digital Compass - * @altname Grove 3-Axis Digital Compass - * @type compass - * @man seeed - * @con i2c - * @kit robok - * - * @brief API for the HMC5883L 3-Axis Digital Compass - * - * Honeywell [HMC5883L] - * (http://www.adafruit.com/datasheets/HMC5883L_3-Axis_Digital_Compass_IC.pdf) - * is a 3-axis digital compass. Communication with HMC5883L is simple and - * all done through an I2C interface. Different breakout boards are available. - * Typically, a 3V supply is all that is needed to power the sensor. - * - * @image html hmc5883l.jpeg - * @snippet hmc5883l.cxx Interesting - */ -class Hmc5883l { -public: /** - * Creates an Hmc5883l object + * @brief HMC5883L Magnometer library + * @defgroup hmc5883l libupm-hmc5883l + * @ingroup seeed i2c compass robok + */ + + /** + * @library hmc5883l + * @sensor hmc5883l + * @comname HMC5883L 3-Axis Digital Compass + * @altname Grove 3-Axis Digital Compass + * @type compass + * @man seeed + * @con i2c + * @kit robok * - * @param bus Number of the used I2C bus - */ - Hmc5883l(int bus); - - /* - * Returns the direction - */ - float direction(); - - /* - * Returns the heading - */ - float heading(); - - /** - * Returns a pointer to an int[3] that contains the coordinates as ints + * @brief API for the HMC5883L 3-Axis Digital Compass * - * @return *int to an int[3] - */ - int16_t* coordinates(); - - /** - * Updates the values by reading from I2C + * Honeywell [HMC5883L] + * (http://www.adafruit.com/datasheets/HMC5883L_3-Axis_Digital_Compass_IC.pdf) + * is a 3-axis digital compass. Communication with HMC5883L is + * simple and all done through an I2C interface. Different + * breakout boards are available. Typically, a 3V supply is all + * that is needed to power the sensor. * - * @return 0 if successful + * @image html hmc5883l.jpeg + * @snippet hmc5883l.cxx Interesting */ - mraa::Result update(); + class Hmc5883l { + public: + /** + * Creates an Hmc5883l object. The I2C address cannot be + * changed, and is always 0x1e (7-bit). + * + * @param bus I2C bus number + */ + Hmc5883l(int bus); - /** - * Sets the magnetic declination for better calibration - */ - void set_declination(float dec); + /* + * Returns the direction + */ + float direction(); - /** - * Gets the current magnetic declination value - * - * @return Magnetic declination as a floating-point value - */ - float get_declination(); -private: - int16_t m_coor[3]; - float m_declination; - uint8_t m_rx_tx_buf[MAX_BUFFER_LENGTH]; - mraa::I2c m_i2c; -}; + /* + * Returns the heading + */ + float heading(); + /** + * Returns a pointer to an int[3] that contains the coordinates as ints + * + * @return *int to an int[3] + */ + const int16_t* coordinates(); + + /** + * Updates the values by reading from I2C + * + * @return 0 if successful + */ + upm_result_t update(); + + /** + * Sets the magnetic declination for better calibration + */ + void set_declination(float dec); + + /** + * Gets the current magnetic declination value + * + * @return Magnetic declination as a floating-point value + */ + float get_declination(); + + protected: + hmc5883l_context m_hmc5883l; + + private: + }; } diff --git a/src/hmc5883l/hmc5883l_fti.c b/src/hmc5883l/hmc5883l_fti.c new file mode 100644 index 00000000..99db31a8 --- /dev/null +++ b/src/hmc5883l/hmc5883l_fti.c @@ -0,0 +1,87 @@ +/* + * Author: Jon Trulson + * Copyright (c) 2017 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 "hmc5883l.h" +#include "upm_fti.h" + +/** + * This file implements the Function Table Interface (FTI) for this sensor + */ + +const char upm_hmc5883l_name[] = "HMC5883L"; +const char upm_hmc5883l_description[] = "HMC5883L Compass"; +const upm_protocol_t upm_hmc5883l_protocol[] = {UPM_I2C}; +const upm_sensor_t upm_hmc5883l_category[] = {UPM_COMPASS}; + +// forward declarations +const void* upm_hmc5883l_get_ft(upm_sensor_t sensor_type); +void* upm_hmc5883l_init_name(); +void upm_hmc5883l_close(void *dev); +upm_result_t upm_hmc5883l_get_heading(void *dev, float *value); + +static const upm_sensor_ft ft = +{ + .upm_sensor_init_name = upm_hmc5883l_init_name, + .upm_sensor_close = upm_hmc5883l_close, +}; + +static const upm_compass_ft cft = +{ + .upm_compass_get_value = upm_hmc5883l_get_heading, +}; + +const void* upm_hmc5883l_get_ft(upm_sensor_t sensor_type) +{ + switch(sensor_type) + { + case UPM_SENSOR: + return &ft; + case UPM_COMPASS: + return &cft; + default: + return NULL; + } +} + +void* upm_hmc5883l_init_name() +{ + return NULL; +} + +void upm_hmc5883l_close(void *dev) +{ + hmc5883l_close((hmc5883l_context)dev); +} + +upm_result_t upm_hmc5883l_get_heading(void *dev, float *value) +{ + upm_result_t rv; + + if ((rv = hmc5883l_update((hmc5883l_context)dev))) + return rv; + + *value = hmc5883l_heading((hmc5883l_context)dev); + + return UPM_SUCCESS; +}