Official Sheffield ARMBand micro:bit program

Committer:
MrBedfordVan
Date:
Mon Oct 17 12:41:20 2016 +0000
Revision:
0:b9164b348919
Official Sheffield ARMBand Micro:bit program

Who changed what in which revision?

UserRevisionLine numberNew contents of line
MrBedfordVan 0:b9164b348919 1 /*
MrBedfordVan 0:b9164b348919 2 The MIT License (MIT)
MrBedfordVan 0:b9164b348919 3
MrBedfordVan 0:b9164b348919 4 Copyright (c) 2016 British Broadcasting Corporation.
MrBedfordVan 0:b9164b348919 5 This software is provided by Lancaster University by arrangement with the BBC.
MrBedfordVan 0:b9164b348919 6
MrBedfordVan 0:b9164b348919 7 Permission is hereby granted, free of charge, to any person obtaining a
MrBedfordVan 0:b9164b348919 8 copy of this software and associated documentation files (the "Software"),
MrBedfordVan 0:b9164b348919 9 to deal in the Software without restriction, including without limitation
MrBedfordVan 0:b9164b348919 10 the rights to use, copy, modify, merge, publish, distribute, sublicense,
MrBedfordVan 0:b9164b348919 11 and/or sell copies of the Software, and to permit persons to whom the
MrBedfordVan 0:b9164b348919 12 Software is furnished to do so, subject to the following conditions:
MrBedfordVan 0:b9164b348919 13
MrBedfordVan 0:b9164b348919 14 The above copyright notice and this permission notice shall be included in
MrBedfordVan 0:b9164b348919 15 all copies or substantial portions of the Software.
MrBedfordVan 0:b9164b348919 16
MrBedfordVan 0:b9164b348919 17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
MrBedfordVan 0:b9164b348919 18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
MrBedfordVan 0:b9164b348919 19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
MrBedfordVan 0:b9164b348919 20 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
MrBedfordVan 0:b9164b348919 21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
MrBedfordVan 0:b9164b348919 22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
MrBedfordVan 0:b9164b348919 23 DEALINGS IN THE SOFTWARE.
MrBedfordVan 0:b9164b348919 24 */
MrBedfordVan 0:b9164b348919 25
MrBedfordVan 0:b9164b348919 26 /**
MrBedfordVan 0:b9164b348919 27 * Class definition for MicroBit Compass.
MrBedfordVan 0:b9164b348919 28 *
MrBedfordVan 0:b9164b348919 29 * Represents an implementation of the Freescale MAG3110 I2C Magnetmometer.
MrBedfordVan 0:b9164b348919 30 * Also includes basic caching, calibration and on demand activation.
MrBedfordVan 0:b9164b348919 31 */
MrBedfordVan 0:b9164b348919 32 #include "MicroBitConfig.h"
MrBedfordVan 0:b9164b348919 33 #include "MicroBitCompass.h"
MrBedfordVan 0:b9164b348919 34 #include "MicroBitFiber.h"
MrBedfordVan 0:b9164b348919 35 #include "ErrorNo.h"
MrBedfordVan 0:b9164b348919 36
MrBedfordVan 0:b9164b348919 37 /**
MrBedfordVan 0:b9164b348919 38 * An initialisation member function used by the many constructors of MicroBitCompass.
MrBedfordVan 0:b9164b348919 39 *
MrBedfordVan 0:b9164b348919 40 * @param id the unique identifier for this compass instance.
MrBedfordVan 0:b9164b348919 41 *
MrBedfordVan 0:b9164b348919 42 * @param address the base address of the magnetometer on the i2c bus.
MrBedfordVan 0:b9164b348919 43 */
MrBedfordVan 0:b9164b348919 44 void MicroBitCompass::init(uint16_t id, uint16_t address)
MrBedfordVan 0:b9164b348919 45 {
MrBedfordVan 0:b9164b348919 46 this->id = id;
MrBedfordVan 0:b9164b348919 47 this->address = address;
MrBedfordVan 0:b9164b348919 48
MrBedfordVan 0:b9164b348919 49 // Select 10Hz update rate, with oversampling, and enable the device.
MrBedfordVan 0:b9164b348919 50 this->samplePeriod = 100;
MrBedfordVan 0:b9164b348919 51 this->configure();
MrBedfordVan 0:b9164b348919 52
MrBedfordVan 0:b9164b348919 53 // Assume that we have no calibration information.
MrBedfordVan 0:b9164b348919 54 status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED;
MrBedfordVan 0:b9164b348919 55
MrBedfordVan 0:b9164b348919 56 if(this->storage != NULL)
MrBedfordVan 0:b9164b348919 57 {
MrBedfordVan 0:b9164b348919 58 KeyValuePair *calibrationData = storage->get("compassCal");
MrBedfordVan 0:b9164b348919 59
MrBedfordVan 0:b9164b348919 60 if(calibrationData != NULL)
MrBedfordVan 0:b9164b348919 61 {
MrBedfordVan 0:b9164b348919 62 CompassSample storedSample = CompassSample();
MrBedfordVan 0:b9164b348919 63
MrBedfordVan 0:b9164b348919 64 memcpy(&storedSample, calibrationData->value, sizeof(CompassSample));
MrBedfordVan 0:b9164b348919 65
MrBedfordVan 0:b9164b348919 66 setCalibration(storedSample);
MrBedfordVan 0:b9164b348919 67
MrBedfordVan 0:b9164b348919 68 delete calibrationData;
MrBedfordVan 0:b9164b348919 69 }
MrBedfordVan 0:b9164b348919 70 }
MrBedfordVan 0:b9164b348919 71
MrBedfordVan 0:b9164b348919 72 // Indicate that we're up and running.
MrBedfordVan 0:b9164b348919 73 status |= MICROBIT_COMPONENT_RUNNING;
MrBedfordVan 0:b9164b348919 74 }
MrBedfordVan 0:b9164b348919 75
MrBedfordVan 0:b9164b348919 76 /**
MrBedfordVan 0:b9164b348919 77 * Constructor.
MrBedfordVan 0:b9164b348919 78 * Create a software representation of an e-compass.
MrBedfordVan 0:b9164b348919 79 *
MrBedfordVan 0:b9164b348919 80 * @param _i2c an instance of i2c, which the compass is accessible from.
MrBedfordVan 0:b9164b348919 81 *
MrBedfordVan 0:b9164b348919 82 * @param _accelerometer an instance of the accelerometer, used for tilt compensation.
MrBedfordVan 0:b9164b348919 83 *
MrBedfordVan 0:b9164b348919 84 * @param _storage an instance of MicroBitStorage, used to persist calibration data across resets.
MrBedfordVan 0:b9164b348919 85 *
MrBedfordVan 0:b9164b348919 86 * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
MrBedfordVan 0:b9164b348919 87 *
MrBedfordVan 0:b9164b348919 88 * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
MrBedfordVan 0:b9164b348919 89 *
MrBedfordVan 0:b9164b348919 90 * @code
MrBedfordVan 0:b9164b348919 91 * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
MrBedfordVan 0:b9164b348919 92 *
MrBedfordVan 0:b9164b348919 93 * MicroBitAccelerometer accelerometer(i2c);
MrBedfordVan 0:b9164b348919 94 *
MrBedfordVan 0:b9164b348919 95 * MicroBitStorage storage;
MrBedfordVan 0:b9164b348919 96 *
MrBedfordVan 0:b9164b348919 97 * MicroBitCompass compass(i2c, accelerometer, storage);
MrBedfordVan 0:b9164b348919 98 * @endcode
MrBedfordVan 0:b9164b348919 99 */
MrBedfordVan 0:b9164b348919 100 MicroBitCompass::MicroBitCompass(MicroBitI2C& _i2c, MicroBitAccelerometer& _accelerometer, MicroBitStorage& _storage, uint16_t address, uint16_t id) :
MrBedfordVan 0:b9164b348919 101 average(),
MrBedfordVan 0:b9164b348919 102 sample(),
MrBedfordVan 0:b9164b348919 103 int1(MICROBIT_PIN_COMPASS_DATA_READY),
MrBedfordVan 0:b9164b348919 104 i2c(_i2c),
MrBedfordVan 0:b9164b348919 105 accelerometer(&_accelerometer),
MrBedfordVan 0:b9164b348919 106 storage(&_storage)
MrBedfordVan 0:b9164b348919 107 {
MrBedfordVan 0:b9164b348919 108 init(id, address);
MrBedfordVan 0:b9164b348919 109 }
MrBedfordVan 0:b9164b348919 110
MrBedfordVan 0:b9164b348919 111 /**
MrBedfordVan 0:b9164b348919 112 * Constructor.
MrBedfordVan 0:b9164b348919 113 * Create a software representation of an e-compass.
MrBedfordVan 0:b9164b348919 114 *
MrBedfordVan 0:b9164b348919 115 * @param _i2c an instance of i2c, which the compass is accessible from.
MrBedfordVan 0:b9164b348919 116 *
MrBedfordVan 0:b9164b348919 117 * @param _accelerometer an instance of the accelerometer, used for tilt compensation.
MrBedfordVan 0:b9164b348919 118 *
MrBedfordVan 0:b9164b348919 119 * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
MrBedfordVan 0:b9164b348919 120 *
MrBedfordVan 0:b9164b348919 121 * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
MrBedfordVan 0:b9164b348919 122 *
MrBedfordVan 0:b9164b348919 123 * @code
MrBedfordVan 0:b9164b348919 124 * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
MrBedfordVan 0:b9164b348919 125 *
MrBedfordVan 0:b9164b348919 126 * MicroBitAccelerometer accelerometer(i2c);
MrBedfordVan 0:b9164b348919 127 *
MrBedfordVan 0:b9164b348919 128 * MicroBitCompass compass(i2c, accelerometer, storage);
MrBedfordVan 0:b9164b348919 129 * @endcode
MrBedfordVan 0:b9164b348919 130 */
MrBedfordVan 0:b9164b348919 131 MicroBitCompass::MicroBitCompass(MicroBitI2C& _i2c, MicroBitAccelerometer& _accelerometer, uint16_t address, uint16_t id) :
MrBedfordVan 0:b9164b348919 132 average(),
MrBedfordVan 0:b9164b348919 133 sample(),
MrBedfordVan 0:b9164b348919 134 int1(MICROBIT_PIN_COMPASS_DATA_READY),
MrBedfordVan 0:b9164b348919 135 i2c(_i2c),
MrBedfordVan 0:b9164b348919 136 accelerometer(&_accelerometer),
MrBedfordVan 0:b9164b348919 137 storage(NULL)
MrBedfordVan 0:b9164b348919 138 {
MrBedfordVan 0:b9164b348919 139 init(id, address);
MrBedfordVan 0:b9164b348919 140 }
MrBedfordVan 0:b9164b348919 141
MrBedfordVan 0:b9164b348919 142 /**
MrBedfordVan 0:b9164b348919 143 * Constructor.
MrBedfordVan 0:b9164b348919 144 * Create a software representation of an e-compass.
MrBedfordVan 0:b9164b348919 145 *
MrBedfordVan 0:b9164b348919 146 * @param _i2c an instance of i2c, which the compass is accessible from.
MrBedfordVan 0:b9164b348919 147 *
MrBedfordVan 0:b9164b348919 148 * @param _storage an instance of MicroBitStorage, used to persist calibration data across resets.
MrBedfordVan 0:b9164b348919 149 *
MrBedfordVan 0:b9164b348919 150 * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
MrBedfordVan 0:b9164b348919 151 *
MrBedfordVan 0:b9164b348919 152 * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
MrBedfordVan 0:b9164b348919 153 *
MrBedfordVan 0:b9164b348919 154 * @code
MrBedfordVan 0:b9164b348919 155 * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
MrBedfordVan 0:b9164b348919 156 *
MrBedfordVan 0:b9164b348919 157 * MicroBitStorage storage;
MrBedfordVan 0:b9164b348919 158 *
MrBedfordVan 0:b9164b348919 159 * MicroBitCompass compass(i2c, storage);
MrBedfordVan 0:b9164b348919 160 * @endcode
MrBedfordVan 0:b9164b348919 161 */
MrBedfordVan 0:b9164b348919 162 MicroBitCompass::MicroBitCompass(MicroBitI2C& _i2c, MicroBitStorage& _storage, uint16_t address, uint16_t id) :
MrBedfordVan 0:b9164b348919 163 average(),
MrBedfordVan 0:b9164b348919 164 sample(),
MrBedfordVan 0:b9164b348919 165 int1(MICROBIT_PIN_COMPASS_DATA_READY),
MrBedfordVan 0:b9164b348919 166 i2c(_i2c),
MrBedfordVan 0:b9164b348919 167 accelerometer(NULL),
MrBedfordVan 0:b9164b348919 168 storage(&_storage)
MrBedfordVan 0:b9164b348919 169 {
MrBedfordVan 0:b9164b348919 170 init(id, address);
MrBedfordVan 0:b9164b348919 171 }
MrBedfordVan 0:b9164b348919 172
MrBedfordVan 0:b9164b348919 173 /**
MrBedfordVan 0:b9164b348919 174 * Constructor.
MrBedfordVan 0:b9164b348919 175 * Create a software representation of an e-compass.
MrBedfordVan 0:b9164b348919 176 *
MrBedfordVan 0:b9164b348919 177 * @param _i2c an instance of i2c, which the compass is accessible from.
MrBedfordVan 0:b9164b348919 178 *
MrBedfordVan 0:b9164b348919 179 * @param address the default address for the compass register on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR.
MrBedfordVan 0:b9164b348919 180 *
MrBedfordVan 0:b9164b348919 181 * @param id the ID of the new MicroBitCompass object. Defaults to MAG3110_DEFAULT_ADDR.
MrBedfordVan 0:b9164b348919 182 *
MrBedfordVan 0:b9164b348919 183 * @code
MrBedfordVan 0:b9164b348919 184 * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
MrBedfordVan 0:b9164b348919 185 *
MrBedfordVan 0:b9164b348919 186 * MicroBitCompass compass(i2c);
MrBedfordVan 0:b9164b348919 187 * @endcode
MrBedfordVan 0:b9164b348919 188 */
MrBedfordVan 0:b9164b348919 189 MicroBitCompass::MicroBitCompass(MicroBitI2C& _i2c, uint16_t address, uint16_t id) :
MrBedfordVan 0:b9164b348919 190 average(),
MrBedfordVan 0:b9164b348919 191 sample(),
MrBedfordVan 0:b9164b348919 192 int1(MICROBIT_PIN_COMPASS_DATA_READY),
MrBedfordVan 0:b9164b348919 193 i2c(_i2c),
MrBedfordVan 0:b9164b348919 194 accelerometer(NULL),
MrBedfordVan 0:b9164b348919 195 storage(NULL)
MrBedfordVan 0:b9164b348919 196 {
MrBedfordVan 0:b9164b348919 197 init(id, address);
MrBedfordVan 0:b9164b348919 198 }
MrBedfordVan 0:b9164b348919 199
MrBedfordVan 0:b9164b348919 200 /**
MrBedfordVan 0:b9164b348919 201 * Issues a standard, 2 byte I2C command write to the accelerometer.
MrBedfordVan 0:b9164b348919 202 *
MrBedfordVan 0:b9164b348919 203 * Blocks the calling thread until complete.
MrBedfordVan 0:b9164b348919 204 *
MrBedfordVan 0:b9164b348919 205 * @param reg The address of the register to write to.
MrBedfordVan 0:b9164b348919 206 *
MrBedfordVan 0:b9164b348919 207 * @param value The value to write.
MrBedfordVan 0:b9164b348919 208 *
MrBedfordVan 0:b9164b348919 209 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
MrBedfordVan 0:b9164b348919 210 */
MrBedfordVan 0:b9164b348919 211 int MicroBitCompass::writeCommand(uint8_t reg, uint8_t value)
MrBedfordVan 0:b9164b348919 212 {
MrBedfordVan 0:b9164b348919 213 uint8_t command[2];
MrBedfordVan 0:b9164b348919 214 command[0] = reg;
MrBedfordVan 0:b9164b348919 215 command[1] = value;
MrBedfordVan 0:b9164b348919 216
MrBedfordVan 0:b9164b348919 217 return i2c.write(address, (const char *)command, 2);
MrBedfordVan 0:b9164b348919 218 }
MrBedfordVan 0:b9164b348919 219
MrBedfordVan 0:b9164b348919 220 /**
MrBedfordVan 0:b9164b348919 221 * Issues a read command, copying data into the specified buffer.
MrBedfordVan 0:b9164b348919 222 *
MrBedfordVan 0:b9164b348919 223 * Blocks the calling thread until complete.
MrBedfordVan 0:b9164b348919 224 *
MrBedfordVan 0:b9164b348919 225 * @param reg The address of the register to access.
MrBedfordVan 0:b9164b348919 226 *
MrBedfordVan 0:b9164b348919 227 * @param buffer Memory area to read the data into.
MrBedfordVan 0:b9164b348919 228 *
MrBedfordVan 0:b9164b348919 229 * @param length The number of bytes to read.
MrBedfordVan 0:b9164b348919 230 *
MrBedfordVan 0:b9164b348919 231 * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
MrBedfordVan 0:b9164b348919 232 */
MrBedfordVan 0:b9164b348919 233 int MicroBitCompass::readCommand(uint8_t reg, uint8_t* buffer, int length)
MrBedfordVan 0:b9164b348919 234 {
MrBedfordVan 0:b9164b348919 235 int result;
MrBedfordVan 0:b9164b348919 236
MrBedfordVan 0:b9164b348919 237 if (buffer == NULL || length <= 0)
MrBedfordVan 0:b9164b348919 238 return MICROBIT_INVALID_PARAMETER;
MrBedfordVan 0:b9164b348919 239
MrBedfordVan 0:b9164b348919 240 result = i2c.write(address, (const char *)&reg, 1, true);
MrBedfordVan 0:b9164b348919 241 if (result !=0)
MrBedfordVan 0:b9164b348919 242 return MICROBIT_I2C_ERROR;
MrBedfordVan 0:b9164b348919 243
MrBedfordVan 0:b9164b348919 244 result = i2c.read(address, (char *)buffer, length);
MrBedfordVan 0:b9164b348919 245 if (result !=0)
MrBedfordVan 0:b9164b348919 246 return MICROBIT_I2C_ERROR;
MrBedfordVan 0:b9164b348919 247
MrBedfordVan 0:b9164b348919 248 return MICROBIT_OK;
MrBedfordVan 0:b9164b348919 249 }
MrBedfordVan 0:b9164b348919 250
MrBedfordVan 0:b9164b348919 251
MrBedfordVan 0:b9164b348919 252 /**
MrBedfordVan 0:b9164b348919 253 * Issues a read of a given address, and returns the value.
MrBedfordVan 0:b9164b348919 254 *
MrBedfordVan 0:b9164b348919 255 * Blocks the calling thread until complete.
MrBedfordVan 0:b9164b348919 256 *
MrBedfordVan 0:b9164b348919 257 * @param reg The address of the 16 bit register to access.
MrBedfordVan 0:b9164b348919 258 *
MrBedfordVan 0:b9164b348919 259 * @return The register value, interpreted as a 16 but signed value, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed.
MrBedfordVan 0:b9164b348919 260 */
MrBedfordVan 0:b9164b348919 261 int MicroBitCompass::read16(uint8_t reg)
MrBedfordVan 0:b9164b348919 262 {
MrBedfordVan 0:b9164b348919 263 uint8_t cmd[2];
MrBedfordVan 0:b9164b348919 264 int result;
MrBedfordVan 0:b9164b348919 265
MrBedfordVan 0:b9164b348919 266 cmd[0] = reg;
MrBedfordVan 0:b9164b348919 267 result = i2c.write(address, (const char *)cmd, 1);
MrBedfordVan 0:b9164b348919 268 if (result !=0)
MrBedfordVan 0:b9164b348919 269 return MICROBIT_I2C_ERROR;
MrBedfordVan 0:b9164b348919 270
MrBedfordVan 0:b9164b348919 271 cmd[0] = 0x00;
MrBedfordVan 0:b9164b348919 272 cmd[1] = 0x00;
MrBedfordVan 0:b9164b348919 273
MrBedfordVan 0:b9164b348919 274 result = i2c.read(address, (char *)cmd, 2);
MrBedfordVan 0:b9164b348919 275 if (result !=0)
MrBedfordVan 0:b9164b348919 276 return MICROBIT_I2C_ERROR;
MrBedfordVan 0:b9164b348919 277
MrBedfordVan 0:b9164b348919 278 return (int16_t) ((cmd[1] | (cmd[0] << 8))); //concatenate the MSB and LSB
MrBedfordVan 0:b9164b348919 279 }
MrBedfordVan 0:b9164b348919 280
MrBedfordVan 0:b9164b348919 281 /**
MrBedfordVan 0:b9164b348919 282 * Issues a read of a given address, and returns the value.
MrBedfordVan 0:b9164b348919 283 *
MrBedfordVan 0:b9164b348919 284 * Blocks the calling thread until complete.
MrBedfordVan 0:b9164b348919 285 *
MrBedfordVan 0:b9164b348919 286 * @param reg The address of the 16 bit register to access.
MrBedfordVan 0:b9164b348919 287 *
MrBedfordVan 0:b9164b348919 288 * @return The register value, interpreted as a 8 bit unsigned value, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed.
MrBedfordVan 0:b9164b348919 289 */
MrBedfordVan 0:b9164b348919 290 int MicroBitCompass::read8(uint8_t reg)
MrBedfordVan 0:b9164b348919 291 {
MrBedfordVan 0:b9164b348919 292 uint8_t data;
MrBedfordVan 0:b9164b348919 293 int result;
MrBedfordVan 0:b9164b348919 294
MrBedfordVan 0:b9164b348919 295 data = 0;
MrBedfordVan 0:b9164b348919 296 result = readCommand(reg, (uint8_t*) &data, 1);
MrBedfordVan 0:b9164b348919 297 if (result != MICROBIT_OK)
MrBedfordVan 0:b9164b348919 298 return MICROBIT_I2C_ERROR;
MrBedfordVan 0:b9164b348919 299
MrBedfordVan 0:b9164b348919 300 return data;
MrBedfordVan 0:b9164b348919 301 }
MrBedfordVan 0:b9164b348919 302
MrBedfordVan 0:b9164b348919 303 /**
MrBedfordVan 0:b9164b348919 304 * Calculates a tilt compensated bearing of the device, using the accelerometer.
MrBedfordVan 0:b9164b348919 305 */
MrBedfordVan 0:b9164b348919 306 int MicroBitCompass::tiltCompensatedBearing()
MrBedfordVan 0:b9164b348919 307 {
MrBedfordVan 0:b9164b348919 308 // Precompute the tilt compensation parameters to improve readability.
MrBedfordVan 0:b9164b348919 309 float phi = accelerometer->getRollRadians();
MrBedfordVan 0:b9164b348919 310 float theta = accelerometer->getPitchRadians();
MrBedfordVan 0:b9164b348919 311
MrBedfordVan 0:b9164b348919 312 float x = (float) getX(NORTH_EAST_DOWN);
MrBedfordVan 0:b9164b348919 313 float y = (float) getY(NORTH_EAST_DOWN);
MrBedfordVan 0:b9164b348919 314 float z = (float) getZ(NORTH_EAST_DOWN);
MrBedfordVan 0:b9164b348919 315
MrBedfordVan 0:b9164b348919 316 // Precompute cos and sin of pitch and roll angles to make the calculation a little more efficient.
MrBedfordVan 0:b9164b348919 317 float sinPhi = sin(phi);
MrBedfordVan 0:b9164b348919 318 float cosPhi = cos(phi);
MrBedfordVan 0:b9164b348919 319 float sinTheta = sin(theta);
MrBedfordVan 0:b9164b348919 320 float cosTheta = cos(theta);
MrBedfordVan 0:b9164b348919 321
MrBedfordVan 0:b9164b348919 322 float bearing = (360*atan2(z*sinPhi - y*cosPhi, x*cosTheta + y*sinTheta*sinPhi + z*sinTheta*cosPhi)) / (2*PI);
MrBedfordVan 0:b9164b348919 323
MrBedfordVan 0:b9164b348919 324 if (bearing < 0)
MrBedfordVan 0:b9164b348919 325 bearing += 360.0;
MrBedfordVan 0:b9164b348919 326
MrBedfordVan 0:b9164b348919 327 return (int) bearing;
MrBedfordVan 0:b9164b348919 328 }
MrBedfordVan 0:b9164b348919 329
MrBedfordVan 0:b9164b348919 330 /**
MrBedfordVan 0:b9164b348919 331 * Calculates a non-tilt compensated bearing of the device.
MrBedfordVan 0:b9164b348919 332 */
MrBedfordVan 0:b9164b348919 333 int MicroBitCompass::basicBearing()
MrBedfordVan 0:b9164b348919 334 {
MrBedfordVan 0:b9164b348919 335 updateSample();
MrBedfordVan 0:b9164b348919 336
MrBedfordVan 0:b9164b348919 337 float bearing = (atan2((double)(sample.y - average.y),(double)(sample.x - average.x)))*180/PI;
MrBedfordVan 0:b9164b348919 338
MrBedfordVan 0:b9164b348919 339 if (bearing < 0)
MrBedfordVan 0:b9164b348919 340 bearing += 360.0;
MrBedfordVan 0:b9164b348919 341
MrBedfordVan 0:b9164b348919 342 return (int)(360.0 - bearing);
MrBedfordVan 0:b9164b348919 343 }
MrBedfordVan 0:b9164b348919 344
MrBedfordVan 0:b9164b348919 345 /**
MrBedfordVan 0:b9164b348919 346 * Gets the current heading of the device, relative to magnetic north.
MrBedfordVan 0:b9164b348919 347 *
MrBedfordVan 0:b9164b348919 348 * If the compass is not calibrated, it will raise the MICROBIT_COMPASS_EVT_CALIBRATE event.
MrBedfordVan 0:b9164b348919 349 *
MrBedfordVan 0:b9164b348919 350 * Users wishing to implement their own calibration algorithms should listen for this event,
MrBedfordVan 0:b9164b348919 351 * using MESSAGE_BUS_LISTENER_IMMEDIATE model. This ensures that calibration is complete before
MrBedfordVan 0:b9164b348919 352 * the user program continues.
MrBedfordVan 0:b9164b348919 353 *
MrBedfordVan 0:b9164b348919 354 * @return the current heading, in degrees. Or MICROBIT_CALIBRATION_IN_PROGRESS if the compass is calibrating.
MrBedfordVan 0:b9164b348919 355 *
MrBedfordVan 0:b9164b348919 356 * @code
MrBedfordVan 0:b9164b348919 357 * compass.heading();
MrBedfordVan 0:b9164b348919 358 * @endcode
MrBedfordVan 0:b9164b348919 359 */
MrBedfordVan 0:b9164b348919 360 int MicroBitCompass::heading()
MrBedfordVan 0:b9164b348919 361 {
MrBedfordVan 0:b9164b348919 362 if(status & MICROBIT_COMPASS_STATUS_CALIBRATING)
MrBedfordVan 0:b9164b348919 363 return MICROBIT_CALIBRATION_IN_PROGRESS;
MrBedfordVan 0:b9164b348919 364
MrBedfordVan 0:b9164b348919 365 if(!(status & MICROBIT_COMPASS_STATUS_CALIBRATED))
MrBedfordVan 0:b9164b348919 366 calibrate();
MrBedfordVan 0:b9164b348919 367
MrBedfordVan 0:b9164b348919 368 if(accelerometer != NULL)
MrBedfordVan 0:b9164b348919 369 return tiltCompensatedBearing();
MrBedfordVan 0:b9164b348919 370
MrBedfordVan 0:b9164b348919 371 return basicBearing();
MrBedfordVan 0:b9164b348919 372 }
MrBedfordVan 0:b9164b348919 373
MrBedfordVan 0:b9164b348919 374 /**
MrBedfordVan 0:b9164b348919 375 * Updates the local sample, only if the compass indicates that
MrBedfordVan 0:b9164b348919 376 * data is stale.
MrBedfordVan 0:b9164b348919 377 *
MrBedfordVan 0:b9164b348919 378 * @note Can be used to trigger manual updates, if the device is running without a scheduler.
MrBedfordVan 0:b9164b348919 379 * Also called internally by all get[X,Y,Z]() member functions.
MrBedfordVan 0:b9164b348919 380 */
MrBedfordVan 0:b9164b348919 381 int MicroBitCompass::updateSample()
MrBedfordVan 0:b9164b348919 382 {
MrBedfordVan 0:b9164b348919 383 /**
MrBedfordVan 0:b9164b348919 384 * Adds the compass to idle, if it hasn't been added already.
MrBedfordVan 0:b9164b348919 385 * This is an optimisation so that the compass is only added on first 'use'.
MrBedfordVan 0:b9164b348919 386 */
MrBedfordVan 0:b9164b348919 387 if(!(status & MICROBIT_COMPASS_STATUS_ADDED_TO_IDLE))
MrBedfordVan 0:b9164b348919 388 {
MrBedfordVan 0:b9164b348919 389 fiber_add_idle_component(this);
MrBedfordVan 0:b9164b348919 390 status |= MICROBIT_COMPASS_STATUS_ADDED_TO_IDLE;
MrBedfordVan 0:b9164b348919 391 }
MrBedfordVan 0:b9164b348919 392
MrBedfordVan 0:b9164b348919 393 // Poll interrupt line from compass (Active HI).
MrBedfordVan 0:b9164b348919 394 // Interrupt is cleared on data read of MAG_OUT_X_MSB.
MrBedfordVan 0:b9164b348919 395 if(int1)
MrBedfordVan 0:b9164b348919 396 {
MrBedfordVan 0:b9164b348919 397 sample.x = MAG3110_NORMALIZE_SAMPLE((int) read16(MAG_OUT_X_MSB));
MrBedfordVan 0:b9164b348919 398 sample.y = MAG3110_NORMALIZE_SAMPLE((int) read16(MAG_OUT_Y_MSB));
MrBedfordVan 0:b9164b348919 399 sample.z = MAG3110_NORMALIZE_SAMPLE((int) read16(MAG_OUT_Z_MSB));
MrBedfordVan 0:b9164b348919 400
MrBedfordVan 0:b9164b348919 401 // Indicate that a new sample is available
MrBedfordVan 0:b9164b348919 402 MicroBitEvent e(id, MICROBIT_COMPASS_EVT_DATA_UPDATE);
MrBedfordVan 0:b9164b348919 403 }
MrBedfordVan 0:b9164b348919 404
MrBedfordVan 0:b9164b348919 405 return MICROBIT_OK;
MrBedfordVan 0:b9164b348919 406 }
MrBedfordVan 0:b9164b348919 407
MrBedfordVan 0:b9164b348919 408 /**
MrBedfordVan 0:b9164b348919 409 * Periodic callback from MicroBit idle thread.
MrBedfordVan 0:b9164b348919 410 *
MrBedfordVan 0:b9164b348919 411 * Calls updateSample().
MrBedfordVan 0:b9164b348919 412 */
MrBedfordVan 0:b9164b348919 413 void MicroBitCompass::idleTick()
MrBedfordVan 0:b9164b348919 414 {
MrBedfordVan 0:b9164b348919 415 updateSample();
MrBedfordVan 0:b9164b348919 416 }
MrBedfordVan 0:b9164b348919 417
MrBedfordVan 0:b9164b348919 418 /**
MrBedfordVan 0:b9164b348919 419 * Reads the value of the X axis from the latest update retrieved from the magnetometer.
MrBedfordVan 0:b9164b348919 420 *
MrBedfordVan 0:b9164b348919 421 * @param system The coordinate system to use. By default, a simple cartesian system is provided.
MrBedfordVan 0:b9164b348919 422 *
MrBedfordVan 0:b9164b348919 423 * @return The magnetic force measured in the X axis, in nano teslas.
MrBedfordVan 0:b9164b348919 424 *
MrBedfordVan 0:b9164b348919 425 * @code
MrBedfordVan 0:b9164b348919 426 * compass.getX();
MrBedfordVan 0:b9164b348919 427 * @endcode
MrBedfordVan 0:b9164b348919 428 */
MrBedfordVan 0:b9164b348919 429 int MicroBitCompass::getX(MicroBitCoordinateSystem system)
MrBedfordVan 0:b9164b348919 430 {
MrBedfordVan 0:b9164b348919 431 updateSample();
MrBedfordVan 0:b9164b348919 432
MrBedfordVan 0:b9164b348919 433 switch (system)
MrBedfordVan 0:b9164b348919 434 {
MrBedfordVan 0:b9164b348919 435 case SIMPLE_CARTESIAN:
MrBedfordVan 0:b9164b348919 436 return sample.x - average.x;
MrBedfordVan 0:b9164b348919 437
MrBedfordVan 0:b9164b348919 438 case NORTH_EAST_DOWN:
MrBedfordVan 0:b9164b348919 439 return -(sample.y - average.y);
MrBedfordVan 0:b9164b348919 440
MrBedfordVan 0:b9164b348919 441 case RAW:
MrBedfordVan 0:b9164b348919 442 default:
MrBedfordVan 0:b9164b348919 443 return sample.x;
MrBedfordVan 0:b9164b348919 444 }
MrBedfordVan 0:b9164b348919 445 }
MrBedfordVan 0:b9164b348919 446
MrBedfordVan 0:b9164b348919 447 /**
MrBedfordVan 0:b9164b348919 448 * Reads the value of the Y axis from the latest update retrieved from the magnetometer.
MrBedfordVan 0:b9164b348919 449 *
MrBedfordVan 0:b9164b348919 450 * @param system The coordinate system to use. By default, a simple cartesian system is provided.
MrBedfordVan 0:b9164b348919 451 *
MrBedfordVan 0:b9164b348919 452 * @return The magnetic force measured in the Y axis, in nano teslas.
MrBedfordVan 0:b9164b348919 453 *
MrBedfordVan 0:b9164b348919 454 * @code
MrBedfordVan 0:b9164b348919 455 * compass.getY();
MrBedfordVan 0:b9164b348919 456 * @endcode
MrBedfordVan 0:b9164b348919 457 */
MrBedfordVan 0:b9164b348919 458 int MicroBitCompass::getY(MicroBitCoordinateSystem system)
MrBedfordVan 0:b9164b348919 459 {
MrBedfordVan 0:b9164b348919 460 updateSample();
MrBedfordVan 0:b9164b348919 461
MrBedfordVan 0:b9164b348919 462 switch (system)
MrBedfordVan 0:b9164b348919 463 {
MrBedfordVan 0:b9164b348919 464 case SIMPLE_CARTESIAN:
MrBedfordVan 0:b9164b348919 465 return -(sample.y - average.y);
MrBedfordVan 0:b9164b348919 466
MrBedfordVan 0:b9164b348919 467 case NORTH_EAST_DOWN:
MrBedfordVan 0:b9164b348919 468 return (sample.x - average.x);
MrBedfordVan 0:b9164b348919 469
MrBedfordVan 0:b9164b348919 470 case RAW:
MrBedfordVan 0:b9164b348919 471 default:
MrBedfordVan 0:b9164b348919 472 return sample.y;
MrBedfordVan 0:b9164b348919 473 }
MrBedfordVan 0:b9164b348919 474 }
MrBedfordVan 0:b9164b348919 475
MrBedfordVan 0:b9164b348919 476 /**
MrBedfordVan 0:b9164b348919 477 * Reads the value of the Z axis from the latest update retrieved from the magnetometer.
MrBedfordVan 0:b9164b348919 478 *
MrBedfordVan 0:b9164b348919 479 * @param system The coordinate system to use. By default, a simple cartesian system is provided.
MrBedfordVan 0:b9164b348919 480 *
MrBedfordVan 0:b9164b348919 481 * @return The magnetic force measured in the Z axis, in nano teslas.
MrBedfordVan 0:b9164b348919 482 *
MrBedfordVan 0:b9164b348919 483 * @code
MrBedfordVan 0:b9164b348919 484 * compass.getZ();
MrBedfordVan 0:b9164b348919 485 * @endcode
MrBedfordVan 0:b9164b348919 486 */
MrBedfordVan 0:b9164b348919 487 int MicroBitCompass::getZ(MicroBitCoordinateSystem system)
MrBedfordVan 0:b9164b348919 488 {
MrBedfordVan 0:b9164b348919 489 updateSample();
MrBedfordVan 0:b9164b348919 490
MrBedfordVan 0:b9164b348919 491 switch (system)
MrBedfordVan 0:b9164b348919 492 {
MrBedfordVan 0:b9164b348919 493 case SIMPLE_CARTESIAN:
MrBedfordVan 0:b9164b348919 494 case NORTH_EAST_DOWN:
MrBedfordVan 0:b9164b348919 495 return -(sample.z - average.z);
MrBedfordVan 0:b9164b348919 496
MrBedfordVan 0:b9164b348919 497 case RAW:
MrBedfordVan 0:b9164b348919 498 default:
MrBedfordVan 0:b9164b348919 499 return sample.z;
MrBedfordVan 0:b9164b348919 500 }
MrBedfordVan 0:b9164b348919 501 }
MrBedfordVan 0:b9164b348919 502
MrBedfordVan 0:b9164b348919 503 /**
MrBedfordVan 0:b9164b348919 504 * Determines the overall magnetic field strength based on the latest update from the magnetometer.
MrBedfordVan 0:b9164b348919 505 *
MrBedfordVan 0:b9164b348919 506 * @return The magnetic force measured across all axis, in nano teslas.
MrBedfordVan 0:b9164b348919 507 *
MrBedfordVan 0:b9164b348919 508 * @code
MrBedfordVan 0:b9164b348919 509 * compass.getFieldStrength();
MrBedfordVan 0:b9164b348919 510 * @endcode
MrBedfordVan 0:b9164b348919 511 */
MrBedfordVan 0:b9164b348919 512 int MicroBitCompass::getFieldStrength()
MrBedfordVan 0:b9164b348919 513 {
MrBedfordVan 0:b9164b348919 514 double x = getX();
MrBedfordVan 0:b9164b348919 515 double y = getY();
MrBedfordVan 0:b9164b348919 516 double z = getZ();
MrBedfordVan 0:b9164b348919 517
MrBedfordVan 0:b9164b348919 518 return (int) sqrt(x*x + y*y + z*z);
MrBedfordVan 0:b9164b348919 519 }
MrBedfordVan 0:b9164b348919 520
MrBedfordVan 0:b9164b348919 521 /**
MrBedfordVan 0:b9164b348919 522 * Configures the compass for the sample rate defined in this object.
MrBedfordVan 0:b9164b348919 523 * The nearest values are chosen to those defined that are supported by the hardware.
MrBedfordVan 0:b9164b348919 524 * The instance variables are then updated to reflect reality.
MrBedfordVan 0:b9164b348919 525 *
MrBedfordVan 0:b9164b348919 526 * @return MICROBIT_OK or MICROBIT_I2C_ERROR if the magnetometer could not be configured.
MrBedfordVan 0:b9164b348919 527 */
MrBedfordVan 0:b9164b348919 528 int MicroBitCompass::configure()
MrBedfordVan 0:b9164b348919 529 {
MrBedfordVan 0:b9164b348919 530 const MAG3110SampleRateConfig *actualSampleRate;
MrBedfordVan 0:b9164b348919 531 int result;
MrBedfordVan 0:b9164b348919 532
MrBedfordVan 0:b9164b348919 533 // First, take the device offline, so it can be configured.
MrBedfordVan 0:b9164b348919 534 result = writeCommand(MAG_CTRL_REG1, 0x00);
MrBedfordVan 0:b9164b348919 535 if (result != MICROBIT_OK)
MrBedfordVan 0:b9164b348919 536 return MICROBIT_I2C_ERROR;
MrBedfordVan 0:b9164b348919 537
MrBedfordVan 0:b9164b348919 538 // Wait for the part to enter standby mode...
MrBedfordVan 0:b9164b348919 539 while(1)
MrBedfordVan 0:b9164b348919 540 {
MrBedfordVan 0:b9164b348919 541 // Read the status of the part...
MrBedfordVan 0:b9164b348919 542 // If we can't communicate with it over I2C, pass on the error.
MrBedfordVan 0:b9164b348919 543 result = this->read8(MAG_SYSMOD);
MrBedfordVan 0:b9164b348919 544 if (result == MICROBIT_I2C_ERROR)
MrBedfordVan 0:b9164b348919 545 return MICROBIT_I2C_ERROR;
MrBedfordVan 0:b9164b348919 546
MrBedfordVan 0:b9164b348919 547 // if the part in in standby, we're good to carry on.
MrBedfordVan 0:b9164b348919 548 if((result & 0x03) == 0)
MrBedfordVan 0:b9164b348919 549 break;
MrBedfordVan 0:b9164b348919 550
MrBedfordVan 0:b9164b348919 551 // Perform a power efficient sleep...
MrBedfordVan 0:b9164b348919 552 fiber_sleep(100);
MrBedfordVan 0:b9164b348919 553 }
MrBedfordVan 0:b9164b348919 554
MrBedfordVan 0:b9164b348919 555 // Find the nearest sample rate to that specified.
MrBedfordVan 0:b9164b348919 556 actualSampleRate = &MAG3110SampleRate[MAG3110_SAMPLE_RATES-1];
MrBedfordVan 0:b9164b348919 557 for (int i=MAG3110_SAMPLE_RATES-1; i>=0; i--)
MrBedfordVan 0:b9164b348919 558 {
MrBedfordVan 0:b9164b348919 559 if(MAG3110SampleRate[i].sample_period < this->samplePeriod * 1000)
MrBedfordVan 0:b9164b348919 560 break;
MrBedfordVan 0:b9164b348919 561
MrBedfordVan 0:b9164b348919 562 actualSampleRate = &MAG3110SampleRate[i];
MrBedfordVan 0:b9164b348919 563 }
MrBedfordVan 0:b9164b348919 564
MrBedfordVan 0:b9164b348919 565 // OK, we have the correct data. Update our local state.
MrBedfordVan 0:b9164b348919 566 this->samplePeriod = actualSampleRate->sample_period / 1000;
MrBedfordVan 0:b9164b348919 567
MrBedfordVan 0:b9164b348919 568 // Enable automatic reset after each sample;
MrBedfordVan 0:b9164b348919 569 result = writeCommand(MAG_CTRL_REG2, 0xA0);
MrBedfordVan 0:b9164b348919 570 if (result != MICROBIT_OK)
MrBedfordVan 0:b9164b348919 571 return MICROBIT_I2C_ERROR;
MrBedfordVan 0:b9164b348919 572
MrBedfordVan 0:b9164b348919 573
MrBedfordVan 0:b9164b348919 574 // Bring the device online, with the requested sample frequency.
MrBedfordVan 0:b9164b348919 575 result = writeCommand(MAG_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01);
MrBedfordVan 0:b9164b348919 576 if (result != MICROBIT_OK)
MrBedfordVan 0:b9164b348919 577 return MICROBIT_I2C_ERROR;
MrBedfordVan 0:b9164b348919 578
MrBedfordVan 0:b9164b348919 579 return MICROBIT_OK;
MrBedfordVan 0:b9164b348919 580 }
MrBedfordVan 0:b9164b348919 581
MrBedfordVan 0:b9164b348919 582 /**
MrBedfordVan 0:b9164b348919 583 * Attempts to set the sample rate of the compass to the specified value (in ms).
MrBedfordVan 0:b9164b348919 584 *
MrBedfordVan 0:b9164b348919 585 * @param period the requested time between samples, in milliseconds.
MrBedfordVan 0:b9164b348919 586 *
MrBedfordVan 0:b9164b348919 587 * @return MICROBIT_OK or MICROBIT_I2C_ERROR if the magnetometer could not be updated.
MrBedfordVan 0:b9164b348919 588 *
MrBedfordVan 0:b9164b348919 589 * @code
MrBedfordVan 0:b9164b348919 590 * // sample rate is now 20 ms.
MrBedfordVan 0:b9164b348919 591 * compass.setPeriod(20);
MrBedfordVan 0:b9164b348919 592 * @endcode
MrBedfordVan 0:b9164b348919 593 *
MrBedfordVan 0:b9164b348919 594 * @note The requested rate may not be possible on the hardware. In this case, the
MrBedfordVan 0:b9164b348919 595 * nearest lower rate is chosen.
MrBedfordVan 0:b9164b348919 596 */
MrBedfordVan 0:b9164b348919 597 int MicroBitCompass::setPeriod(int period)
MrBedfordVan 0:b9164b348919 598 {
MrBedfordVan 0:b9164b348919 599 this->samplePeriod = period;
MrBedfordVan 0:b9164b348919 600 return this->configure();
MrBedfordVan 0:b9164b348919 601 }
MrBedfordVan 0:b9164b348919 602
MrBedfordVan 0:b9164b348919 603 /**
MrBedfordVan 0:b9164b348919 604 * Reads the currently configured sample rate of the compass.
MrBedfordVan 0:b9164b348919 605 *
MrBedfordVan 0:b9164b348919 606 * @return The time between samples, in milliseconds.
MrBedfordVan 0:b9164b348919 607 */
MrBedfordVan 0:b9164b348919 608 int MicroBitCompass::getPeriod()
MrBedfordVan 0:b9164b348919 609 {
MrBedfordVan 0:b9164b348919 610 return (int)samplePeriod;
MrBedfordVan 0:b9164b348919 611 }
MrBedfordVan 0:b9164b348919 612
MrBedfordVan 0:b9164b348919 613 /**
MrBedfordVan 0:b9164b348919 614 * Attempts to read the 8 bit ID from the magnetometer, this can be used for
MrBedfordVan 0:b9164b348919 615 * validation purposes.
MrBedfordVan 0:b9164b348919 616 *
MrBedfordVan 0:b9164b348919 617 * @return the 8 bit ID returned by the magnetometer, or MICROBIT_I2C_ERROR if the request fails.
MrBedfordVan 0:b9164b348919 618 *
MrBedfordVan 0:b9164b348919 619 * @code
MrBedfordVan 0:b9164b348919 620 * compass.whoAmI();
MrBedfordVan 0:b9164b348919 621 * @endcode
MrBedfordVan 0:b9164b348919 622 */
MrBedfordVan 0:b9164b348919 623 int MicroBitCompass::whoAmI()
MrBedfordVan 0:b9164b348919 624 {
MrBedfordVan 0:b9164b348919 625 uint8_t data;
MrBedfordVan 0:b9164b348919 626 int result;
MrBedfordVan 0:b9164b348919 627
MrBedfordVan 0:b9164b348919 628 result = readCommand(MAG_WHOAMI, &data, 1);
MrBedfordVan 0:b9164b348919 629 if (result != MICROBIT_OK)
MrBedfordVan 0:b9164b348919 630 return MICROBIT_I2C_ERROR;
MrBedfordVan 0:b9164b348919 631
MrBedfordVan 0:b9164b348919 632 return (int)data;
MrBedfordVan 0:b9164b348919 633 }
MrBedfordVan 0:b9164b348919 634
MrBedfordVan 0:b9164b348919 635 /**
MrBedfordVan 0:b9164b348919 636 * Reads the current die temperature of the compass.
MrBedfordVan 0:b9164b348919 637 *
MrBedfordVan 0:b9164b348919 638 * @return the temperature in degrees celsius, or MICROBIT_I2C_ERROR if the temperature reading could not be retreived
MrBedfordVan 0:b9164b348919 639 * from the accelerometer.
MrBedfordVan 0:b9164b348919 640 */
MrBedfordVan 0:b9164b348919 641 int MicroBitCompass::readTemperature()
MrBedfordVan 0:b9164b348919 642 {
MrBedfordVan 0:b9164b348919 643 int8_t temperature;
MrBedfordVan 0:b9164b348919 644 int result;
MrBedfordVan 0:b9164b348919 645
MrBedfordVan 0:b9164b348919 646 result = readCommand(MAG_DIE_TEMP, (uint8_t *)&temperature, 1);
MrBedfordVan 0:b9164b348919 647 if (result != MICROBIT_OK)
MrBedfordVan 0:b9164b348919 648 return MICROBIT_I2C_ERROR;
MrBedfordVan 0:b9164b348919 649
MrBedfordVan 0:b9164b348919 650 return temperature;
MrBedfordVan 0:b9164b348919 651 }
MrBedfordVan 0:b9164b348919 652
MrBedfordVan 0:b9164b348919 653 /**
MrBedfordVan 0:b9164b348919 654 * Perform a calibration of the compass.
MrBedfordVan 0:b9164b348919 655 *
MrBedfordVan 0:b9164b348919 656 * This method will be called automatically if a user attempts to read a compass value when
MrBedfordVan 0:b9164b348919 657 * the compass is uncalibrated. It can also be called at any time by the user.
MrBedfordVan 0:b9164b348919 658 *
MrBedfordVan 0:b9164b348919 659 * The method will only return once the compass has been calibrated.
MrBedfordVan 0:b9164b348919 660 *
MrBedfordVan 0:b9164b348919 661 * @return MICROBIT_OK, MICROBIT_I2C_ERROR if the magnetometer could not be accessed,
MrBedfordVan 0:b9164b348919 662 * or MICROBIT_CALIBRATION_REQUIRED if the calibration algorithm failed to complete successfully.
MrBedfordVan 0:b9164b348919 663 *
MrBedfordVan 0:b9164b348919 664 * @note THIS MUST BE CALLED TO GAIN RELIABLE VALUES FROM THE COMPASS
MrBedfordVan 0:b9164b348919 665 */
MrBedfordVan 0:b9164b348919 666 int MicroBitCompass::calibrate()
MrBedfordVan 0:b9164b348919 667 {
MrBedfordVan 0:b9164b348919 668 // Only perform one calibration process at a time.
MrBedfordVan 0:b9164b348919 669 if(isCalibrating())
MrBedfordVan 0:b9164b348919 670 return MICROBIT_CALIBRATION_IN_PROGRESS;
MrBedfordVan 0:b9164b348919 671
MrBedfordVan 0:b9164b348919 672 updateSample();
MrBedfordVan 0:b9164b348919 673
MrBedfordVan 0:b9164b348919 674 // Delete old calibration data
MrBedfordVan 0:b9164b348919 675 clearCalibration();
MrBedfordVan 0:b9164b348919 676
MrBedfordVan 0:b9164b348919 677 // Record that we've started calibrating.
MrBedfordVan 0:b9164b348919 678 status |= MICROBIT_COMPASS_STATUS_CALIBRATING;
MrBedfordVan 0:b9164b348919 679
MrBedfordVan 0:b9164b348919 680 // Launch any registred calibration alogrithm visialisation
MrBedfordVan 0:b9164b348919 681 MicroBitEvent(id, MICROBIT_COMPASS_EVT_CALIBRATE);
MrBedfordVan 0:b9164b348919 682
MrBedfordVan 0:b9164b348919 683 // Record that we've finished calibrating.
MrBedfordVan 0:b9164b348919 684 status &= ~MICROBIT_COMPASS_STATUS_CALIBRATING;
MrBedfordVan 0:b9164b348919 685
MrBedfordVan 0:b9164b348919 686 // If there are no changes to our sample data, we either have no calibration algorithm, or it couldn't complete succesfully.
MrBedfordVan 0:b9164b348919 687 if(!(status & MICROBIT_COMPASS_STATUS_CALIBRATED))
MrBedfordVan 0:b9164b348919 688 return MICROBIT_CALIBRATION_REQUIRED;
MrBedfordVan 0:b9164b348919 689
MrBedfordVan 0:b9164b348919 690 return MICROBIT_OK;
MrBedfordVan 0:b9164b348919 691 }
MrBedfordVan 0:b9164b348919 692
MrBedfordVan 0:b9164b348919 693 /**
MrBedfordVan 0:b9164b348919 694 * Configure the compass to use the calibration data that is supplied to this call.
MrBedfordVan 0:b9164b348919 695 *
MrBedfordVan 0:b9164b348919 696 * Calibration data is comprised of the perceived zero offset of each axis of the compass.
MrBedfordVan 0:b9164b348919 697 *
MrBedfordVan 0:b9164b348919 698 * After calibration this should now take into account trimming errors in the magnetometer,
MrBedfordVan 0:b9164b348919 699 * and any "hard iron" offsets on the device.
MrBedfordVan 0:b9164b348919 700 *
MrBedfordVan 0:b9164b348919 701 * @param calibration A CompassSample containing the offsets for the x, y and z axis.
MrBedfordVan 0:b9164b348919 702 */
MrBedfordVan 0:b9164b348919 703 void MicroBitCompass::setCalibration(CompassSample calibration)
MrBedfordVan 0:b9164b348919 704 {
MrBedfordVan 0:b9164b348919 705 if(this->storage != NULL)
MrBedfordVan 0:b9164b348919 706 this->storage->put(ManagedString("compassCal"), (uint8_t *)&calibration, sizeof(CompassSample));
MrBedfordVan 0:b9164b348919 707
MrBedfordVan 0:b9164b348919 708 average = calibration;
MrBedfordVan 0:b9164b348919 709 status |= MICROBIT_COMPASS_STATUS_CALIBRATED;
MrBedfordVan 0:b9164b348919 710 }
MrBedfordVan 0:b9164b348919 711
MrBedfordVan 0:b9164b348919 712 /**
MrBedfordVan 0:b9164b348919 713 * Provides the calibration data currently in use by the compass.
MrBedfordVan 0:b9164b348919 714 *
MrBedfordVan 0:b9164b348919 715 * More specifically, the x, y and z zero offsets of the compass.
MrBedfordVan 0:b9164b348919 716 *
MrBedfordVan 0:b9164b348919 717 * @return calibration A CompassSample containing the offsets for the x, y and z axis.
MrBedfordVan 0:b9164b348919 718 */
MrBedfordVan 0:b9164b348919 719 CompassSample MicroBitCompass::getCalibration()
MrBedfordVan 0:b9164b348919 720 {
MrBedfordVan 0:b9164b348919 721 return average;
MrBedfordVan 0:b9164b348919 722 }
MrBedfordVan 0:b9164b348919 723
MrBedfordVan 0:b9164b348919 724 /**
MrBedfordVan 0:b9164b348919 725 * Returns 0 or 1. 1 indicates that the compass is calibrated, zero means the compass requires calibration.
MrBedfordVan 0:b9164b348919 726 */
MrBedfordVan 0:b9164b348919 727 int MicroBitCompass::isCalibrated()
MrBedfordVan 0:b9164b348919 728 {
MrBedfordVan 0:b9164b348919 729 return status & MICROBIT_COMPASS_STATUS_CALIBRATED;
MrBedfordVan 0:b9164b348919 730 }
MrBedfordVan 0:b9164b348919 731
MrBedfordVan 0:b9164b348919 732 /**
MrBedfordVan 0:b9164b348919 733 * Returns 0 or 1. 1 indicates that the compass is calibrating, zero means the compass is not currently calibrating.
MrBedfordVan 0:b9164b348919 734 */
MrBedfordVan 0:b9164b348919 735 int MicroBitCompass::isCalibrating()
MrBedfordVan 0:b9164b348919 736 {
MrBedfordVan 0:b9164b348919 737 return status & MICROBIT_COMPASS_STATUS_CALIBRATING;
MrBedfordVan 0:b9164b348919 738 }
MrBedfordVan 0:b9164b348919 739
MrBedfordVan 0:b9164b348919 740 /**
MrBedfordVan 0:b9164b348919 741 * Clears the calibration held in persistent storage, and sets the calibrated flag to zero.
MrBedfordVan 0:b9164b348919 742 */
MrBedfordVan 0:b9164b348919 743 void MicroBitCompass::clearCalibration()
MrBedfordVan 0:b9164b348919 744 {
MrBedfordVan 0:b9164b348919 745 status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED;
MrBedfordVan 0:b9164b348919 746 }
MrBedfordVan 0:b9164b348919 747
MrBedfordVan 0:b9164b348919 748 /**
MrBedfordVan 0:b9164b348919 749 * Destructor for MicroBitCompass, where we deregister this instance from the array of fiber components.
MrBedfordVan 0:b9164b348919 750 */
MrBedfordVan 0:b9164b348919 751 MicroBitCompass::~MicroBitCompass()
MrBedfordVan 0:b9164b348919 752 {
MrBedfordVan 0:b9164b348919 753 fiber_remove_idle_component(this);
MrBedfordVan 0:b9164b348919 754 }
MrBedfordVan 0:b9164b348919 755
MrBedfordVan 0:b9164b348919 756 const MAG3110SampleRateConfig MAG3110SampleRate[MAG3110_SAMPLE_RATES] = {
MrBedfordVan 0:b9164b348919 757 {12500, 0x00}, // 80 Hz
MrBedfordVan 0:b9164b348919 758 {25000, 0x20}, // 40 Hz
MrBedfordVan 0:b9164b348919 759 {50000, 0x40}, // 20 Hz
MrBedfordVan 0:b9164b348919 760 {100000, 0x60}, // 10 hz
MrBedfordVan 0:b9164b348919 761 {200000, 0x80}, // 5 hz
MrBedfordVan 0:b9164b348919 762 {400000, 0x88}, // 2.5 hz
MrBedfordVan 0:b9164b348919 763 {800000, 0x90}, // 1.25 hz
MrBedfordVan 0:b9164b348919 764 {1600000, 0xb0}, // 0.63 hz
MrBedfordVan 0:b9164b348919 765 {3200000, 0xd0}, // 0.31 hz
MrBedfordVan 0:b9164b348919 766 {6400000, 0xf0}, // 0.16 hz
MrBedfordVan 0:b9164b348919 767 {12800000, 0xf8} // 0.08 hz
MrBedfordVan 0:b9164b348919 768 };