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:18:27 2016 +0100
Revision:
48:34d1adb6771c
Parent:
45:23b71960fe6c
Synchronized with git rev dc9b0078

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 #include "MicroBitConfig.h"
Jonathan Austin 1:8aa5cdb4ab67 27 #include "MicroBitThermometer.h"
Jonathan Austin 1:8aa5cdb4ab67 28 #include "MicroBitSystemTimer.h"
Jonathan Austin 1:8aa5cdb4ab67 29 #include "MicroBitFiber.h"
Jonathan Austin 1:8aa5cdb4ab67 30
Jonathan Austin 1:8aa5cdb4ab67 31 /*
Jonathan Austin 1:8aa5cdb4ab67 32 * The underlying Nordic libraries that support BLE do not compile cleanly with the stringent GCC settings we employ
Jonathan Austin 1:8aa5cdb4ab67 33 * If we're compiling under GCC, then we suppress any warnings generated from this code (but not the rest of the DAL)
Jonathan Austin 1:8aa5cdb4ab67 34 * The ARM cc compiler is more tolerant. We don't test __GNUC__ here to detect GCC as ARMCC also typically sets this
Jonathan Austin 1:8aa5cdb4ab67 35 * as a compatability option, but does not support the options used...
Jonathan Austin 1:8aa5cdb4ab67 36 */
Jonathan Austin 1:8aa5cdb4ab67 37 #if !defined(__arm)
Jonathan Austin 1:8aa5cdb4ab67 38 #pragma GCC diagnostic ignored "-Wunused-function"
Jonathan Austin 1:8aa5cdb4ab67 39 #pragma GCC diagnostic push
Jonathan Austin 1:8aa5cdb4ab67 40 #pragma GCC diagnostic ignored "-Wunused-parameter"
Jonathan Austin 1:8aa5cdb4ab67 41 #endif
Jonathan Austin 1:8aa5cdb4ab67 42
Jonathan Austin 1:8aa5cdb4ab67 43 #include "nrf_soc.h"
Jonathan Austin 1:8aa5cdb4ab67 44 #include "nrf_sdm.h"
Jonathan Austin 1:8aa5cdb4ab67 45
Jonathan Austin 1:8aa5cdb4ab67 46 /*
Jonathan Austin 1:8aa5cdb4ab67 47 * Return to our predefined compiler settings.
Jonathan Austin 1:8aa5cdb4ab67 48 */
Jonathan Austin 1:8aa5cdb4ab67 49 #if !defined(__arm)
Jonathan Austin 1:8aa5cdb4ab67 50 #pragma GCC diagnostic pop
Jonathan Austin 1:8aa5cdb4ab67 51 #endif
Jonathan Austin 1:8aa5cdb4ab67 52
Jonathan Austin 1:8aa5cdb4ab67 53 /**
Jonathan Austin 1:8aa5cdb4ab67 54 * Constructor.
Jonathan Austin 1:8aa5cdb4ab67 55 * Create new MicroBitThermometer that gives an indication of the current temperature.
Jonathan Austin 1:8aa5cdb4ab67 56 *
Jonathan Austin 1:8aa5cdb4ab67 57 * @param _storage an instance of MicroBitStorage used to persist temperature offset data
Jonathan Austin 1:8aa5cdb4ab67 58 *
Jonathan Austin 1:8aa5cdb4ab67 59 * @param id the unique EventModel id of this component. Defaults to MICROBIT_ID_THERMOMETER.
Jonathan Austin 1:8aa5cdb4ab67 60 *
Jonathan Austin 1:8aa5cdb4ab67 61 * @code
Jonathan Austin 1:8aa5cdb4ab67 62 * MicroBitStorage storage;
Jonathan Austin 1:8aa5cdb4ab67 63 * MicroBitThermometer thermometer(storage);
Jonathan Austin 1:8aa5cdb4ab67 64 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 65 */
Jonathan Austin 1:8aa5cdb4ab67 66 MicroBitThermometer::MicroBitThermometer(MicroBitStorage& _storage, uint16_t id) :
Jonathan Austin 1:8aa5cdb4ab67 67 storage(&_storage)
Jonathan Austin 1:8aa5cdb4ab67 68 {
Jonathan Austin 1:8aa5cdb4ab67 69 this->id = id;
Jonathan Austin 1:8aa5cdb4ab67 70 this->samplePeriod = MICROBIT_THERMOMETER_PERIOD;
Jonathan Austin 1:8aa5cdb4ab67 71 this->sampleTime = 0;
Jonathan Austin 1:8aa5cdb4ab67 72 this->offset = 0;
Jonathan Austin 1:8aa5cdb4ab67 73
LancasterUniversity 48:34d1adb6771c 74 KeyValuePair *tempCalibration = storage->get("tempCal");
Jonathan Austin 1:8aa5cdb4ab67 75
Jonathan Austin 1:8aa5cdb4ab67 76 if(tempCalibration != NULL)
Jonathan Austin 1:8aa5cdb4ab67 77 {
Jonathan Austin 1:8aa5cdb4ab67 78 memcpy(&offset, tempCalibration->value, sizeof(int16_t));
Jonathan Austin 1:8aa5cdb4ab67 79 delete tempCalibration;
Jonathan Austin 1:8aa5cdb4ab67 80 }
Jonathan Austin 1:8aa5cdb4ab67 81 }
Jonathan Austin 1:8aa5cdb4ab67 82
Jonathan Austin 1:8aa5cdb4ab67 83 /**
Jonathan Austin 1:8aa5cdb4ab67 84 * Constructor.
Jonathan Austin 1:8aa5cdb4ab67 85 * Create new MicroBitThermometer that gives an indication of the current temperature.
Jonathan Austin 1:8aa5cdb4ab67 86 *
Jonathan Austin 1:8aa5cdb4ab67 87 * @param id the unique EventModel id of this component. Defaults to MICROBIT_ID_THERMOMETER.
Jonathan Austin 1:8aa5cdb4ab67 88 *
Jonathan Austin 1:8aa5cdb4ab67 89 * @code
Jonathan Austin 1:8aa5cdb4ab67 90 * MicroBitThermometer thermometer;
Jonathan Austin 1:8aa5cdb4ab67 91 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 92 */
Jonathan Austin 1:8aa5cdb4ab67 93 MicroBitThermometer::MicroBitThermometer(uint16_t id) :
Jonathan Austin 1:8aa5cdb4ab67 94 storage(NULL)
Jonathan Austin 1:8aa5cdb4ab67 95 {
Jonathan Austin 1:8aa5cdb4ab67 96 this->id = id;
Jonathan Austin 1:8aa5cdb4ab67 97 this->samplePeriod = MICROBIT_THERMOMETER_PERIOD;
Jonathan Austin 1:8aa5cdb4ab67 98 this->sampleTime = 0;
Jonathan Austin 1:8aa5cdb4ab67 99 this->offset = 0;
Jonathan Austin 1:8aa5cdb4ab67 100 }
Jonathan Austin 1:8aa5cdb4ab67 101
Jonathan Austin 1:8aa5cdb4ab67 102 /**
Jonathan Austin 1:8aa5cdb4ab67 103 * Gets the current temperature of the microbit.
Jonathan Austin 1:8aa5cdb4ab67 104 *
Jonathan Austin 1:8aa5cdb4ab67 105 * @return the current temperature, in degrees celsius.
Jonathan Austin 1:8aa5cdb4ab67 106 *
Jonathan Austin 1:8aa5cdb4ab67 107 * @code
Jonathan Austin 1:8aa5cdb4ab67 108 * thermometer.getTemperature();
Jonathan Austin 1:8aa5cdb4ab67 109 * @endcode
Jonathan Austin 1:8aa5cdb4ab67 110 */
Jonathan Austin 1:8aa5cdb4ab67 111 int MicroBitThermometer::getTemperature()
Jonathan Austin 1:8aa5cdb4ab67 112 {
Jonathan Austin 1:8aa5cdb4ab67 113 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 114 return temperature - offset;
Jonathan Austin 1:8aa5cdb4ab67 115 }
Jonathan Austin 1:8aa5cdb4ab67 116
Jonathan Austin 1:8aa5cdb4ab67 117
Jonathan Austin 1:8aa5cdb4ab67 118 /**
Jonathan Austin 1:8aa5cdb4ab67 119 * Updates the temperature sample of this instance of MicroBitThermometer
Jonathan Austin 1:8aa5cdb4ab67 120 * only if isSampleNeeded() indicates that an update is required.
Jonathan Austin 1:8aa5cdb4ab67 121 *
Jonathan Austin 1:8aa5cdb4ab67 122 * This call also will add the thermometer to fiber components to receive
Jonathan Austin 1:8aa5cdb4ab67 123 * periodic callbacks.
Jonathan Austin 1:8aa5cdb4ab67 124 *
Jonathan Austin 1:8aa5cdb4ab67 125 * @return MICROBIT_OK on success.
Jonathan Austin 1:8aa5cdb4ab67 126 */
Jonathan Austin 1:8aa5cdb4ab67 127 int MicroBitThermometer::updateSample()
Jonathan Austin 1:8aa5cdb4ab67 128 {
Jonathan Austin 1:8aa5cdb4ab67 129 if(!(status & MICROBIT_THERMOMETER_ADDED_TO_IDLE))
Jonathan Austin 1:8aa5cdb4ab67 130 {
Jonathan Austin 1:8aa5cdb4ab67 131 // If we're running under a fiber scheduer, register ourselves for a periodic callback to keep our data up to date.
Jonathan Austin 1:8aa5cdb4ab67 132 // Otherwise, we do just do this on demand, when polled through our read() interface.
Jonathan Austin 1:8aa5cdb4ab67 133 fiber_add_idle_component(this);
Jonathan Austin 1:8aa5cdb4ab67 134 status |= MICROBIT_THERMOMETER_ADDED_TO_IDLE;
Jonathan Austin 1:8aa5cdb4ab67 135 }
Jonathan Austin 1:8aa5cdb4ab67 136
Jonathan Austin 1:8aa5cdb4ab67 137 // check if we need to update our sample...
Jonathan Austin 1:8aa5cdb4ab67 138 if(isSampleNeeded())
Jonathan Austin 1:8aa5cdb4ab67 139 {
Jonathan Austin 1:8aa5cdb4ab67 140 int32_t processorTemperature;
Jonathan Austin 1:8aa5cdb4ab67 141 uint8_t sd_enabled;
Jonathan Austin 1:8aa5cdb4ab67 142
Jonathan Austin 1:8aa5cdb4ab67 143 // For now, we just rely on the nrf senesor to be the most accurate.
Jonathan Austin 1:8aa5cdb4ab67 144 // The compass module also has a temperature sensor, and has the lowest power consumption, so will run the cooler...
Jonathan Austin 1:8aa5cdb4ab67 145 // ...however it isn't trimmed for accuracy during manufacture, so requires calibration.
Jonathan Austin 1:8aa5cdb4ab67 146
Jonathan Austin 1:8aa5cdb4ab67 147 sd_softdevice_is_enabled(&sd_enabled);
Jonathan Austin 1:8aa5cdb4ab67 148
Jonathan Austin 1:8aa5cdb4ab67 149 if (sd_enabled)
Jonathan Austin 1:8aa5cdb4ab67 150 {
Jonathan Austin 1:8aa5cdb4ab67 151 // If Bluetooth is enabled, we need to go through the Nordic software to safely do this
Jonathan Austin 1:8aa5cdb4ab67 152 sd_temp_get(&processorTemperature);
Jonathan Austin 1:8aa5cdb4ab67 153 }
Jonathan Austin 1:8aa5cdb4ab67 154 else
Jonathan Austin 1:8aa5cdb4ab67 155 {
Jonathan Austin 1:8aa5cdb4ab67 156 // Othwerwise, we access the information directly...
Jonathan Austin 1:8aa5cdb4ab67 157 uint32_t *TEMP = (uint32_t *)0x4000C508;
Jonathan Austin 1:8aa5cdb4ab67 158
Jonathan Austin 1:8aa5cdb4ab67 159 NRF_TEMP->TASKS_START = 1;
Jonathan Austin 1:8aa5cdb4ab67 160
Jonathan Austin 1:8aa5cdb4ab67 161 while (NRF_TEMP->EVENTS_DATARDY == 0);
Jonathan Austin 1:8aa5cdb4ab67 162
Jonathan Austin 1:8aa5cdb4ab67 163 NRF_TEMP->EVENTS_DATARDY = 0;
Jonathan Austin 1:8aa5cdb4ab67 164
Jonathan Austin 1:8aa5cdb4ab67 165 processorTemperature = *TEMP;
Jonathan Austin 1:8aa5cdb4ab67 166
Jonathan Austin 1:8aa5cdb4ab67 167 NRF_TEMP->TASKS_STOP = 1;
Jonathan Austin 1:8aa5cdb4ab67 168 }
Jonathan Austin 1:8aa5cdb4ab67 169
Jonathan Austin 1:8aa5cdb4ab67 170
Jonathan Austin 1:8aa5cdb4ab67 171 // Record our reading...
Jonathan Austin 1:8aa5cdb4ab67 172 temperature = processorTemperature / 4;
Jonathan Austin 1:8aa5cdb4ab67 173
Jonathan Austin 1:8aa5cdb4ab67 174 // Schedule our next sample.
Jonathan Austin 1:8aa5cdb4ab67 175 sampleTime = system_timer_current_time() + samplePeriod;
Jonathan Austin 1:8aa5cdb4ab67 176
Jonathan Austin 1:8aa5cdb4ab67 177 // Send an event to indicate that we'e updated our temperature.
Jonathan Austin 1:8aa5cdb4ab67 178 MicroBitEvent e(id, MICROBIT_THERMOMETER_EVT_UPDATE);
Jonathan Austin 1:8aa5cdb4ab67 179 }
Jonathan Austin 1:8aa5cdb4ab67 180
Jonathan Austin 1:8aa5cdb4ab67 181 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 182 };
Jonathan Austin 1:8aa5cdb4ab67 183
Jonathan Austin 1:8aa5cdb4ab67 184 /**
Jonathan Austin 1:8aa5cdb4ab67 185 * Periodic callback from MicroBit idle thread.
Jonathan Austin 1:8aa5cdb4ab67 186 */
Jonathan Austin 1:8aa5cdb4ab67 187 void MicroBitThermometer::idleTick()
Jonathan Austin 1:8aa5cdb4ab67 188 {
Jonathan Austin 1:8aa5cdb4ab67 189 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 190 }
Jonathan Austin 1:8aa5cdb4ab67 191
Jonathan Austin 1:8aa5cdb4ab67 192 /**
Jonathan Austin 1:8aa5cdb4ab67 193 * Determines if we're due to take another temperature reading
Jonathan Austin 1:8aa5cdb4ab67 194 *
Jonathan Austin 1:8aa5cdb4ab67 195 * @return 1 if we're due to take a temperature reading, 0 otherwise.
Jonathan Austin 1:8aa5cdb4ab67 196 */
Jonathan Austin 1:8aa5cdb4ab67 197 int MicroBitThermometer::isSampleNeeded()
Jonathan Austin 1:8aa5cdb4ab67 198 {
Jonathan Austin 1:8aa5cdb4ab67 199 return system_timer_current_time() >= sampleTime;
Jonathan Austin 1:8aa5cdb4ab67 200 }
Jonathan Austin 1:8aa5cdb4ab67 201
Jonathan Austin 1:8aa5cdb4ab67 202 /**
Jonathan Austin 1:8aa5cdb4ab67 203 * Set the sample rate at which the temperatureis read (in ms).
Jonathan Austin 1:8aa5cdb4ab67 204 *
Jonathan Austin 1:8aa5cdb4ab67 205 * The default sample period is 1 second.
Jonathan Austin 1:8aa5cdb4ab67 206 *
Jonathan Austin 1:8aa5cdb4ab67 207 * @param period the requested time between samples, in milliseconds.
Jonathan Austin 1:8aa5cdb4ab67 208 *
Jonathan Austin 1:8aa5cdb4ab67 209 * @note the temperature is always read in the background, and is only updated
Jonathan Austin 1:8aa5cdb4ab67 210 * when the processor is idle, or when the temperature is explicitly read.
Jonathan Austin 1:8aa5cdb4ab67 211 */
Jonathan Austin 1:8aa5cdb4ab67 212 void MicroBitThermometer::setPeriod(int period)
Jonathan Austin 1:8aa5cdb4ab67 213 {
Jonathan Austin 1:8aa5cdb4ab67 214 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 215 samplePeriod = period;
Jonathan Austin 1:8aa5cdb4ab67 216 }
Jonathan Austin 1:8aa5cdb4ab67 217
Jonathan Austin 1:8aa5cdb4ab67 218 /**
Jonathan Austin 1:8aa5cdb4ab67 219 * Reads the currently configured sample rate of the thermometer.
Jonathan Austin 1:8aa5cdb4ab67 220 *
Jonathan Austin 1:8aa5cdb4ab67 221 * @return The time between samples, in milliseconds.
Jonathan Austin 1:8aa5cdb4ab67 222 */
Jonathan Austin 1:8aa5cdb4ab67 223 int MicroBitThermometer::getPeriod()
Jonathan Austin 1:8aa5cdb4ab67 224 {
Jonathan Austin 1:8aa5cdb4ab67 225 return samplePeriod;
Jonathan Austin 1:8aa5cdb4ab67 226 }
Jonathan Austin 1:8aa5cdb4ab67 227
Jonathan Austin 1:8aa5cdb4ab67 228 /**
Jonathan Austin 1:8aa5cdb4ab67 229 * Set the value that is used to offset the raw silicon temperature.
Jonathan Austin 1:8aa5cdb4ab67 230 *
Jonathan Austin 1:8aa5cdb4ab67 231 * @param offset the offset for the silicon temperature
Jonathan Austin 1:8aa5cdb4ab67 232 *
Jonathan Austin 1:8aa5cdb4ab67 233 * @return MICROBIT_OK on success
Jonathan Austin 1:8aa5cdb4ab67 234 */
Jonathan Austin 1:8aa5cdb4ab67 235 int MicroBitThermometer::setOffset(int offset)
Jonathan Austin 1:8aa5cdb4ab67 236 {
Jonathan Austin 1:8aa5cdb4ab67 237 if(this->storage != NULL)
LancasterUniversity 37:b624ae5e94a5 238 this->storage->put(ManagedString("tempCal"), (uint8_t *)&offset, sizeof(int));
Jonathan Austin 1:8aa5cdb4ab67 239
Jonathan Austin 1:8aa5cdb4ab67 240 this->offset = offset;
Jonathan Austin 1:8aa5cdb4ab67 241
Jonathan Austin 1:8aa5cdb4ab67 242 return MICROBIT_OK;
Jonathan Austin 1:8aa5cdb4ab67 243 }
Jonathan Austin 1:8aa5cdb4ab67 244
Jonathan Austin 1:8aa5cdb4ab67 245 /**
Jonathan Austin 1:8aa5cdb4ab67 246 * Retreive the value that is used to offset the raw silicon temperature.
Jonathan Austin 1:8aa5cdb4ab67 247 *
Jonathan Austin 1:8aa5cdb4ab67 248 * @return the current offset.
Jonathan Austin 1:8aa5cdb4ab67 249 */
Jonathan Austin 1:8aa5cdb4ab67 250 int MicroBitThermometer::getOffset()
Jonathan Austin 1:8aa5cdb4ab67 251 {
Jonathan Austin 1:8aa5cdb4ab67 252 return offset;
Jonathan Austin 1:8aa5cdb4ab67 253 }
Jonathan Austin 1:8aa5cdb4ab67 254
Jonathan Austin 1:8aa5cdb4ab67 255 /**
Jonathan Austin 1:8aa5cdb4ab67 256 * This member function fetches the raw silicon temperature, and calculates
Jonathan Austin 1:8aa5cdb4ab67 257 * the value used to offset the raw silicon temperature based on a given temperature.
Jonathan Austin 1:8aa5cdb4ab67 258 *
Jonathan Austin 1:8aa5cdb4ab67 259 * @param calibrationTemp the temperature used to calculate the raw silicon temperature
Jonathan Austin 1:8aa5cdb4ab67 260 * offset.
Jonathan Austin 1:8aa5cdb4ab67 261 *
Jonathan Austin 1:8aa5cdb4ab67 262 * @return MICROBIT_OK on success
Jonathan Austin 1:8aa5cdb4ab67 263 */
Jonathan Austin 1:8aa5cdb4ab67 264 int MicroBitThermometer::setCalibration(int calibrationTemp)
Jonathan Austin 1:8aa5cdb4ab67 265 {
Jonathan Austin 1:8aa5cdb4ab67 266 updateSample();
Jonathan Austin 1:8aa5cdb4ab67 267 return setOffset(temperature - calibrationTemp);
LancasterUniversity 30:db87179335d5 268 }