Solution for Bluetooth SIG hands-on training course

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

Dependents:   microbit

Fork of microbit-dal-bluetooth-mdw_starter by Martin Woolley

Committer:
LancasterUniversity
Date:
Wed Jul 13 12:17:54 2016 +0100
Revision:
22:23d7b9a4b082
Parent:
6:2e1c2e0d8c7a
Child:
37:b624ae5e94a5
Synchronized with git rev 7cf98c22
Author: James Devine
microbit-dal: patch for fiber_wake_on_event

fiber_wake_on_event used to crash after forking a FOB fiber.

It would attempt to obtain a new fiber context, and would place it on the wait queue.
Then when that fiber was paged in, the context of that fiber would not have been
initialised, as the function presumed schedule would be called immediately after
fiber initialisation.

This patch catches that edge case.

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 Accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 28 *
Jonathan Austin 1:8aa5cdb4ab67 29 * Represents an implementation of the Freescale MMA8653 3 axis accelerometer
Jonathan Austin 1:8aa5cdb4ab67 30 * Also includes basic data caching and on demand activation.
Jonathan Austin 1:8aa5cdb4ab67 31 */
Jonathan Austin 1:8aa5cdb4ab67 32 #include "MicroBitConfig.h"
Jonathan Austin 1:8aa5cdb4ab67 33 #include "MicroBitAccelerometer.h"
Jonathan Austin 1:8aa5cdb4ab67 34 #include "ErrorNo.h"
Jonathan Austin 1:8aa5cdb4ab67 35 #include "MicroBitConfig.h"
Jonathan Austin 1:8aa5cdb4ab67 36 #include "MicroBitEvent.h"
Jonathan Austin 1:8aa5cdb4ab67 37 #include "MicroBitCompat.h"
Jonathan Austin 1:8aa5cdb4ab67 38 #include "MicroBitFiber.h"
Jonathan Austin 1:8aa5cdb4ab67 39
Jonathan Austin 1:8aa5cdb4ab67 40 /**
Jonathan Austin 1:8aa5cdb4ab67 41 * Configures the accelerometer for G range and sample rate defined
Jonathan Austin 1:8aa5cdb4ab67 42 * in this object. The nearest values are chosen to those defined
Jonathan Austin 1:8aa5cdb4ab67 43 * that are supported by the hardware. The instance variables are then
Jonathan Austin 1:8aa5cdb4ab67 44 * updated to reflect reality.
Jonathan Austin 1:8aa5cdb4ab67 45 *
Jonathan Austin 1:8aa5cdb4ab67 46 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the accelerometer could not be configured.
Jonathan Austin 1:8aa5cdb4ab67 47 */
Jonathan Austin 1:8aa5cdb4ab67 48 int MicroBitAccelerometer::configure()
Jonathan Austin 1:8aa5cdb4ab67 49 {
Jonathan Austin 1:8aa5cdb4ab67 50 const MMA8653SampleRangeConfig *actualSampleRange;
Jonathan Austin 1:8aa5cdb4ab67 51 const MMA8653SampleRateConfig *actualSampleRate;
Jonathan Austin 1:8aa5cdb4ab67 52 int result;
Jonathan Austin 1:8aa5cdb4ab67 53
Jonathan Austin 1:8aa5cdb4ab67 54 // First find the nearest sample rate to that specified.
Jonathan Austin 1:8aa5cdb4ab67 55 actualSampleRate = &MMA8653SampleRate[MMA8653_SAMPLE_RATES-1];
Jonathan Austin 1:8aa5cdb4ab67 56 for (int i=MMA8653_SAMPLE_RATES-1; i>=0; i--)
Jonathan Austin 1:8aa5cdb4ab67 57 {
Jonathan Austin 1:8aa5cdb4ab67 58 if(MMA8653SampleRate[i].sample_period < this->samplePeriod * 1000)
Jonathan Austin 1:8aa5cdb4ab67 59 break;
Jonathan Austin 1:8aa5cdb4ab67 60
Jonathan Austin 1:8aa5cdb4ab67 61 actualSampleRate = &MMA8653SampleRate[i];
Jonathan Austin 1:8aa5cdb4ab67 62 }
Jonathan Austin 1:8aa5cdb4ab67 63
Jonathan Austin 1:8aa5cdb4ab67 64 // Now find the nearest sample range to that specified.
Jonathan Austin 1:8aa5cdb4ab67 65 actualSampleRange = &MMA8653SampleRange[MMA8653_SAMPLE_RANGES-1];
Jonathan Austin 1:8aa5cdb4ab67 66 for (int i=MMA8653_SAMPLE_RANGES-1; i>=0; i--)
Jonathan Austin 1:8aa5cdb4ab67 67 {
Jonathan Austin 1:8aa5cdb4ab67 68 if(MMA8653SampleRange[i].sample_range < this->sampleRange)
Jonathan Austin 1:8aa5cdb4ab67 69 break;
Jonathan Austin 1:8aa5cdb4ab67 70
Jonathan Austin 1:8aa5cdb4ab67 71 actualSampleRange = &MMA8653SampleRange[i];
Jonathan Austin 1:8aa5cdb4ab67 72 }
Jonathan Austin 1:8aa5cdb4ab67 73
Jonathan Austin 1:8aa5cdb4ab67 74 // OK, we have the correct data. Update our local state.
Jonathan Austin 1:8aa5cdb4ab67 75 this->samplePeriod = actualSampleRate->sample_period / 1000;
Jonathan Austin 1:8aa5cdb4ab67 76 this->sampleRange = actualSampleRange->sample_range;
Jonathan Austin 1:8aa5cdb4ab67 77
Jonathan Austin 1:8aa5cdb4ab67 78 // Now configure the accelerometer accordingly.
Jonathan Austin 1:8aa5cdb4ab67 79 // First place the device into standby mode, so it can be configured.
Jonathan Austin 1:8aa5cdb4ab67 80 result = writeCommand(MMA8653_CTRL_REG1, 0x00);
Jonathan Austin 1:8aa5cdb4ab67 81 if (result != 0)
Jonathan Austin 1:8aa5cdb4ab67 82 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 83
Jonathan Austin 1:8aa5cdb4ab67 84 // Enable high precisiosn mode. This consumes a bit more power, but still only 184 uA!
Jonathan Austin 1:8aa5cdb4ab67 85 result = writeCommand(MMA8653_CTRL_REG2, 0x10);
Jonathan Austin 1:8aa5cdb4ab67 86 if (result != 0)
Jonathan Austin 1:8aa5cdb4ab67 87 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 88
Jonathan Austin 1:8aa5cdb4ab67 89 // Enable the INT1 interrupt pin.
Jonathan Austin 1:8aa5cdb4ab67 90 result = writeCommand(MMA8653_CTRL_REG4, 0x01);
Jonathan Austin 1:8aa5cdb4ab67 91 if (result != 0)
Jonathan Austin 1:8aa5cdb4ab67 92 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 93
Jonathan Austin 1:8aa5cdb4ab67 94 // Select the DATA_READY event source to be routed to INT1
Jonathan Austin 1:8aa5cdb4ab67 95 result = writeCommand(MMA8653_CTRL_REG5, 0x01);
Jonathan Austin 1:8aa5cdb4ab67 96 if (result != 0)
Jonathan Austin 1:8aa5cdb4ab67 97 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 98
Jonathan Austin 1:8aa5cdb4ab67 99 // Configure for the selected g range.
Jonathan Austin 1:8aa5cdb4ab67 100 result = writeCommand(MMA8653_XYZ_DATA_CFG, actualSampleRange->xyz_data_cfg);
Jonathan Austin 1:8aa5cdb4ab67 101 if (result != 0)
Jonathan Austin 1:8aa5cdb4ab67 102 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 103
Jonathan Austin 1:8aa5cdb4ab67 104 // Bring the device back online, with 10bit wide samples at the requested frequency.
Jonathan Austin 1:8aa5cdb4ab67 105 result = writeCommand(MMA8653_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01);
Jonathan Austin 1:8aa5cdb4ab67 106 if (result != 0)
Jonathan Austin 1:8aa5cdb4ab67 107 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 108
Jonathan Austin 1:8aa5cdb4ab67 109 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 110 }
Jonathan Austin 1:8aa5cdb4ab67 111
Jonathan Austin 1:8aa5cdb4ab67 112 /**
Jonathan Austin 1:8aa5cdb4ab67 113 * Issues a standard, 2 byte I2C command write to the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 114 *
Jonathan Austin 1:8aa5cdb4ab67 115 * Blocks the calling thread until complete.
Jonathan Austin 1:8aa5cdb4ab67 116 *
Jonathan Austin 1:8aa5cdb4ab67 117 * @param reg The address of the register to write to.
Jonathan Austin 1:8aa5cdb4ab67 118 *
Jonathan Austin 1:8aa5cdb4ab67 119 * @param value The value to write.
Jonathan Austin 1:8aa5cdb4ab67 120 *
Jonathan Austin 1:8aa5cdb4ab67 121 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
Jonathan Austin 1:8aa5cdb4ab67 122 */
Jonathan Austin 1:8aa5cdb4ab67 123 int MicroBitAccelerometer::writeCommand(uint8_t reg, uint8_t value)
Jonathan Austin 1:8aa5cdb4ab67 124 {
Jonathan Austin 1:8aa5cdb4ab67 125 uint8_t command[2];
Jonathan Austin 1:8aa5cdb4ab67 126 command[0] = reg;
Jonathan Austin 1:8aa5cdb4ab67 127 command[1] = value;
Jonathan Austin 1:8aa5cdb4ab67 128
Jonathan Austin 1:8aa5cdb4ab67 129 return i2c.write(address, (const char *)command, 2);
Jonathan Austin 1:8aa5cdb4ab67 130 }
Jonathan Austin 1:8aa5cdb4ab67 131
Jonathan Austin 1:8aa5cdb4ab67 132 /**
Jonathan Austin 1:8aa5cdb4ab67 133 * Issues a read command, copying data into the specified buffer.
Jonathan Austin 1:8aa5cdb4ab67 134 *
Jonathan Austin 1:8aa5cdb4ab67 135 * Blocks the calling thread until complete.
Jonathan Austin 1:8aa5cdb4ab67 136 *
Jonathan Austin 1:8aa5cdb4ab67 137 * @param reg The address of the register to access.
Jonathan Austin 1:8aa5cdb4ab67 138 *
Jonathan Austin 1:8aa5cdb4ab67 139 * @param buffer Memory area to read the data into.
Jonathan Austin 1:8aa5cdb4ab67 140 *
Jonathan Austin 1:8aa5cdb4ab67 141 * @param length The number of bytes to read.
Jonathan Austin 1:8aa5cdb4ab67 142 *
Jonathan Austin 1:8aa5cdb4ab67 143 * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
Jonathan Austin 1:8aa5cdb4ab67 144 */
Jonathan Austin 1:8aa5cdb4ab67 145 int MicroBitAccelerometer::readCommand(uint8_t reg, uint8_t* buffer, int length)
Jonathan Austin 1:8aa5cdb4ab67 146 {
Jonathan Austin 1:8aa5cdb4ab67 147 int result;
Jonathan Austin 1:8aa5cdb4ab67 148
Jonathan Austin 1:8aa5cdb4ab67 149 if (buffer == NULL || length <= 0 )
Jonathan Austin 1:8aa5cdb4ab67 150 return MICROBIT_INVALID_PARAMETER;
Jonathan Austin 1:8aa5cdb4ab67 151
Jonathan Austin 1:8aa5cdb4ab67 152 result = i2c.write(address, (const char *)&reg, 1, true);
Jonathan Austin 1:8aa5cdb4ab67 153 if (result !=0)
Jonathan Austin 1:8aa5cdb4ab67 154 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 155
Jonathan Austin 1:8aa5cdb4ab67 156 result = i2c.read(address, (char *)buffer, length);
Jonathan Austin 1:8aa5cdb4ab67 157 if (result !=0)
Jonathan Austin 1:8aa5cdb4ab67 158 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 159
Jonathan Austin 1:8aa5cdb4ab67 160 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 161 }
Jonathan Austin 1:8aa5cdb4ab67 162
Jonathan Austin 1:8aa5cdb4ab67 163 /**
Jonathan Austin 1:8aa5cdb4ab67 164 * Constructor.
Jonathan Austin 1:8aa5cdb4ab67 165 * Create a software abstraction of an accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 166 *
Jonathan Austin 1:8aa5cdb4ab67 167 * @param _i2c an instance of MicroBitI2C used to communicate with the onboard accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 168 *
Jonathan Austin 1:8aa5cdb4ab67 169 * @param address the default I2C address of the accelerometer. Defaults to: MMA8653_DEFAULT_ADDR.
Jonathan Austin 1:8aa5cdb4ab67 170 *
Jonathan Austin 1:8aa5cdb4ab67 171 * @param id the unique EventModel id of this component. Defaults to: MICROBIT_ID_ACCELEROMETER
Jonathan Austin 1:8aa5cdb4ab67 172 *
Jonathan Austin 1:8aa5cdb4ab67 173 * @code
Jonathan Austin 1:8aa5cdb4ab67 174 * MicroBitI2C i2c = MicroBitI2C(I2C_SDA0, I2C_SCL0);
Jonathan Austin 1:8aa5cdb4ab67 175 *
Jonathan Austin 1:8aa5cdb4ab67 176 * MicroBitAccelerometer accelerometer = MicroBitAccelerometer(i2c);
Jonathan Austin 1:8aa5cdb4ab67 177 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 178 */
Jonathan Austin 1:8aa5cdb4ab67 179 MicroBitAccelerometer::MicroBitAccelerometer(MicroBitI2C& _i2c, uint16_t address, uint16_t id) : sample(), int1(MICROBIT_PIN_ACCEL_DATA_READY), i2c(_i2c)
Jonathan Austin 1:8aa5cdb4ab67 180 {
Jonathan Austin 1:8aa5cdb4ab67 181 // Store our identifiers.
Jonathan Austin 1:8aa5cdb4ab67 182 this->id = id;
Jonathan Austin 1:8aa5cdb4ab67 183 this->status = 0;
Jonathan Austin 1:8aa5cdb4ab67 184 this->address = address;
Jonathan Austin 1:8aa5cdb4ab67 185
Jonathan Austin 1:8aa5cdb4ab67 186 // Update our internal state for 50Hz at +/- 2g (50Hz has a period af 20ms).
Jonathan Austin 1:8aa5cdb4ab67 187 this->samplePeriod = 20;
Jonathan Austin 1:8aa5cdb4ab67 188 this->sampleRange = 2;
Jonathan Austin 1:8aa5cdb4ab67 189
Jonathan Austin 1:8aa5cdb4ab67 190 // Initialise gesture history
Jonathan Austin 1:8aa5cdb4ab67 191 this->sigma = 0;
Jonathan Austin 1:8aa5cdb4ab67 192 this->lastGesture = GESTURE_NONE;
Jonathan Austin 1:8aa5cdb4ab67 193 this->currentGesture = GESTURE_NONE;
Jonathan Austin 1:8aa5cdb4ab67 194 this->shake.x = 0;
Jonathan Austin 1:8aa5cdb4ab67 195 this->shake.y = 0;
Jonathan Austin 1:8aa5cdb4ab67 196 this->shake.z = 0;
Jonathan Austin 1:8aa5cdb4ab67 197 this->shake.count = 0;
Jonathan Austin 1:8aa5cdb4ab67 198 this->shake.timer = 0;
Jonathan Austin 1:8aa5cdb4ab67 199
Jonathan Austin 1:8aa5cdb4ab67 200 // Configure and enable the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 201 if (this->configure() == MICROBIT_OK)
Jonathan Austin 1:8aa5cdb4ab67 202 status |= MICROBIT_COMPONENT_RUNNING;
Jonathan Austin 1:8aa5cdb4ab67 203 }
Jonathan Austin 1:8aa5cdb4ab67 204
Jonathan Austin 1:8aa5cdb4ab67 205 /**
Jonathan Austin 1:8aa5cdb4ab67 206 * Attempts to read the 8 bit ID from the accelerometer, this can be used for
Jonathan Austin 1:8aa5cdb4ab67 207 * validation purposes.
Jonathan Austin 1:8aa5cdb4ab67 208 *
Jonathan Austin 1:8aa5cdb4ab67 209 * @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
Jonathan Austin 1:8aa5cdb4ab67 210 *
Jonathan Austin 1:8aa5cdb4ab67 211 * @code
Jonathan Austin 1:8aa5cdb4ab67 212 * accelerometer.whoAmI();
Jonathan Austin 1:8aa5cdb4ab67 213 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 214 */
Jonathan Austin 1:8aa5cdb4ab67 215 int MicroBitAccelerometer::whoAmI()
Jonathan Austin 1:8aa5cdb4ab67 216 {
Jonathan Austin 1:8aa5cdb4ab67 217 uint8_t data;
Jonathan Austin 1:8aa5cdb4ab67 218 int result;
Jonathan Austin 1:8aa5cdb4ab67 219
Jonathan Austin 1:8aa5cdb4ab67 220 result = readCommand(MMA8653_WHOAMI, &data, 1);
Jonathan Austin 1:8aa5cdb4ab67 221 if (result !=0)
Jonathan Austin 1:8aa5cdb4ab67 222 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 223
Jonathan Austin 1:8aa5cdb4ab67 224 return (int)data;
Jonathan Austin 1:8aa5cdb4ab67 225 }
Jonathan Austin 1:8aa5cdb4ab67 226
Jonathan Austin 1:8aa5cdb4ab67 227 /**
Jonathan Austin 1:8aa5cdb4ab67 228 * Reads the acceleration data from the accelerometer, and stores it in our buffer.
Jonathan Austin 1:8aa5cdb4ab67 229 * This only happens if the accelerometer indicates that it has new data via int1.
Jonathan Austin 1:8aa5cdb4ab67 230 *
Jonathan Austin 1:8aa5cdb4ab67 231 * On first use, this member function will attempt to add this component to the
Jonathan Austin 1:8aa5cdb4ab67 232 * list of fiber components in order to constantly update the values stored
Jonathan Austin 1:8aa5cdb4ab67 233 * by this object.
Jonathan Austin 1:8aa5cdb4ab67 234 *
Jonathan Austin 1:8aa5cdb4ab67 235 * This technique is called lazy instantiation, and it means that we do not
Jonathan Austin 1:8aa5cdb4ab67 236 * obtain the overhead from non-chalantly adding this component to fiber components.
Jonathan Austin 1:8aa5cdb4ab67 237 *
Jonathan Austin 1:8aa5cdb4ab67 238 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the read request fails.
Jonathan Austin 1:8aa5cdb4ab67 239 */
Jonathan Austin 1:8aa5cdb4ab67 240 int MicroBitAccelerometer::updateSample()
Jonathan Austin 1:8aa5cdb4ab67 241 {
Jonathan Austin 1:8aa5cdb4ab67 242 if(!(status & MICROBIT_ACCEL_ADDED_TO_IDLE))
Jonathan Austin 1:8aa5cdb4ab67 243 {
Jonathan Austin 1:8aa5cdb4ab67 244 fiber_add_idle_component(this);
Jonathan Austin 1:8aa5cdb4ab67 245 status |= MICROBIT_ACCEL_ADDED_TO_IDLE;
Jonathan Austin 1:8aa5cdb4ab67 246 }
Jonathan Austin 1:8aa5cdb4ab67 247
Jonathan Austin 1:8aa5cdb4ab67 248 // Poll interrupt line from accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 249 // n.b. Default is Active LO. Interrupt is cleared in data read.
Jonathan Austin 1:8aa5cdb4ab67 250 if(!int1)
Jonathan Austin 1:8aa5cdb4ab67 251 {
Jonathan Austin 1:8aa5cdb4ab67 252 int8_t data[6];
Jonathan Austin 1:8aa5cdb4ab67 253 int result;
Jonathan Austin 1:8aa5cdb4ab67 254
Jonathan Austin 1:8aa5cdb4ab67 255 result = readCommand(MMA8653_OUT_X_MSB, (uint8_t *)data, 6);
Jonathan Austin 1:8aa5cdb4ab67 256 if (result !=0)
Jonathan Austin 1:8aa5cdb4ab67 257 return MICROBIT_I2C_ERROR;
Jonathan Austin 1:8aa5cdb4ab67 258
Jonathan Austin 1:8aa5cdb4ab67 259 // read MSB values...
Jonathan Austin 1:8aa5cdb4ab67 260 sample.x = data[0];
Jonathan Austin 1:8aa5cdb4ab67 261 sample.y = data[2];
Jonathan Austin 1:8aa5cdb4ab67 262 sample.z = data[4];
Jonathan Austin 1:8aa5cdb4ab67 263
Jonathan Austin 1:8aa5cdb4ab67 264 // Normalize the data in the 0..1024 range.
Jonathan Austin 1:8aa5cdb4ab67 265 sample.x *= 8;
Jonathan Austin 1:8aa5cdb4ab67 266 sample.y *= 8;
Jonathan Austin 1:8aa5cdb4ab67 267 sample.z *= 8;
Jonathan Austin 1:8aa5cdb4ab67 268
Jonathan Austin 1:8aa5cdb4ab67 269 #if CONFIG_ENABLED(USE_ACCEL_LSB)
Jonathan Austin 1:8aa5cdb4ab67 270 // Add in LSB values.
Jonathan Austin 1:8aa5cdb4ab67 271 sample.x += (data[1] / 64);
Jonathan Austin 1:8aa5cdb4ab67 272 sample.y += (data[3] / 64);
Jonathan Austin 1:8aa5cdb4ab67 273 sample.z += (data[5] / 64);
Jonathan Austin 1:8aa5cdb4ab67 274 #endif
Jonathan Austin 1:8aa5cdb4ab67 275
Jonathan Austin 1:8aa5cdb4ab67 276 // Scale into millig (approx!)
Jonathan Austin 1:8aa5cdb4ab67 277 sample.x *= this->sampleRange;
Jonathan Austin 1:8aa5cdb4ab67 278 sample.y *= this->sampleRange;
Jonathan Austin 1:8aa5cdb4ab67 279 sample.z *= this->sampleRange;
Jonathan Austin 1:8aa5cdb4ab67 280
Jonathan Austin 1:8aa5cdb4ab67 281 // Indicate that pitch and roll data is now stale, and needs to be recalculated if needed.
Jonathan Austin 1:8aa5cdb4ab67 282 status &= ~MICROBIT_ACCEL_PITCH_ROLL_VALID;
Jonathan Austin 1:8aa5cdb4ab67 283
Jonathan Austin 1:8aa5cdb4ab67 284 // Update gesture tracking
Jonathan Austin 1:8aa5cdb4ab67 285 updateGesture();
Jonathan Austin 1:8aa5cdb4ab67 286
Jonathan Austin 1:8aa5cdb4ab67 287 // Indicate that a new sample is available
Jonathan Austin 1:8aa5cdb4ab67 288 MicroBitEvent e(id, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE);
Jonathan Austin 1:8aa5cdb4ab67 289 }
Jonathan Austin 1:8aa5cdb4ab67 290
Jonathan Austin 1:8aa5cdb4ab67 291 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 292 };
Jonathan Austin 1:8aa5cdb4ab67 293
Jonathan Austin 1:8aa5cdb4ab67 294 /**
Jonathan Austin 1:8aa5cdb4ab67 295 * A service function.
Jonathan Austin 1:8aa5cdb4ab67 296 * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2).
Jonathan Austin 1:8aa5cdb4ab67 297 * It does not, however, square root the result, as this is a relatively high cost operation.
Jonathan Austin 1:8aa5cdb4ab67 298 *
Jonathan Austin 1:8aa5cdb4ab67 299 * This is left to application code should it be needed.
Jonathan Austin 1:8aa5cdb4ab67 300 *
Jonathan Austin 1:8aa5cdb4ab67 301 * @return the sum of the square of the acceleration of the device across all axes.
Jonathan Austin 1:8aa5cdb4ab67 302 */
Jonathan Austin 1:8aa5cdb4ab67 303 int MicroBitAccelerometer::instantaneousAccelerationSquared()
Jonathan Austin 1:8aa5cdb4ab67 304 {
Jonathan Austin 1:8aa5cdb4ab67 305 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 306
Jonathan Austin 1:8aa5cdb4ab67 307 // Use pythagoras theorem to determine the combined force acting on the device.
Jonathan Austin 1:8aa5cdb4ab67 308 return (int)sample.x*(int)sample.x + (int)sample.y*(int)sample.y + (int)sample.z*(int)sample.z;
Jonathan Austin 1:8aa5cdb4ab67 309 }
Jonathan Austin 1:8aa5cdb4ab67 310
Jonathan Austin 1:8aa5cdb4ab67 311 /**
Jonathan Austin 1:8aa5cdb4ab67 312 * Service function.
Jonathan Austin 1:8aa5cdb4ab67 313 * Determines a 'best guess' posture of the device based on instantaneous data.
Jonathan Austin 1:8aa5cdb4ab67 314 *
Jonathan Austin 1:8aa5cdb4ab67 315 * This makes no use of historic data, and forms this input to the filter implemented in updateGesture().
Jonathan Austin 1:8aa5cdb4ab67 316 *
Jonathan Austin 1:8aa5cdb4ab67 317 * @return A 'best guess' of the current posture of the device, based on instanataneous data.
Jonathan Austin 1:8aa5cdb4ab67 318 */
Jonathan Austin 1:8aa5cdb4ab67 319 BasicGesture MicroBitAccelerometer::instantaneousPosture()
Jonathan Austin 1:8aa5cdb4ab67 320 {
Jonathan Austin 1:8aa5cdb4ab67 321 int force = instantaneousAccelerationSquared();
Jonathan Austin 1:8aa5cdb4ab67 322 bool shakeDetected = false;
Jonathan Austin 1:8aa5cdb4ab67 323
Jonathan Austin 1:8aa5cdb4ab67 324 // Test for shake events.
Jonathan Austin 1:8aa5cdb4ab67 325 // We detect a shake by measuring zero crossings in each axis. In other words, if we see a strong acceleration to the left followed by
Jonathan Austin 1:8aa5cdb4ab67 326 // a string acceleration to the right, then we can infer a shake. Similarly, we can do this for each acxis (left/right, up/down, in/out).
Jonathan Austin 1:8aa5cdb4ab67 327 //
Jonathan Austin 1:8aa5cdb4ab67 328 // If we see enough zero crossings in succession (MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD), then we decide that the device
Jonathan Austin 1:8aa5cdb4ab67 329 // has been shaken.
Jonathan Austin 1:8aa5cdb4ab67 330 if ((getX() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.x) || (getX() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.x))
Jonathan Austin 1:8aa5cdb4ab67 331 {
Jonathan Austin 1:8aa5cdb4ab67 332 shakeDetected = true;
Jonathan Austin 1:8aa5cdb4ab67 333 shake.x = !shake.x;
Jonathan Austin 1:8aa5cdb4ab67 334 }
Jonathan Austin 1:8aa5cdb4ab67 335
Jonathan Austin 1:8aa5cdb4ab67 336 if ((getY() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.y) || (getY() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.y))
Jonathan Austin 1:8aa5cdb4ab67 337 {
Jonathan Austin 1:8aa5cdb4ab67 338 shakeDetected = true;
Jonathan Austin 1:8aa5cdb4ab67 339 shake.y = !shake.y;
Jonathan Austin 1:8aa5cdb4ab67 340 }
Jonathan Austin 1:8aa5cdb4ab67 341
Jonathan Austin 1:8aa5cdb4ab67 342 if ((getZ() < -MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && shake.z) || (getZ() > MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE && !shake.z))
Jonathan Austin 1:8aa5cdb4ab67 343 {
Jonathan Austin 1:8aa5cdb4ab67 344 shakeDetected = true;
Jonathan Austin 1:8aa5cdb4ab67 345 shake.z = !shake.z;
Jonathan Austin 1:8aa5cdb4ab67 346 }
Jonathan Austin 1:8aa5cdb4ab67 347
Jonathan Austin 1:8aa5cdb4ab67 348 if (shakeDetected && shake.count < MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD && ++shake.count == MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD)
Jonathan Austin 1:8aa5cdb4ab67 349 shake.shaken = 1;
Jonathan Austin 1:8aa5cdb4ab67 350
Jonathan Austin 1:8aa5cdb4ab67 351 if (++shake.timer >= MICROBIT_ACCELEROMETER_SHAKE_DAMPING)
Jonathan Austin 1:8aa5cdb4ab67 352 {
Jonathan Austin 1:8aa5cdb4ab67 353 shake.timer = 0;
Jonathan Austin 1:8aa5cdb4ab67 354 if (shake.count > 0)
Jonathan Austin 1:8aa5cdb4ab67 355 {
Jonathan Austin 1:8aa5cdb4ab67 356 if(--shake.count == 0)
Jonathan Austin 1:8aa5cdb4ab67 357 shake.shaken = 0;
Jonathan Austin 1:8aa5cdb4ab67 358 }
Jonathan Austin 1:8aa5cdb4ab67 359 }
Jonathan Austin 1:8aa5cdb4ab67 360
Jonathan Austin 1:8aa5cdb4ab67 361 if (shake.shaken)
Jonathan Austin 1:8aa5cdb4ab67 362 return GESTURE_SHAKE;
Jonathan Austin 1:8aa5cdb4ab67 363
Jonathan Austin 1:8aa5cdb4ab67 364 if (force < MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD)
Jonathan Austin 1:8aa5cdb4ab67 365 return GESTURE_FREEFALL;
Jonathan Austin 1:8aa5cdb4ab67 366
Jonathan Austin 1:8aa5cdb4ab67 367 if (force > MICROBIT_ACCELEROMETER_3G_THRESHOLD)
Jonathan Austin 1:8aa5cdb4ab67 368 return GESTURE_3G;
Jonathan Austin 1:8aa5cdb4ab67 369
Jonathan Austin 1:8aa5cdb4ab67 370 if (force > MICROBIT_ACCELEROMETER_6G_THRESHOLD)
Jonathan Austin 1:8aa5cdb4ab67 371 return GESTURE_6G;
Jonathan Austin 1:8aa5cdb4ab67 372
Jonathan Austin 1:8aa5cdb4ab67 373 if (force > MICROBIT_ACCELEROMETER_8G_THRESHOLD)
Jonathan Austin 1:8aa5cdb4ab67 374 return GESTURE_8G;
Jonathan Austin 1:8aa5cdb4ab67 375
Jonathan Austin 1:8aa5cdb4ab67 376 // Determine our posture.
Jonathan Austin 1:8aa5cdb4ab67 377 if (getX() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
Jonathan Austin 1:8aa5cdb4ab67 378 return GESTURE_LEFT;
Jonathan Austin 1:8aa5cdb4ab67 379
Jonathan Austin 1:8aa5cdb4ab67 380 if (getX() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
Jonathan Austin 1:8aa5cdb4ab67 381 return GESTURE_RIGHT;
Jonathan Austin 1:8aa5cdb4ab67 382
Jonathan Austin 1:8aa5cdb4ab67 383 if (getY() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
Jonathan Austin 1:8aa5cdb4ab67 384 return GESTURE_DOWN;
Jonathan Austin 1:8aa5cdb4ab67 385
Jonathan Austin 1:8aa5cdb4ab67 386 if (getY() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
Jonathan Austin 1:8aa5cdb4ab67 387 return GESTURE_UP;
Jonathan Austin 1:8aa5cdb4ab67 388
Jonathan Austin 1:8aa5cdb4ab67 389 if (getZ() < (-1000 + MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
Jonathan Austin 1:8aa5cdb4ab67 390 return GESTURE_FACE_UP;
Jonathan Austin 1:8aa5cdb4ab67 391
Jonathan Austin 1:8aa5cdb4ab67 392 if (getZ() > (1000 - MICROBIT_ACCELEROMETER_TILT_TOLERANCE))
Jonathan Austin 1:8aa5cdb4ab67 393 return GESTURE_FACE_DOWN;
Jonathan Austin 1:8aa5cdb4ab67 394
Jonathan Austin 1:8aa5cdb4ab67 395 return GESTURE_NONE;
Jonathan Austin 1:8aa5cdb4ab67 396 }
Jonathan Austin 1:8aa5cdb4ab67 397
Jonathan Austin 1:8aa5cdb4ab67 398 /**
Jonathan Austin 1:8aa5cdb4ab67 399 * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote
Jonathan Austin 1:8aa5cdb4ab67 400 * stability.
Jonathan Austin 1:8aa5cdb4ab67 401 */
Jonathan Austin 1:8aa5cdb4ab67 402 void MicroBitAccelerometer::updateGesture()
Jonathan Austin 1:8aa5cdb4ab67 403 {
Jonathan Austin 1:8aa5cdb4ab67 404 // Determine what it looks like we're doing based on the latest sample...
Jonathan Austin 1:8aa5cdb4ab67 405 BasicGesture g = instantaneousPosture();
Jonathan Austin 1:8aa5cdb4ab67 406
Jonathan Austin 1:8aa5cdb4ab67 407 // Perform some low pass filtering to reduce jitter from any detected effects
Jonathan Austin 1:8aa5cdb4ab67 408 if (g == currentGesture)
Jonathan Austin 1:8aa5cdb4ab67 409 {
Jonathan Austin 1:8aa5cdb4ab67 410 if (sigma < MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
Jonathan Austin 1:8aa5cdb4ab67 411 sigma++;
Jonathan Austin 1:8aa5cdb4ab67 412 }
Jonathan Austin 1:8aa5cdb4ab67 413 else
Jonathan Austin 1:8aa5cdb4ab67 414 {
Jonathan Austin 1:8aa5cdb4ab67 415 currentGesture = g;
Jonathan Austin 1:8aa5cdb4ab67 416 sigma = 0;
Jonathan Austin 1:8aa5cdb4ab67 417 }
Jonathan Austin 1:8aa5cdb4ab67 418
Jonathan Austin 1:8aa5cdb4ab67 419 // If we've reached threshold, update our record and raise the relevant event...
Jonathan Austin 1:8aa5cdb4ab67 420 if (currentGesture != lastGesture && sigma >= MICROBIT_ACCELEROMETER_GESTURE_DAMPING)
Jonathan Austin 1:8aa5cdb4ab67 421 {
Jonathan Austin 1:8aa5cdb4ab67 422 lastGesture = currentGesture;
Jonathan Austin 1:8aa5cdb4ab67 423 MicroBitEvent e(MICROBIT_ID_GESTURE, lastGesture);
Jonathan Austin 1:8aa5cdb4ab67 424 }
Jonathan Austin 1:8aa5cdb4ab67 425 }
Jonathan Austin 1:8aa5cdb4ab67 426
Jonathan Austin 1:8aa5cdb4ab67 427 /**
Jonathan Austin 1:8aa5cdb4ab67 428 * Attempts to set the sample rate of the accelerometer to the specified value (in ms).
Jonathan Austin 1:8aa5cdb4ab67 429 *
Jonathan Austin 1:8aa5cdb4ab67 430 * @param period the requested time between samples, in milliseconds.
Jonathan Austin 1:8aa5cdb4ab67 431 *
Jonathan Austin 1:8aa5cdb4ab67 432 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
Jonathan Austin 1:8aa5cdb4ab67 433 *
Jonathan Austin 1:8aa5cdb4ab67 434 * @code
Jonathan Austin 1:8aa5cdb4ab67 435 * // sample rate is now 20 ms.
Jonathan Austin 1:8aa5cdb4ab67 436 * accelerometer.setPeriod(20);
Jonathan Austin 1:8aa5cdb4ab67 437 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 438 *
Jonathan Austin 1:8aa5cdb4ab67 439 * @note The requested rate may not be possible on the hardware. In this case, the
Jonathan Austin 1:8aa5cdb4ab67 440 * nearest lower rate is chosen.
Jonathan Austin 1:8aa5cdb4ab67 441 */
Jonathan Austin 1:8aa5cdb4ab67 442 int MicroBitAccelerometer::setPeriod(int period)
Jonathan Austin 1:8aa5cdb4ab67 443 {
Jonathan Austin 1:8aa5cdb4ab67 444 this->samplePeriod = period;
Jonathan Austin 1:8aa5cdb4ab67 445 return this->configure();
Jonathan Austin 1:8aa5cdb4ab67 446 }
Jonathan Austin 1:8aa5cdb4ab67 447
Jonathan Austin 1:8aa5cdb4ab67 448 /**
Jonathan Austin 1:8aa5cdb4ab67 449 * Reads the currently configured sample rate of the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 450 *
Jonathan Austin 1:8aa5cdb4ab67 451 * @return The time between samples, in milliseconds.
Jonathan Austin 1:8aa5cdb4ab67 452 */
Jonathan Austin 1:8aa5cdb4ab67 453 int MicroBitAccelerometer::getPeriod()
Jonathan Austin 1:8aa5cdb4ab67 454 {
Jonathan Austin 1:8aa5cdb4ab67 455 return (int)samplePeriod;
Jonathan Austin 1:8aa5cdb4ab67 456 }
Jonathan Austin 1:8aa5cdb4ab67 457
Jonathan Austin 1:8aa5cdb4ab67 458 /**
Jonathan Austin 1:8aa5cdb4ab67 459 * Attempts to set the sample range of the accelerometer to the specified value (in g).
Jonathan Austin 1:8aa5cdb4ab67 460 *
Jonathan Austin 1:8aa5cdb4ab67 461 * @param range The requested sample range of samples, in g.
Jonathan Austin 1:8aa5cdb4ab67 462 *
Jonathan Austin 1:8aa5cdb4ab67 463 * @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
Jonathan Austin 1:8aa5cdb4ab67 464 *
Jonathan Austin 1:8aa5cdb4ab67 465 * @code
Jonathan Austin 1:8aa5cdb4ab67 466 * // the sample range of the accelerometer is now 8G.
Jonathan Austin 1:8aa5cdb4ab67 467 * accelerometer.setRange(8);
Jonathan Austin 1:8aa5cdb4ab67 468 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 469 *
Jonathan Austin 1:8aa5cdb4ab67 470 * @note The requested range may not be possible on the hardware. In this case, the
Jonathan Austin 1:8aa5cdb4ab67 471 * nearest lower range is chosen.
Jonathan Austin 1:8aa5cdb4ab67 472 */
Jonathan Austin 1:8aa5cdb4ab67 473 int MicroBitAccelerometer::setRange(int range)
Jonathan Austin 1:8aa5cdb4ab67 474 {
Jonathan Austin 1:8aa5cdb4ab67 475 this->sampleRange = range;
Jonathan Austin 1:8aa5cdb4ab67 476 return this->configure();
Jonathan Austin 1:8aa5cdb4ab67 477 }
Jonathan Austin 1:8aa5cdb4ab67 478
Jonathan Austin 1:8aa5cdb4ab67 479 /**
Jonathan Austin 1:8aa5cdb4ab67 480 * Reads the currently configured sample range of the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 481 *
Jonathan Austin 1:8aa5cdb4ab67 482 * @return The sample range, in g.
Jonathan Austin 1:8aa5cdb4ab67 483 */
Jonathan Austin 1:8aa5cdb4ab67 484 int MicroBitAccelerometer::getRange()
Jonathan Austin 1:8aa5cdb4ab67 485 {
Jonathan Austin 1:8aa5cdb4ab67 486 return (int)sampleRange;
Jonathan Austin 1:8aa5cdb4ab67 487 }
Jonathan Austin 1:8aa5cdb4ab67 488
Jonathan Austin 1:8aa5cdb4ab67 489 /**
Jonathan Austin 1:8aa5cdb4ab67 490 * Reads the value of the X axis from the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 491 *
Jonathan Austin 1:8aa5cdb4ab67 492 * @param system The coordinate system to use. By default, a simple cartesian system is provided.
Jonathan Austin 1:8aa5cdb4ab67 493 *
Jonathan Austin 1:8aa5cdb4ab67 494 * @return The force measured in the X axis, in milli-g.
Jonathan Austin 1:8aa5cdb4ab67 495 *
Jonathan Austin 1:8aa5cdb4ab67 496 * @code
Jonathan Austin 1:8aa5cdb4ab67 497 * accelerometer.getX();
Jonathan Austin 1:8aa5cdb4ab67 498 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 499 */
Jonathan Austin 1:8aa5cdb4ab67 500 int MicroBitAccelerometer::getX(MicroBitCoordinateSystem system)
Jonathan Austin 1:8aa5cdb4ab67 501 {
Jonathan Austin 1:8aa5cdb4ab67 502 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 503
Jonathan Austin 1:8aa5cdb4ab67 504 switch (system)
Jonathan Austin 1:8aa5cdb4ab67 505 {
Jonathan Austin 1:8aa5cdb4ab67 506 case SIMPLE_CARTESIAN:
Jonathan Austin 1:8aa5cdb4ab67 507 return -sample.x;
Jonathan Austin 1:8aa5cdb4ab67 508
Jonathan Austin 1:8aa5cdb4ab67 509 case NORTH_EAST_DOWN:
Jonathan Austin 1:8aa5cdb4ab67 510 return sample.y;
Jonathan Austin 1:8aa5cdb4ab67 511
Jonathan Austin 1:8aa5cdb4ab67 512 case RAW:
Jonathan Austin 1:8aa5cdb4ab67 513 default:
Jonathan Austin 1:8aa5cdb4ab67 514 return sample.x;
Jonathan Austin 1:8aa5cdb4ab67 515 }
Jonathan Austin 1:8aa5cdb4ab67 516 }
Jonathan Austin 1:8aa5cdb4ab67 517
Jonathan Austin 1:8aa5cdb4ab67 518 /**
Jonathan Austin 1:8aa5cdb4ab67 519 * Reads the value of the Y axis from the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 520 *
Jonathan Austin 1:8aa5cdb4ab67 521 * @return The force measured in the Y axis, in milli-g.
Jonathan Austin 1:8aa5cdb4ab67 522 *
Jonathan Austin 1:8aa5cdb4ab67 523 * @code
Jonathan Austin 1:8aa5cdb4ab67 524 * accelerometer.getY();
Jonathan Austin 1:8aa5cdb4ab67 525 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 526 */
Jonathan Austin 1:8aa5cdb4ab67 527 int MicroBitAccelerometer::getY(MicroBitCoordinateSystem system)
Jonathan Austin 1:8aa5cdb4ab67 528 {
Jonathan Austin 1:8aa5cdb4ab67 529 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 530
Jonathan Austin 1:8aa5cdb4ab67 531 switch (system)
Jonathan Austin 1:8aa5cdb4ab67 532 {
Jonathan Austin 1:8aa5cdb4ab67 533 case SIMPLE_CARTESIAN:
Jonathan Austin 1:8aa5cdb4ab67 534 return -sample.y;
Jonathan Austin 1:8aa5cdb4ab67 535
Jonathan Austin 1:8aa5cdb4ab67 536 case NORTH_EAST_DOWN:
Jonathan Austin 1:8aa5cdb4ab67 537 return -sample.x;
Jonathan Austin 1:8aa5cdb4ab67 538
Jonathan Austin 1:8aa5cdb4ab67 539 case RAW:
Jonathan Austin 1:8aa5cdb4ab67 540 default:
Jonathan Austin 1:8aa5cdb4ab67 541 return sample.y;
Jonathan Austin 1:8aa5cdb4ab67 542 }
Jonathan Austin 1:8aa5cdb4ab67 543 }
Jonathan Austin 1:8aa5cdb4ab67 544
Jonathan Austin 1:8aa5cdb4ab67 545 /**
Jonathan Austin 1:8aa5cdb4ab67 546 * Reads the value of the Z axis from the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 547 *
Jonathan Austin 1:8aa5cdb4ab67 548 * @return The force measured in the Z axis, in milli-g.
Jonathan Austin 1:8aa5cdb4ab67 549 *
Jonathan Austin 1:8aa5cdb4ab67 550 * @code
Jonathan Austin 1:8aa5cdb4ab67 551 * accelerometer.getZ();
Jonathan Austin 1:8aa5cdb4ab67 552 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 553 */
Jonathan Austin 1:8aa5cdb4ab67 554 int MicroBitAccelerometer::getZ(MicroBitCoordinateSystem system)
Jonathan Austin 1:8aa5cdb4ab67 555 {
Jonathan Austin 1:8aa5cdb4ab67 556 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 557
Jonathan Austin 1:8aa5cdb4ab67 558 switch (system)
Jonathan Austin 1:8aa5cdb4ab67 559 {
Jonathan Austin 1:8aa5cdb4ab67 560 case NORTH_EAST_DOWN:
Jonathan Austin 1:8aa5cdb4ab67 561 return -sample.z;
Jonathan Austin 1:8aa5cdb4ab67 562
Jonathan Austin 1:8aa5cdb4ab67 563 case SIMPLE_CARTESIAN:
Jonathan Austin 1:8aa5cdb4ab67 564 case RAW:
Jonathan Austin 1:8aa5cdb4ab67 565 default:
Jonathan Austin 1:8aa5cdb4ab67 566 return sample.z;
Jonathan Austin 1:8aa5cdb4ab67 567 }
Jonathan Austin 1:8aa5cdb4ab67 568 }
Jonathan Austin 1:8aa5cdb4ab67 569
Jonathan Austin 1:8aa5cdb4ab67 570 /**
Jonathan Austin 1:8aa5cdb4ab67 571 * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 572 *
Jonathan Austin 1:8aa5cdb4ab67 573 * @return The pitch of the device, in degrees.
Jonathan Austin 1:8aa5cdb4ab67 574 *
Jonathan Austin 1:8aa5cdb4ab67 575 * @code
Jonathan Austin 1:8aa5cdb4ab67 576 * accelerometer.getPitch();
Jonathan Austin 1:8aa5cdb4ab67 577 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 578 */
Jonathan Austin 1:8aa5cdb4ab67 579 int MicroBitAccelerometer::getPitch()
Jonathan Austin 1:8aa5cdb4ab67 580 {
Jonathan Austin 1:8aa5cdb4ab67 581 return (int) ((360*getPitchRadians()) / (2*PI));
Jonathan Austin 1:8aa5cdb4ab67 582 }
Jonathan Austin 1:8aa5cdb4ab67 583
Jonathan Austin 1:8aa5cdb4ab67 584 /**
Jonathan Austin 1:8aa5cdb4ab67 585 * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 586 *
Jonathan Austin 1:8aa5cdb4ab67 587 * @return The pitch of the device, in radians.
Jonathan Austin 1:8aa5cdb4ab67 588 *
Jonathan Austin 1:8aa5cdb4ab67 589 * @code
Jonathan Austin 1:8aa5cdb4ab67 590 * accelerometer.getPitchRadians();
Jonathan Austin 1:8aa5cdb4ab67 591 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 592 */
Jonathan Austin 1:8aa5cdb4ab67 593 float MicroBitAccelerometer::getPitchRadians()
Jonathan Austin 1:8aa5cdb4ab67 594 {
Jonathan Austin 1:8aa5cdb4ab67 595 if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID))
Jonathan Austin 1:8aa5cdb4ab67 596 recalculatePitchRoll();
Jonathan Austin 1:8aa5cdb4ab67 597
Jonathan Austin 1:8aa5cdb4ab67 598 return pitch;
Jonathan Austin 1:8aa5cdb4ab67 599 }
Jonathan Austin 1:8aa5cdb4ab67 600
Jonathan Austin 1:8aa5cdb4ab67 601 /**
Jonathan Austin 1:8aa5cdb4ab67 602 * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 603 *
Jonathan Austin 1:8aa5cdb4ab67 604 * @return The roll of the device, in degrees.
Jonathan Austin 1:8aa5cdb4ab67 605 *
Jonathan Austin 1:8aa5cdb4ab67 606 * @code
Jonathan Austin 1:8aa5cdb4ab67 607 * accelerometer.getRoll();
Jonathan Austin 1:8aa5cdb4ab67 608 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 609 */
Jonathan Austin 1:8aa5cdb4ab67 610 int MicroBitAccelerometer::getRoll()
Jonathan Austin 1:8aa5cdb4ab67 611 {
Jonathan Austin 1:8aa5cdb4ab67 612 return (int) ((360*getRollRadians()) / (2*PI));
Jonathan Austin 1:8aa5cdb4ab67 613 }
Jonathan Austin 1:8aa5cdb4ab67 614
Jonathan Austin 1:8aa5cdb4ab67 615 /**
Jonathan Austin 1:8aa5cdb4ab67 616 * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 617 *
Jonathan Austin 1:8aa5cdb4ab67 618 * @return The roll of the device, in radians.
Jonathan Austin 1:8aa5cdb4ab67 619 *
Jonathan Austin 1:8aa5cdb4ab67 620 * @code
Jonathan Austin 1:8aa5cdb4ab67 621 * accelerometer.getRollRadians();
Jonathan Austin 1:8aa5cdb4ab67 622 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 623 */
Jonathan Austin 1:8aa5cdb4ab67 624 float MicroBitAccelerometer::getRollRadians()
Jonathan Austin 1:8aa5cdb4ab67 625 {
Jonathan Austin 1:8aa5cdb4ab67 626 if (!(status & MICROBIT_ACCEL_PITCH_ROLL_VALID))
Jonathan Austin 1:8aa5cdb4ab67 627 recalculatePitchRoll();
Jonathan Austin 1:8aa5cdb4ab67 628
Jonathan Austin 1:8aa5cdb4ab67 629 return roll;
Jonathan Austin 1:8aa5cdb4ab67 630 }
Jonathan Austin 1:8aa5cdb4ab67 631
Jonathan Austin 1:8aa5cdb4ab67 632 /**
Jonathan Austin 1:8aa5cdb4ab67 633 * Recalculate roll and pitch values for the current sample.
Jonathan Austin 1:8aa5cdb4ab67 634 *
Jonathan Austin 1:8aa5cdb4ab67 635 * @note We only do this at most once per sample, as the necessary trigonemteric functions are rather
Jonathan Austin 1:8aa5cdb4ab67 636 * heavyweight for a CPU without a floating point unit.
Jonathan Austin 1:8aa5cdb4ab67 637 */
Jonathan Austin 1:8aa5cdb4ab67 638 void MicroBitAccelerometer::recalculatePitchRoll()
Jonathan Austin 1:8aa5cdb4ab67 639 {
Jonathan Austin 1:8aa5cdb4ab67 640 float x = (float) getX(NORTH_EAST_DOWN);
Jonathan Austin 1:8aa5cdb4ab67 641 float y = (float) getY(NORTH_EAST_DOWN);
Jonathan Austin 1:8aa5cdb4ab67 642 float z = (float) getZ(NORTH_EAST_DOWN);
Jonathan Austin 1:8aa5cdb4ab67 643
LancasterUniversity 6:2e1c2e0d8c7a 644 roll = atan2((double)getY(NORTH_EAST_DOWN), (double)getZ(NORTH_EAST_DOWN));
LancasterUniversity 6:2e1c2e0d8c7a 645
Jonathan Austin 1:8aa5cdb4ab67 646 pitch = atan(-x / (y*sin(roll) + z*cos(roll)));
Jonathan Austin 1:8aa5cdb4ab67 647 status |= MICROBIT_ACCEL_PITCH_ROLL_VALID;
Jonathan Austin 1:8aa5cdb4ab67 648 }
Jonathan Austin 1:8aa5cdb4ab67 649
Jonathan Austin 1:8aa5cdb4ab67 650 /**
Jonathan Austin 1:8aa5cdb4ab67 651 * Retrieves the last recorded gesture.
Jonathan Austin 1:8aa5cdb4ab67 652 *
Jonathan Austin 1:8aa5cdb4ab67 653 * @return The last gesture that was detected.
Jonathan Austin 1:8aa5cdb4ab67 654 *
Jonathan Austin 1:8aa5cdb4ab67 655 * Example:
Jonathan Austin 1:8aa5cdb4ab67 656 * @code
Jonathan Austin 1:8aa5cdb4ab67 657 * MicroBitDisplay display;
Jonathan Austin 1:8aa5cdb4ab67 658 *
Jonathan Austin 1:8aa5cdb4ab67 659 * if (accelerometer.getGesture() == SHAKE)
Jonathan Austin 1:8aa5cdb4ab67 660 * display.scroll("SHAKE!");
Jonathan Austin 1:8aa5cdb4ab67 661 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 662 */
Jonathan Austin 1:8aa5cdb4ab67 663 BasicGesture MicroBitAccelerometer::getGesture()
Jonathan Austin 1:8aa5cdb4ab67 664 {
Jonathan Austin 1:8aa5cdb4ab67 665 return lastGesture;
Jonathan Austin 1:8aa5cdb4ab67 666 }
Jonathan Austin 1:8aa5cdb4ab67 667
Jonathan Austin 1:8aa5cdb4ab67 668 /**
Jonathan Austin 1:8aa5cdb4ab67 669 * A periodic callback invoked by the fiber scheduler idle thread.
Jonathan Austin 1:8aa5cdb4ab67 670 *
Jonathan Austin 1:8aa5cdb4ab67 671 * Internally calls updateSample().
Jonathan Austin 1:8aa5cdb4ab67 672 */
Jonathan Austin 1:8aa5cdb4ab67 673 void MicroBitAccelerometer::idleTick()
Jonathan Austin 1:8aa5cdb4ab67 674 {
Jonathan Austin 1:8aa5cdb4ab67 675 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 676 }
Jonathan Austin 1:8aa5cdb4ab67 677
Jonathan Austin 1:8aa5cdb4ab67 678 /**
Jonathan Austin 1:8aa5cdb4ab67 679 * 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 680 *
Jonathan Austin 1:8aa5cdb4ab67 681 * We check if any data is ready for reading by checking the interrupt flag on the accelerometer.
Jonathan Austin 1:8aa5cdb4ab67 682 */
Jonathan Austin 1:8aa5cdb4ab67 683 int MicroBitAccelerometer::isIdleCallbackNeeded()
Jonathan Austin 1:8aa5cdb4ab67 684 {
Jonathan Austin 1:8aa5cdb4ab67 685 return !int1;
Jonathan Austin 1:8aa5cdb4ab67 686 }
Jonathan Austin 1:8aa5cdb4ab67 687
Jonathan Austin 1:8aa5cdb4ab67 688 /**
Jonathan Austin 1:8aa5cdb4ab67 689 * Destructor for MicroBitAccelerometer, where we deregister from the array of fiber components.
Jonathan Austin 1:8aa5cdb4ab67 690 */
Jonathan Austin 1:8aa5cdb4ab67 691 MicroBitAccelerometer::~MicroBitAccelerometer()
Jonathan Austin 1:8aa5cdb4ab67 692 {
Jonathan Austin 1:8aa5cdb4ab67 693 fiber_remove_idle_component(this);
Jonathan Austin 1:8aa5cdb4ab67 694 }
Jonathan Austin 1:8aa5cdb4ab67 695
Jonathan Austin 1:8aa5cdb4ab67 696 const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = {
Jonathan Austin 1:8aa5cdb4ab67 697 {2, 0},
Jonathan Austin 1:8aa5cdb4ab67 698 {4, 1},
Jonathan Austin 1:8aa5cdb4ab67 699 {8, 2}
Jonathan Austin 1:8aa5cdb4ab67 700 };
Jonathan Austin 1:8aa5cdb4ab67 701
Jonathan Austin 1:8aa5cdb4ab67 702 const MMA8653SampleRateConfig MMA8653SampleRate[MMA8653_SAMPLE_RATES] = {
Jonathan Austin 1:8aa5cdb4ab67 703 {1250, 0x00},
Jonathan Austin 1:8aa5cdb4ab67 704 {2500, 0x08},
Jonathan Austin 1:8aa5cdb4ab67 705 {5000, 0x10},
Jonathan Austin 1:8aa5cdb4ab67 706 {10000, 0x18},
Jonathan Austin 1:8aa5cdb4ab67 707 {20000, 0x20},
Jonathan Austin 1:8aa5cdb4ab67 708 {80000, 0x28},
Jonathan Austin 1:8aa5cdb4ab67 709 {160000, 0x30},
Jonathan Austin 1:8aa5cdb4ab67 710 {640000, 0x38}
LancasterUniversity 6:2e1c2e0d8c7a 711 };