forking microbit-dal

Dependencies:   BLE_API mbed-dev-bin nRF51822-bluetooth-mdw

Fork of microbit-dal by Martin Woolley

Revision:
1:8aa5cdb4ab67
Child:
41:da05ec75cd5d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/inc/drivers/MicroBitCompass.h	Thu Apr 07 01:33:22 2016 +0100
@@ -0,0 +1,518 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2016 British Broadcasting Corporation.
+This software is provided by Lancaster University by arrangement with the BBC.
+
+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 MICROBIT_COMPASS_H
+#define MICROBIT_COMPASS_H
+
+#include "mbed.h"
+#include "MicroBitConfig.h"
+#include "MicroBitComponent.h"
+#include "MicroBitCoordinateSystem.h"
+#include "MicroBitAccelerometer.h"
+#include "MicroBitStorage.h"
+
+/**
+  * Relevant pin assignments
+  */
+#define MICROBIT_PIN_COMPASS_DATA_READY          P0_29
+
+/**
+  * I2C constants
+  */
+#define MAG3110_DEFAULT_ADDR    0x1D
+
+/**
+  * MAG3110 Register map
+  */
+#define MAG_DR_STATUS 0x00
+#define MAG_OUT_X_MSB 0x01
+#define MAG_OUT_X_LSB 0x02
+#define MAG_OUT_Y_MSB 0x03
+#define MAG_OUT_Y_LSB 0x04
+#define MAG_OUT_Z_MSB 0x05
+#define MAG_OUT_Z_LSB 0x06
+#define MAG_WHOAMI    0x07
+#define MAG_SYSMOD    0x08
+#define MAG_OFF_X_MSB 0x09
+#define MAG_OFF_X_LSB 0x0A
+#define MAG_OFF_Y_MSB 0x0B
+#define MAG_OFF_Y_LSB 0x0C
+#define MAG_OFF_Z_MSB 0x0D
+#define MAG_OFF_Z_LSB 0x0E
+#define MAG_DIE_TEMP  0x0F
+#define MAG_CTRL_REG1 0x10
+#define MAG_CTRL_REG2 0x11
+
+/**
+  * Configuration options
+  */
+struct MAG3110SampleRateConfig
+{
+    uint32_t        sample_period;
+    uint8_t         ctrl_reg1;
+};
+
+extern const MAG3110SampleRateConfig MAG3110SampleRate[];
+
+#define MAG3110_SAMPLE_RATES                    11
+
+/**
+  * Compass events
+  */
+#define MICROBIT_COMPASS_EVT_CAL_REQUIRED       1               // DEPRECATED
+#define MICROBIT_COMPASS_EVT_CAL_START          2               // DEPRECATED
+#define MICROBIT_COMPASS_EVT_CAL_END            3               // DEPRECATED
+
+#define MICROBIT_COMPASS_EVT_DATA_UPDATE        4
+#define MICROBIT_COMPASS_EVT_CONFIG_NEEDED      5
+#define MICROBIT_COMPASS_EVT_CALIBRATE          6
+
+/**
+  * Status Bits
+  */
+#define MICROBIT_COMPASS_STATUS_CALIBRATED      2
+#define MICROBIT_COMPASS_STATUS_CALIBRATING     4
+#define MICROBIT_COMPASS_STATUS_ADDED_TO_IDLE   8
+
+/**
+  * Term to convert sample data into SI units
+  */
+#define MAG3110_NORMALIZE_SAMPLE(x) (100*x)
+
+/**
+  * MAG3110 MAGIC ID value
+  * Returned from the MAG_WHO_AM_I register for ID purposes.
+  */
+#define MAG3110_WHOAMI_VAL 0xC4
+
+struct CompassSample
+{
+    int     x;
+    int     y;
+    int     z;
+
+    CompassSample()
+    {
+        this->x = 0;
+        this->y = 0;
+        this->z = 0;
+    }
+
+    CompassSample(int x, int y, int z)
+    {
+        this->x = x;
+        this->y = y;
+        this->z = z;
+    }
+
+    bool operator==(const CompassSample& other) const
+    {
+        return x == other.x && y == other.y && z == other.z;
+    }
+
+    bool operator!=(const CompassSample& other) const
+    {
+        return !(x == other.x && y == other.y && z == other.z);
+    }
+};
+
+/**
+  * Class definition for MicroBit Compass.
+  *
+  * Represents an implementation of the Freescale MAG3110 I2C Magnetmometer.
+  * Also includes basic caching, calibration and on demand activation.
+  */
+class MicroBitCompass : public MicroBitComponent
+{
+    uint16_t                address;                  // I2C address of the magnetmometer.
+    uint16_t                samplePeriod;             // The time between samples, in millseconds.
+
+    CompassSample           average;                  // Centre point of sample data.
+    CompassSample           sample;                   // The latest sample data recorded.
+    DigitalIn               int1;                     // Data ready interrupt.
+    MicroBitI2C&		    i2c;                      // The I2C interface the sensor is connected to.
+    MicroBitAccelerometer*  accelerometer;            // The accelerometer to use for tilt compensation.
+    MicroBitStorage*        storage;                  // An instance of MicroBitStorage used for persistence.
+
+    public:
+
+    /**
+      * Constructor.
+      * Create a software representation of an e-compass.
+      *
+      * @param _i2c an instance of i2c, which the compass is accessible from.
+      *
+      * @param _accelerometer an instance of the accelerometer, used for tilt compensation.
+      *
+      * @param _storage an instance of MicroBitStorage, used to persist calibration data across resets.
+      *
+      * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @code
+      * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+      *
+      * MicroBitAccelerometer accelerometer(i2c);
+      *
+      * MicroBitStorage storage;
+      *
+      * MicroBitCompass compass(i2c, accelerometer, storage);
+      * @endcode
+      */
+    MicroBitCompass(MicroBitI2C& _i2c, MicroBitAccelerometer& _accelerometer, MicroBitStorage& _storage, uint16_t address = MAG3110_DEFAULT_ADDR, uint16_t id = MICROBIT_ID_COMPASS);
+
+    /**
+      * Constructor.
+      * Create a software representation of an e-compass.
+      *
+      * @param _i2c an instance of i2c, which the compass is accessible from.
+      *
+      * @param _accelerometer an instance of the accelerometer, used for tilt compensation.
+      *
+      * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @code
+      * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+      *
+      * MicroBitAccelerometer accelerometer(i2c);
+      *
+      * MicroBitCompass compass(i2c, accelerometer, storage);
+      * @endcode
+      */
+    MicroBitCompass(MicroBitI2C& _i2c, MicroBitAccelerometer& _accelerometer, uint16_t address = MAG3110_DEFAULT_ADDR, uint16_t id = MICROBIT_ID_COMPASS);
+
+    /**
+      * Constructor.
+      * Create a software representation of an e-compass.
+      *
+      * @param _i2c an instance of i2c, which the compass is accessible from.
+      *
+      * @param _storage an instance of MicroBitStorage, used to persist calibration data across resets.
+      *
+      * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @code
+      * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+      *
+      * MicroBitStorage storage;
+      *
+      * MicroBitCompass compass(i2c, storage);
+      * @endcode
+      */
+    MicroBitCompass(MicroBitI2C& _i2c, MicroBitStorage& _storage, uint16_t address = MAG3110_DEFAULT_ADDR, uint16_t id = MICROBIT_ID_COMPASS);
+
+    /**
+      * Constructor.
+      * Create a software representation of an e-compass.
+      *
+      * @param _i2c an instance of i2c, which the compass is accessible from.
+      *
+      * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
+      *
+      * @code
+      * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
+      *
+      * MicroBitCompass compass(i2c);
+      * @endcode
+      */
+    MicroBitCompass(MicroBitI2C& _i2c, uint16_t address = MAG3110_DEFAULT_ADDR, uint16_t id = MICROBIT_ID_COMPASS);
+
+    /**
+      * Configures the compass for the sample rate defined in this object.
+      * The nearest values are chosen to those defined that are supported by the hardware.
+      * The instance variables are then updated to reflect reality.
+      *
+      * @return MICROBIT_OK or MICROBIT_I2C_ERROR if the magnetometer could not be configured.
+      */
+    int configure();
+
+    /**
+      * Attempts to set the sample rate of the compass to the specified value (in ms).
+      *
+      * @param period the requested time between samples, in milliseconds.
+      *
+      * @return MICROBIT_OK or MICROBIT_I2C_ERROR if the magnetometer could not be updated.
+      *
+      * @code
+      * // sample rate is now 20 ms.
+      * compass.setPeriod(20);
+      * @endcode
+      *
+      * @note The requested rate may not be possible on the hardware. In this case, the
+      * nearest lower rate is chosen.
+      */
+    int setPeriod(int period);
+
+    /**
+      * Reads the currently configured sample rate of the compass.
+      *
+      * @return The time between samples, in milliseconds.
+      */
+    int getPeriod();
+
+    /**
+      * Gets the current heading of the device, relative to magnetic north.
+      *
+      * If the compass is not calibrated, it will raise the MICROBIT_COMPASS_EVT_CALIBRATE event.
+      *
+      * Users wishing to implement their own calibration algorithms should listen for this event,
+      * using MESSAGE_BUS_LISTENER_IMMEDIATE model. This ensures that calibration is complete before
+      * the user program continues.
+      *
+      * @return the current heading, in degrees. Or MICROBIT_CALIBRATION_IN_PROGRESS if the compass is calibrating.
+      *
+      * @code
+      * compass.heading();
+      * @endcode
+      */
+    int heading();
+
+    /**
+      * Attempts to read the 8 bit ID from the magnetometer, this can be used for
+      * validation purposes.
+      *
+      * @return the 8 bit ID returned by the magnetometer, or MICROBIT_I2C_ERROR if the request fails.
+      *
+      * @code
+      * compass.whoAmI();
+      * @endcode
+      */
+    int whoAmI();
+
+    /**
+      * Reads the value of the X axis from the latest update retrieved from the magnetometer.
+      *
+      * @param system The coordinate system to use. By default, a simple cartesian system is provided.
+      *
+      * @return The magnetic force measured in the X axis, in nano teslas.
+      *
+      * @code
+      * compass.getX();
+      * @endcode
+      */
+    int getX(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
+
+    /**
+      * Reads the value of the Y axis from the latest update retrieved from the magnetometer.
+      *
+      * @param system The coordinate system to use. By default, a simple cartesian system is provided.
+      *
+      * @return The magnetic force measured in the Y axis, in nano teslas.
+      *
+      * @code
+      * compass.getY();
+      * @endcode
+      */
+    int getY(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
+
+    /**
+      * Reads the value of the Z axis from the latest update retrieved from the magnetometer.
+      *
+      * @param system The coordinate system to use. By default, a simple cartesian system is provided.
+      *
+      * @return The magnetic force measured in the Z axis, in nano teslas.
+      *
+      * @code
+      * compass.getZ();
+      * @endcode
+      */
+    int getZ(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
+
+    /**
+      * Determines the overall magnetic field strength based on the latest update from the magnetometer.
+      *
+      * @return The magnetic force measured across all axis, in nano teslas.
+      *
+      * @code
+      * compass.getFieldStrength();
+      * @endcode
+      */
+    int getFieldStrength();
+
+    /**
+      * Reads the current die temperature of the compass.
+      *
+      * @return the temperature in degrees celsius, or MICROBIT_I2C_ERROR if the temperature reading could not be retreived
+      *         from the accelerometer.
+      */
+    int readTemperature();
+
+    /**
+      * Perform a calibration of the compass.
+      *
+      * This method will be called automatically if a user attempts to read a compass value when
+      * the compass is uncalibrated. It can also be called at any time by the user.
+      *
+      * The method will only return once the compass has been calibrated.
+      *
+      * @return MICROBIT_OK, MICROBIT_I2C_ERROR if the magnetometer could not be accessed,
+      * or MICROBIT_CALIBRATION_REQUIRED if the calibration algorithm failed to complete successfully.
+      *
+      * @note THIS MUST BE CALLED TO GAIN RELIABLE VALUES FROM THE COMPASS
+      */
+    int calibrate();
+
+    /**
+      * Configure the compass to use the calibration data that is supplied to this call.
+      *
+      * Calibration data is comprised of the perceived zero offset of each axis of the compass.
+      *
+      * After calibration this should now take into account trimming errors in the magnetometer,
+      * and any "hard iron" offsets on the device.
+      *
+      * @param calibration A CompassSample containing the offsets for the x, y and z axis.
+      */
+    void setCalibration(CompassSample calibration);
+
+    /**
+      * Provides the calibration data currently in use by the compass.
+      *
+      * More specifically, the x, y and z zero offsets of the compass.
+      *
+      * @return calibration A CompassSample containing the offsets for the x, y and z axis.
+      */
+    CompassSample getCalibration();
+
+    /**
+      * Updates the local sample, only if the compass indicates that
+      * data is stale.
+      *
+      * @note Can be used to trigger manual updates, if the device is running without a scheduler.
+      *       Also called internally by all get[X,Y,Z]() member functions.
+      */
+    int updateSample();
+
+    /**
+      * Periodic callback from MicroBit idle thread.
+      *
+      * Calls updateSample().
+      */
+    virtual void idleTick();
+
+    /**
+      * Returns 0 or 1. 1 indicates that the compass is calibrated, zero means the compass requires calibration.
+      */
+    int isCalibrated();
+
+    /**
+      * Returns 0 or 1. 1 indicates that the compass is calibrating, zero means the compass is not currently calibrating.
+      */
+    int isCalibrating();
+
+    /**
+      * Clears the calibration held in persistent storage, and sets the calibrated flag to zero.
+      */
+    void clearCalibration();
+
+    /**
+      * Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read.
+      */
+    virtual int isIdleCallbackNeeded();
+
+    /**
+      * Destructor for MicroBitCompass, where we deregister this instance from the array of fiber components.
+      */
+    ~MicroBitCompass();
+
+    private:
+
+    /**
+      * Issues a standard, 2 byte I2C command write to the accelerometer.
+      *
+      * Blocks the calling thread until complete.
+      *
+      * @param reg The address of the register to write to.
+      *
+      * @param value The value to write.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
+      */
+    int writeCommand(uint8_t reg, uint8_t value);
+
+    /**
+      * Issues a read command, copying data into the specified buffer.
+      *
+      * Blocks the calling thread until complete.
+      *
+      * @param reg The address of the register to access.
+      *
+      * @param buffer Memory area to read the data into.
+      *
+      * @param length The number of bytes to read.
+      *
+      * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
+      */
+    int readCommand(uint8_t reg, uint8_t* buffer, int length);
+
+    /**
+      * Issues a read of a given address, and returns the value.
+      *
+      * Blocks the calling thread until complete.
+      *
+      * @param reg The address of the 16 bit register to access.
+      *
+      * @return The register value, interpreted as a 16 but signed value, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed.
+      */
+    int read16(uint8_t reg);
+
+    /**
+      * Issues a read of a given address, and returns the value.
+      *
+      * Blocks the calling thread until complete.
+      *
+      * @param reg The address of the 16 bit register to access.
+      *
+      * @return The register value, interpreted as a 8 bit unsigned value, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed.
+      */
+    int read8(uint8_t reg);
+
+    /**
+      * Calculates a tilt compensated bearing of the device, using the accelerometer.
+      */
+    int tiltCompensatedBearing();
+
+    /**
+      * Calculates a non-tilt compensated bearing of the device.
+      */
+    int basicBearing();
+
+    /**
+      * An initialisation member function used by the many constructors of MicroBitCompass.
+      *
+      * @param id the unique identifier for this compass instance.
+      *
+      * @param address the base address of the magnetometer on the i2c bus.
+      */
+    void init(uint16_t id, uint16_t address);
+};
+
+#endif