fsdfds

Dependencies:   BLE_API mbed-dev-bin nRF51822

Fork of microbit-dal by Lancaster University

Committer:
LancasterUniversity
Date:
Wed Jul 13 12:18:08 2016 +0100
Revision:
30:db87179335d5
Parent:
1:8aa5cdb4ab67
Child:
31:87789e55bac7
Synchronized with git rev 3b435c0d
Author: James Devine
microbit-dal: BUGFIX in MicroBitStorage

There was an off by one error when storing the key of the key value
pair, where the null terminator was dropped. This would mean that if
the returned key of the KeyValuePair were used, it would cause a number
of issues.

Another issue raised was the copying a random 48 bytes from memory
regardless of the position of memory in the stack. If the memory was
smaller than 48 bytes, and existed at the top of the stack, this could
have dire consequences. As a result, MicroBitStorage now accepts a size
parameter which informs the number of bytes to be copied into flash.

#130

Who changed what in which revision?

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