diff --git a/inc/MicroBit.h b/inc/MicroBit.h index ba061e0..9f8a56e 100644 --- a/inc/MicroBit.h +++ b/inc/MicroBit.h @@ -22,6 +22,7 @@ #include "MicroBitPin.h" #include "MicroBitCompass.h" #include "MicroBitAccelerometer.h" +#include "MicroBitThermometer.h" #include "MicroBitMultiButton.h" #include "MicroBitSerial.h" @@ -105,6 +106,7 @@ class MicroBit MicroBitMultiButton buttonAB; MicroBitAccelerometer accelerometer; MicroBitCompass compass; + MicroBitThermometer thermometer; //An object of available IO pins on the device MicroBitIO io; diff --git a/inc/MicroBitAccelerometerService.h b/inc/MicroBitAccelerometerService.h index e9567d4..00976af 100644 --- a/inc/MicroBitAccelerometerService.h +++ b/inc/MicroBitAccelerometerService.h @@ -42,7 +42,7 @@ class MicroBitAccelerometerService // memory for our 8 bit control characteristics. uint16_t accelerometerDataCharacteristicBuffer[3]; - uint8_t accelerometerPeriodCharacteristicBuffer; + uint16_t accelerometerPeriodCharacteristicBuffer; // Handles to access each characteristic when they are held by Soft Device. GattAttribute::Handle_t accelerometerDataCharacteristicHandle; diff --git a/inc/MicroBitCompass.h b/inc/MicroBitCompass.h index 52a0cef..00dc547 100644 --- a/inc/MicroBitCompass.h +++ b/inc/MicroBitCompass.h @@ -36,8 +36,6 @@ #define MAG_CTRL_REG1 0x10 #define MAG_CTRL_REG2 0x11 -#define MICROBIT_COMPASS_TEMPERATURE_SENSE_PERIOD 1000 - /** * Configuration options */ @@ -58,7 +56,7 @@ extern const MAG3110SampleRateConfig MAG3110SampleRate[]; #define MICROBIT_COMPASS_EVT_CAL_START 2 #define MICROBIT_COMPASS_EVT_CAL_END 3 #define MICROBIT_COMPASS_EVT_DATA_UPDATE 4 -#define MICROBIT_COMPASS_EVT_TEMPERATURE_UPDATE 5 +#define MICROBIT_COMPASS_EVT_CONFIG_NEEDED 5 /* * Status Bits @@ -80,7 +78,6 @@ struct CompassSample int16_t x; int16_t y; int16_t z; - int16_t temperature; CompassSample() { @@ -106,16 +103,14 @@ class MicroBitCompass : public MicroBitComponent uint16_t address; // I2C address of the magnetmometer. uint16_t samplePeriod; // The time between samples, in millseconds. unsigned long eventStartTime; // used to store the current system clock when async calibration has started - unsigned long temperatureSampleTime; // used to store the current system clock when async calibration has started - uint8_t temperature; // the current die temperture of the compass chip. - public: - CompassSample minSample; // Calibration sample. CompassSample maxSample; // Calibration sample. CompassSample average; // Centre point of sample data. CompassSample sample; // The latest sample data recorded. DigitalIn int1; // Data ready interrupt. + + public: /** * Constructor. @@ -218,7 +213,7 @@ class MicroBitCompass : public MicroBitComponent * Reads the currently die temperature of the compass. * @return The temperature, in degrees celsius. */ - int getTemperature(); + int readTemperature(); /** * Perform the asynchronous calibration of the compass. @@ -305,7 +300,7 @@ class MicroBitCompass : public MicroBitComponent * @param reg The based address of the 16 bit register to access. * @return The register value, interpreted as a 8 bi signed value. */ - int16_t read8(uint8_t reg); + uint8_t read8(uint8_t reg); }; #endif diff --git a/inc/MicroBitComponent.h b/inc/MicroBitComponent.h index 7779069..f836a36 100644 --- a/inc/MicroBitComponent.h +++ b/inc/MicroBitComponent.h @@ -16,6 +16,7 @@ #define MICROBIT_ID_ACCELEROMETER 4 #define MICROBIT_ID_COMPASS 5 #define MICROBIT_ID_DISPLAY 6 +#define MICROBIT_ID_THERMOMETER 7 //EDGE connector events #define MICROBIT_IO_PINS 20 diff --git a/inc/MicroBitConfig.h b/inc/MicroBitConfig.h index c919598..dd06ebf 100644 --- a/inc/MicroBitConfig.h +++ b/inc/MicroBitConfig.h @@ -157,40 +157,40 @@ // This enables the control and the LED matrix display via BLE. // Set '1' to enable. #ifndef MICROBIT_BLE_LED_SERVICE -#define MICROBIT_BLE_LED_SERVICE 1 +#define MICROBIT_BLE_LED_SERVICE 0 #endif // Enable/Disable BLE Service: MicroBitAccelerometerService // This enables live access to the on board 3 axis accelerometer. // Set '1' to enable. #ifndef MICROBIT_BLE_ACCELEROMETER_SERVICE -#define MICROBIT_BLE_ACCELEROMETER_SERVICE 1 +#define MICROBIT_BLE_ACCELEROMETER_SERVICE 0 #endif // Enable/Disable BLE Service: MicroBitMagnetometerService // This enables live access to the on board 3 axis magnetometer. // Set '1' to enable. #ifndef MICROBIT_BLE_MAGNETOMETER_SERVICE -#define MICROBIT_BLE_MAGNETOMETER_SERVICE 1 +#define MICROBIT_BLE_MAGNETOMETER_SERVICE 0 #endif // Enable/Disable BLE Service: MicroBitButtonService // This enables live access to the two micro:bit buttons. // Set '1' to enable. #ifndef MICROBIT_BLE_BUTTON_SERVICE -#define MICROBIT_BLE_BUTTON_SERVICE 1 +#define MICROBIT_BLE_BUTTON_SERVICE 0 #endif // This enables live access to the two micro:bit buttons. // Set '1' to enable. #ifndef MICROBIT_BLE_IO_PIN_SERVICE -#define MICROBIT_BLE_IO_PIN_SERVICE 1 +#define MICROBIT_BLE_IO_PIN_SERVICE 0 #endif // This enables live access to the die temperature sensors on the micro:bit. // Set '1' to enable. #ifndef MICROBIT_BLE_TEMPERATURE_SERVICE -#define MICROBIT_BLE_TEMPERATURE_SERVICE 1 +#define MICROBIT_BLE_TEMPERATURE_SERVICE 0 #endif // Defines the maximum length strong that can be written to the diff --git a/inc/MicroBitDFUService.h b/inc/MicroBitDFUService.h index eaa5850..1d94f32 100644 --- a/inc/MicroBitDFUService.h +++ b/inc/MicroBitDFUService.h @@ -68,9 +68,6 @@ class MicroBitDFUService private: - // BLE pairing name of this device, encoded as an integer. - uint32_t flashCode; - // State of paiting process. bool authenticated; bool flashCodeRequested; @@ -78,9 +75,12 @@ class MicroBitDFUService // Bluetooth stack we're running on. BLEDevice &ble; - // memory for our 8 bit control characteristics. + // memory for our 8 bit control characteristic. uint8_t controlByte; + // BLE pairing name of this device, encoded as an integer. + uint32_t flashCode; + GattAttribute::Handle_t microBitDFUServiceControlCharacteristicHandle; GattAttribute::Handle_t microBitDFUServiceFlashCodeCharacteristicHandle; diff --git a/inc/MicroBitEventService.h b/inc/MicroBitEventService.h index 1c751ca..3ce1aa6 100644 --- a/inc/MicroBitEventService.h +++ b/inc/MicroBitEventService.h @@ -7,6 +7,8 @@ extern const uint8_t MicroBitEventServiceUUID[]; extern const uint8_t MicroBitEventServiceMicroBitEventCharacteristicUUID[]; extern const uint8_t MicroBitEventServiceClientEventCharacteristicUUID[]; +extern const uint8_t MicroBitEventServiceMicroBitRequirementsCharacteristicUUID[]; +extern const uint8_t MicroBitEventServiceClientRequirementsCharacteristicUUID[]; struct EventServiceEvent { @@ -19,7 +21,7 @@ struct EventServiceEvent * Class definition for a MicroBit BLE Event Service. * Provides a _ble gateway onto the MicroBit Message Bus. */ -class MicroBitEventService +class MicroBitEventService : public MicroBitComponent { public: @@ -29,7 +31,13 @@ class MicroBitEventService * @param BLE The instance of a BLE device that we're running on. */ MicroBitEventService(BLEDevice &_ble); - + + /** + * Periodic callback from MicroBit scheduler. + * If we're no longer connected, remove any registered Message Bus listeners. + */ + virtual void idleTick(); + /** * Callback. Invoked when any of our attributes are written via BLE. */ @@ -40,17 +48,32 @@ class MicroBitEventService */ void onMicroBitEvent(MicroBitEvent evt); + /** + * read callback on microBitRequirements characteristic. + * Used to iterate through the events that the code on this micro:bit is interested in. + */ + void onRequirementsRead(GattReadAuthCallbackParams *params); + private: // Bluetooth stack we're running on. BLEDevice &ble; - // memory for our 8 bit control characteristics. + // memory for our event characteristics. EventServiceEvent clientEventBuffer; EventServiceEvent microBitEventBuffer; + EventServiceEvent microBitRequirementsBuffer; + EventServiceEvent clientRequirementsBuffer; + // handles on this service's characterisitics. GattAttribute::Handle_t microBitEventCharacteristicHandle; + GattAttribute::Handle_t clientRequirementsCharacteristicHandle; GattAttribute::Handle_t clientEventCharacteristicHandle; + GattCharacteristic *microBitRequirementsCharacteristic; + + // Message bus offset last sent to the client... + uint16_t messageBusListenerOffset; + }; diff --git a/inc/MicroBitMagnetometerService.h b/inc/MicroBitMagnetometerService.h index a7ec9c5..ee9595a 100644 --- a/inc/MicroBitMagnetometerService.h +++ b/inc/MicroBitMagnetometerService.h @@ -38,6 +38,13 @@ class MicroBitMagnetometerService */ void magnetometerUpdate(MicroBitEvent e); + /** + * Sample Period Change Needed callback. + * Reconfiguring the magnetometer can to a REALLY long time (sometimes even seconds to complete) + * So we do this in the background when necessary, through this event handler. + */ + void samplePeriodUpdateNeeded(MicroBitEvent e); + // Bluetooth stack we're running on. BLEDevice &ble; diff --git a/inc/MicroBitMessageBus.h b/inc/MicroBitMessageBus.h index 0c27a8f..6c2a747 100644 --- a/inc/MicroBitMessageBus.h +++ b/inc/MicroBitMessageBus.h @@ -205,6 +205,13 @@ class MicroBitMessageBus : public MicroBitComponent template void ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent)); + /** + * Returns the microBitListener with the given position in our list. + * @param n The position in the list to return. + * @return the MicroBitListener at postion n in the list, or NULL if the position is invalid. + */ + MicroBitListener *elementAt(int n); + /** * Returns a 'nonce' for use with the NONCE_ID channel of the message bus. */ diff --git a/inc/MicroBitThermometer.h b/inc/MicroBitThermometer.h new file mode 100644 index 0000000..7048978 --- /dev/null +++ b/inc/MicroBitThermometer.h @@ -0,0 +1,102 @@ +#ifndef MICROBIT_THERMOMETER_H +#define MICROBIT_THERMOMETER_H + +#include "mbed.h" +#include "MicroBitComponent.h" + +#define MICROBIT_THERMOMETER_PERIOD 1000 + + +#define MAG3110_SAMPLE_RATES 11 + +/* + * Temperature events + */ +#define MICROBIT_THERMOMETER_EVT_UPDATE 1 + +/** + * Class definition for MicroBit Thermometer. + * + * Infers and stores the ambient temoperature based on the surface temperature + * of the various chips on the micro:bit. + * + */ +class MicroBitThermometer : public MicroBitComponent +{ + unsigned long sampleTime; + uint32_t samplePeriod; + int16_t temperature; + + public: + /** + * Constructor. + * Create new object that can sense temperature. + * @param id the ID of the new MicroBitThermometer object. + * + * Example: + * @code + * thermometer(MICROBIT_ID_THERMOMETER); + * @endcode + * + * Possible Events: + * @code + * MICROBIT_THERMOMETER_EVT_CHANGED + * @endcode + */ + MicroBitThermometer(uint16_t id); + + /** + * Set the sample rate at which the temperatureis read (in ms). + * n.b. the temperature is alwasy read in the background, so wis only updated + * when the processor is idle, or when the temperature is explicitly read. + * The default sample period is 1 second. + * @param period the requested time between samples, in milliseconds. + */ + void setPeriod(int period); + + /** + * Reads the currently configured sample rate of the thermometer. + * @return The time between samples, in milliseconds. + */ + int getPeriod(); + + /** + * Gets the current temperature of the microbit. + * @return the current temperature, in degrees celsius. + * + * Example: + * @code + * uBit.thermometer.getTemperature(); + * @endcode + */ + int getTemperature(); + + /** + * Periodic callback from MicroBit idle thread. + * Check if any data is ready for reading by checking the interrupt. + */ + virtual void idleTick(); + + /** + * Indicates if we'd like some processor time to sense the temperature. 0 means we're not due to read the tmeperature yet. + * @returns 1 if we'd like some processor time, 0 otherwise. + */ + virtual int isIdleCallbackNeeded(); + + private: + + /** + * Determines if we're due to take another temeoratur reading + * @return 1 if we're due to take a temperature reading, 0 otherwise. + */ + int isSampleNeeded(); + + /** + * Updates our recorded temeprature from the many sensors on the micro:bit! + */ + void updateTemperature(); + + +}; + +#endif diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 974df59..2be1c77 100755 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -18,6 +18,7 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES "MicroBitFiber.cpp" "ManagedString.cpp" "MicroBitAccelerometer.cpp" + "MicroBitThermometer.cpp" "MicroBitIO.cpp" "MicroBitCompat.cpp" "MicroBitImage.cpp" diff --git a/source/MicroBit.cpp b/source/MicroBit.cpp index 7b64b54..e99aa96 100644 --- a/source/MicroBit.cpp +++ b/source/MicroBit.cpp @@ -59,6 +59,7 @@ MicroBit::MicroBit() : buttonAB(MICROBIT_ID_BUTTON_AB,MICROBIT_ID_BUTTON_A,MICROBIT_ID_BUTTON_B), accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR), compass(MICROBIT_ID_COMPASS, MAG3110_DEFAULT_ADDR), + thermometer(MICROBIT_ID_THERMOMETER), io(MICROBIT_ID_IO_P0,MICROBIT_ID_IO_P1,MICROBIT_ID_IO_P2, MICROBIT_ID_IO_P3,MICROBIT_ID_IO_P4,MICROBIT_ID_IO_P5, MICROBIT_ID_IO_P6,MICROBIT_ID_IO_P7,MICROBIT_ID_IO_P8, diff --git a/source/MicroBitAccelerometer.cpp b/source/MicroBitAccelerometer.cpp index 18524a3..a849c31 100644 --- a/source/MicroBitAccelerometer.cpp +++ b/source/MicroBitAccelerometer.cpp @@ -144,7 +144,6 @@ int MicroBitAccelerometer::whoAmI() void MicroBitAccelerometer::update() { int8_t data[6]; - static int count=0; readCommand(MMA8653_OUT_X_MSB, (uint8_t *)data, 6); diff --git a/source/MicroBitCompass.cpp b/source/MicroBitCompass.cpp index 019904f..b6a192c 100644 --- a/source/MicroBitCompass.cpp +++ b/source/MicroBitCompass.cpp @@ -23,16 +23,11 @@ MicroBitCompass::MicroBitCompass(uint16_t id, uint16_t address) : average(), sam this->id = id; this->address = address; - //we presume it's calibrated until the average values are read. + //we presume the device calibrated until the average values are read. this->status = 0x01; //initialise eventStartTime to 0 this->eventStartTime = 0; - this->temperatureSampleTime = 0; - this->temperature = 0; - - // Enable automatic reset after each sample; - writeCommand(MAG_CTRL_REG2, 0xA0); // Select 10Hz update rate, with oversampling, and enable the device. this->samplePeriod = 100; @@ -109,9 +104,9 @@ int16_t MicroBitCompass::read16(uint8_t reg) * @param reg The based address of the 16 bit register to access. * @return The register value, interpreted as a 8 bi signed value. */ -int16_t MicroBitCompass::read8(uint8_t reg) +uint8_t MicroBitCompass::read8(uint8_t reg) { - int8_t data; + uint8_t data; data = 0; readCommand(reg, (uint8_t*) &data, 1); @@ -186,19 +181,6 @@ void MicroBitCompass::idleTick() } } - // Update the temperature value if needed - if (temperatureSampleTime == 0 || temperatureSampleTime > ticks) - { - uint8_t data; - - readCommand(MAG_DIE_TEMP, &data, 1); - temperature = data; - - temperatureSampleTime = ticks + MICROBIT_COMPASS_TEMPERATURE_SENSE_PERIOD; - - // Indicate that a new sample is available - MicroBitEvent e(id, MICROBIT_COMPASS_EVT_TEMPERATURE_UPDATE); - } } /** @@ -253,7 +235,14 @@ void MicroBitCompass::configure() { const MAG3110SampleRateConfig *actualSampleRate; - // First find the nearest sample rate to that specified. + // First, take the device offline, so it can be configured. + writeCommand(MAG_CTRL_REG1, 0x00); + + // Wait for the part to enter standby mode... + while(this->read8(MAG_SYSMOD) & 0x03) + uBit.sleep(100); + + // Find the nearest sample rate to that specified. actualSampleRate = &MAG3110SampleRate[MAG3110_SAMPLE_RATES-1]; for (int i=MAG3110_SAMPLE_RATES-1; i>=0; i--) { @@ -266,11 +255,13 @@ void MicroBitCompass::configure() // OK, we have the correct data. Update our local state. this->samplePeriod = actualSampleRate->sample_period / 1000; + // Enable automatic reset after each sample; + writeCommand(MAG_CTRL_REG2, 0xA0); + // Bring the device online, with the requested sample frequency. writeCommand(MAG_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01); } - /** * Attempts to set the sample rate of the compass to the specified value (in ms). * n.b. the requested rate may not be possible on the hardware. In this case, the @@ -314,8 +305,11 @@ int MicroBitCompass::whoAmI() * Reads the currently die temperature of the compass. * @return The temperature, in degrees celsius. */ -int MicroBitCompass::getTemperature() +int MicroBitCompass::readTemperature() { + int8_t temperature; + readCommand(MAG_DIE_TEMP, (uint8_t *)&temperature, 1); + return temperature; } @@ -423,13 +417,13 @@ int MicroBitCompass::isIdleCallbackNeeded() const MAG3110SampleRateConfig MAG3110SampleRate[MAG3110_SAMPLE_RATES] = { {12500, 0x00}, // 80 Hz {25000, 0x20}, // 40 Hz - {50000, 0x40}, // 20 Hz + {50000, 0x40}, // 20 Hz {100000, 0x60}, // 10 hz {200000, 0x80}, // 5 hz - {400000, 0x81}, // 2.5 hz - {800000, 0x82}, // 1.25 hz + {400000, 0x88}, // 2.5 hz + {800000, 0x90}, // 1.25 hz {1600000, 0xb0}, // 0.63 hz {3200000, 0xd0}, // 0.31 hz {6400000, 0xf0}, // 0.16 hz - {12800000, 0xf1} // 0.08 hz + {12800000, 0xf8} // 0.08 hz }; diff --git a/source/MicroBitFiber.cpp b/source/MicroBitFiber.cpp index e5e6685..67b3351 100644 --- a/source/MicroBitFiber.cpp +++ b/source/MicroBitFiber.cpp @@ -226,7 +226,6 @@ void scheduler_event(MicroBitEvent evt) } // Unregister this event, as we've woken up all the fibers with this match. - pc.printf("Scheduler: Deregistering for Event: %d:%d\n", evt.source, evt.value); uBit.MessageBus.ignore(evt.source, evt.value, scheduler_event); } @@ -311,7 +310,6 @@ void fiber_wait_for_event(uint16_t id, uint16_t value) queue_fiber(f, &waitQueue); // Register to receive this event, so we can wake up the fiber when it happens. - pc.printf("Scheduler: Registering for Event: %d:%d\n", id, value); uBit.MessageBus.listen(id, value, scheduler_event, MESSAGE_BUS_LISTENER_NONBLOCKING); // Finally, enter the scheduler. diff --git a/source/MicroBitMessageBus.cpp b/source/MicroBitMessageBus.cpp index 6d69d02..6478945 100644 --- a/source/MicroBitMessageBus.cpp +++ b/source/MicroBitMessageBus.cpp @@ -374,7 +374,6 @@ int MicroBitMessageBus::add(MicroBitListener *newListener) if (newListener == NULL) return 0; - l = listeners; // Firstly, we treat a listener as an idempotent operation. Ensure we don't already have this handler @@ -459,25 +458,28 @@ int MicroBitMessageBus::remove(MicroBitListener *listener) // Walk this list of event handlers. Delete any that match the given listener. while (l != NULL) { - if (l->id == listener->id && l->value == listener->value && ((listener->flags & MESSAGE_BUS_LISTENER_METHOD) == (l->flags & MESSAGE_BUS_LISTENER_METHOD))) + if ((listener->flags & MESSAGE_BUS_LISTENER_METHOD) == (l->flags & MESSAGE_BUS_LISTENER_METHOD)) { if(((listener->flags & MESSAGE_BUS_LISTENER_METHOD) && (*l->cb_method == *listener->cb_method)) || - ((!(listener->flags & MESSAGE_BUS_LISTENER_METHOD) && l->cb == listener->cb))) + ((!(listener->flags & MESSAGE_BUS_LISTENER_METHOD) && l->cb == listener->cb))) { - // Found a match. Remove from the list. - if (p == NULL) - listeners = l->next; - else - p->next = l->next; + if ((listener->id == MICROBIT_ID_ANY || listener->id == l->id) && (listener->value == MICROBIT_EVT_ANY || listener->value == l->value)) + { + // Found a match. Remove from the list. + if (p == NULL) + listeners = l->next; + else + p->next = l->next; - // delete the listener. - MicroBitListener *t = l; - l = l->next; + // delete the listener. + MicroBitListener *t = l; + l = l->next; - delete t; - removed++; + delete t; + removed++; - continue; + continue; + } } } @@ -488,3 +490,24 @@ int MicroBitMessageBus::remove(MicroBitListener *listener) return removed; } +/** + * Returns the microBitListener with the given position in our list. + * @param n The position in the list to return. + * @return the MicroBitListener at postion n in the list, or NULL if the position is invalid. + */ +MicroBitListener* MicroBitMessageBus::elementAt(int n) +{ + MicroBitListener *l = listeners; + + while (n > 0) + { + if (l == NULL) + return NULL; + + n--; + l = l->next; + } + + return l; +} + diff --git a/source/MicroBitThermometer.cpp b/source/MicroBitThermometer.cpp new file mode 100644 index 0000000..8e1df04 --- /dev/null +++ b/source/MicroBitThermometer.cpp @@ -0,0 +1,136 @@ +#include "MicroBit.h" +#include "nrf_soc.h" + +/** + * Constructor. + * Create new object that can sense temperature. + * @param id the ID of the new MicroBitThermometer object. + * + * Example: + * @code + * thermometer(MICROBIT_ID_THERMOMETER); + * @endcode + * + * Possible Events: + * @code + * MICROBIT_THERMOMETER_EVT_CHANGED + * @endcode + */ +MicroBitThermometer::MicroBitThermometer(uint16_t id) +{ + this->id = id; + this->samplePeriod = MICROBIT_THERMOMETER_PERIOD; + this->sampleTime = 0; + + uBit.addIdleComponent(this); +} + +/** + * Gets the current temperature of the microbit. + * @return the current temperature, in degrees celsius. + * + * Example: + * @code + * uBit.thermometer.getTemperature(); + * @endcode + */ +int MicroBitThermometer::getTemperature() +{ + if (isSampleNeeded()) + updateTemperature(); + + return temperature; +} + +/** + * Indicates if we'd like some processor time to sense the temperature. 0 means we're not due to read the tmeperature yet. + * @returns 1 if we'd like some processor time, 0 otherwise. + */ +int MicroBitThermometer::isIdleCallbackNeeded() +{ + return isSampleNeeded(); +} +/** + * periodic callback. + * Check once every second or so for a new temperature reading. + */ +void MicroBitThermometer::idleTick() +{ + if (isSampleNeeded()) + updateTemperature(); +} + +/** + * Determines if we're due to take another temeoratur reading + * @return 1 if we're due to take a temperature reading, 0 otherwise. + */ +int MicroBitThermometer::isSampleNeeded() +{ + return ticks >= sampleTime; +} + +/** + * Set the sample rate at which the temperatureis read (in ms). + * n.b. the temperature is alwasy read in the background, so wis only updated + * when the processor is idle, or when the temperature is explicitly read. + * The default sample period is 1 second. + * @param period the requested time between samples, in milliseconds. + */ +void MicroBitThermometer::setPeriod(int period) +{ + samplePeriod = period; +} + +/** + * Reads the currently configured sample rate of the thermometer. + * @return The time between samples, in milliseconds. + */ +int MicroBitThermometer::getPeriod() +{ + return samplePeriod; +} + +/** + * Updates our recorded temperature from the many sensors on the micro:bit! + */ +void MicroBitThermometer::updateTemperature() +{ + int32_t processorTemperature; + + // For now, we just rely on the nrf senesor to be the most accurate. + // The compass module also has a temperature sensor, and has the lowest power consumption, so will run the cooler... + // ...however it isn't trimmed for accuracy during manufacture, so requires calibration. + + if (uBit.ble) + { + // If Bluetooth is enabled, we need to go through the Nordic software to safely do this + sd_temp_get(&processorTemperature); + } + else + { + // Othwerwise, we access the information directly... + uint32_t *TEMP = (uint32_t *)0x4000C508; + + NRF_TEMP->TASKS_START = 1; + + while (NRF_TEMP->EVENTS_DATARDY == 0); + + NRF_TEMP->EVENTS_DATARDY = 0; + + processorTemperature = *TEMP; + + NRF_TEMP->TASKS_STOP = 1; + } + + + // Record our reading... + temperature = processorTemperature / 4; + + // Schedule our next sample. + sampleTime = ticks + samplePeriod; + + // Send an event to indicate that we'e updated our temperature. + MicroBitEvent e(id, MICROBIT_THERMOMETER_EVT_UPDATE); +} + + diff --git a/source/ble-services/MicroBitAccelerometerService.cpp b/source/ble-services/MicroBitAccelerometerService.cpp index c846b34..3a2cb08 100644 --- a/source/ble-services/MicroBitAccelerometerService.cpp +++ b/source/ble-services/MicroBitAccelerometerService.cpp @@ -20,7 +20,7 @@ MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble) : GattCharacteristic accelerometerDataCharacteristic(MicroBitAccelerometerServiceDataUUID, (uint8_t *)accelerometerDataCharacteristicBuffer, 0, sizeof(accelerometerDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); - GattCharacteristic accelerometerPeriodCharacteristic(MicroBitAccelerometerServicePeriodUUID, (uint8_t *)accelerometerPeriodCharacteristicBuffer, 0, + GattCharacteristic accelerometerPeriodCharacteristic(MicroBitAccelerometerServicePeriodUUID, (uint8_t *)&accelerometerPeriodCharacteristicBuffer, 0, sizeof(accelerometerPeriodCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE); @@ -28,7 +28,7 @@ MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble) : accelerometerDataCharacteristicBuffer[0] = 0; accelerometerDataCharacteristicBuffer[1] = 0; accelerometerDataCharacteristicBuffer[2] = 0; - accelerometerPeriodCharacteristicBuffer = 0; + accelerometerPeriodCharacteristicBuffer = uBit.accelerometer.getPeriod(); GattCharacteristic *characteristics[] = {&accelerometerDataCharacteristic, &accelerometerPeriodCharacteristic}; GattService service(MicroBitAccelerometerServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *)); @@ -38,8 +38,8 @@ MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble) : accelerometerDataCharacteristicHandle = accelerometerDataCharacteristic.getValueHandle(); accelerometerPeriodCharacteristicHandle = accelerometerPeriodCharacteristic.getValueHandle(); - ble.updateCharacteristicValue(accelerometerDataCharacteristicHandle, (const uint8_t *)&accelerometerDataCharacteristicBuffer, sizeof(accelerometerDataCharacteristicBuffer)); - ble.updateCharacteristicValue(accelerometerPeriodCharacteristicHandle, (const uint8_t *)&accelerometerPeriodCharacteristicBuffer, sizeof(accelerometerPeriodCharacteristicBuffer)); + ble.gattServer().write(accelerometerDataCharacteristicHandle,(uint8_t *)accelerometerDataCharacteristicBuffer, sizeof(accelerometerDataCharacteristicBuffer)); + ble.gattServer().write(accelerometerPeriodCharacteristicHandle, (const uint8_t *)&accelerometerPeriodCharacteristicBuffer, sizeof(accelerometerPeriodCharacteristicBuffer)); ble.onDataWritten(this, &MicroBitAccelerometerService::onDataWritten); uBit.MessageBus.listen(MICROBIT_ID_ACCELEROMETER, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE, this, &MicroBitAccelerometerService::accelerometerUpdate, MESSAGE_BUS_LISTENER_NONBLOCKING | MESSAGE_BUS_LISTENER_URGENT); @@ -52,8 +52,13 @@ void MicroBitAccelerometerService::onDataWritten(const GattWriteCallbackParams * { if (params->handle == accelerometerPeriodCharacteristicHandle && params->len >= sizeof(accelerometerPeriodCharacteristicBuffer)) { - accelerometerPeriodCharacteristicBuffer = *((uint8_t *)params->data); + accelerometerPeriodCharacteristicBuffer = *((uint16_t *)params->data); uBit.accelerometer.setPeriod(accelerometerPeriodCharacteristicBuffer); + + // The accelerometer will choose the nearest period to that requested that it can support + // Read back the ACTUAL period it is using, and report this back. + accelerometerPeriodCharacteristicBuffer = uBit.accelerometer.getPeriod(); + ble.gattServer().write(accelerometerPeriodCharacteristicHandle, (const uint8_t *)&accelerometerPeriodCharacteristicBuffer, sizeof(accelerometerPeriodCharacteristicBuffer)); } } @@ -62,11 +67,14 @@ void MicroBitAccelerometerService::onDataWritten(const GattWriteCallbackParams * */ void MicroBitAccelerometerService::accelerometerUpdate(MicroBitEvent e) { - accelerometerDataCharacteristicBuffer[0] = uBit.accelerometer.getX(); - accelerometerDataCharacteristicBuffer[1] = uBit.accelerometer.getY(); - accelerometerDataCharacteristicBuffer[2] = uBit.accelerometer.getZ(); + if (ble.getGapState().connected) + { + accelerometerDataCharacteristicBuffer[0] = uBit.accelerometer.getX(); + accelerometerDataCharacteristicBuffer[1] = uBit.accelerometer.getY(); + accelerometerDataCharacteristicBuffer[2] = uBit.accelerometer.getZ(); - ble.gattServer().notify(accelerometerDataCharacteristicHandle,(uint8_t *)accelerometerDataCharacteristicBuffer, sizeof(accelerometerDataCharacteristicBuffer)); + ble.gattServer().notify(accelerometerDataCharacteristicHandle,(uint8_t *)accelerometerDataCharacteristicBuffer, sizeof(accelerometerDataCharacteristicBuffer)); + } } const uint8_t MicroBitAccelerometerServiceUUID[] = { diff --git a/source/ble-services/MicroBitButtonService.cpp b/source/ble-services/MicroBitButtonService.cpp index a8e26aa..459b7ac 100644 --- a/source/ble-services/MicroBitButtonService.cpp +++ b/source/ble-services/MicroBitButtonService.cpp @@ -17,10 +17,10 @@ MicroBitButtonService::MicroBitButtonService(BLEDevice &_ble) : ble(_ble) { // Create the data structures that represent each of our characteristics in Soft Device. - GattCharacteristic buttonADataCharacteristic(MicroBitButtonAServiceDataUUID, (uint8_t *)buttonADataCharacteristicBuffer, 0, + GattCharacteristic buttonADataCharacteristic(MicroBitButtonAServiceDataUUID, (uint8_t *)&buttonADataCharacteristicBuffer, 0, sizeof(buttonADataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); - GattCharacteristic buttonBDataCharacteristic(MicroBitButtonBServiceDataUUID, (uint8_t *)buttonADataCharacteristicBuffer, 0, + GattCharacteristic buttonBDataCharacteristic(MicroBitButtonBServiceDataUUID, (uint8_t *)&buttonADataCharacteristicBuffer, 0, sizeof(buttonADataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); @@ -36,8 +36,8 @@ MicroBitButtonService::MicroBitButtonService(BLEDevice &_ble) : buttonADataCharacteristicHandle = buttonADataCharacteristic.getValueHandle(); buttonBDataCharacteristicHandle = buttonBDataCharacteristic.getValueHandle(); - ble.updateCharacteristicValue(buttonADataCharacteristicHandle, (const uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer)); - ble.updateCharacteristicValue(buttonBDataCharacteristicHandle, (const uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer)); + ble.gattServer().write(buttonADataCharacteristicHandle,(uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer)); + ble.gattServer().write(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer)); uBit.MessageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_EVT_ANY, this, &MicroBitButtonService::buttonAUpdate, MESSAGE_BUS_LISTENER_NONBLOCKING | MESSAGE_BUS_LISTENER_URGENT); uBit.MessageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_EVT_ANY, this, &MicroBitButtonService::buttonBUpdate, MESSAGE_BUS_LISTENER_NONBLOCKING | MESSAGE_BUS_LISTENER_URGENT); @@ -49,22 +49,25 @@ MicroBitButtonService::MicroBitButtonService(BLEDevice &_ble) : */ void MicroBitButtonService::buttonAUpdate(MicroBitEvent e) { - if (e.value == MICROBIT_BUTTON_EVT_UP) + if (ble.getGapState().connected) { - buttonADataCharacteristicBuffer = 0; - ble.gattServer().notify(buttonADataCharacteristicHandle,(uint8_t *)buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer)); - } + if (e.value == MICROBIT_BUTTON_EVT_UP) + { + buttonADataCharacteristicBuffer = 0; + ble.gattServer().notify(buttonADataCharacteristicHandle,(uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer)); + } - if (e.value == MICROBIT_BUTTON_EVT_DOWN) - { - buttonADataCharacteristicBuffer = 1; - ble.gattServer().notify(buttonADataCharacteristicHandle,(uint8_t *)buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer)); - } + if (e.value == MICROBIT_BUTTON_EVT_DOWN) + { + buttonADataCharacteristicBuffer = 1; + ble.gattServer().notify(buttonADataCharacteristicHandle,(uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer)); + } - if (e.value == MICROBIT_BUTTON_EVT_HOLD) - { - buttonADataCharacteristicBuffer = 2; - ble.gattServer().notify(buttonADataCharacteristicHandle,(uint8_t *)buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer)); + if (e.value == MICROBIT_BUTTON_EVT_HOLD) + { + buttonADataCharacteristicBuffer = 2; + ble.gattServer().notify(buttonADataCharacteristicHandle,(uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer)); + } } } @@ -73,22 +76,25 @@ void MicroBitButtonService::buttonAUpdate(MicroBitEvent e) */ void MicroBitButtonService::buttonBUpdate(MicroBitEvent e) { - if (e.value == MICROBIT_BUTTON_EVT_UP) + if (ble.getGapState().connected) { - buttonBDataCharacteristicBuffer = 0; - ble.gattServer().notify(buttonBDataCharacteristicHandle,(uint8_t *)buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer)); - } + if (e.value == MICROBIT_BUTTON_EVT_UP) + { + buttonBDataCharacteristicBuffer = 0; + ble.gattServer().notify(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer)); + } - if (e.value == MICROBIT_BUTTON_EVT_DOWN) - { - buttonBDataCharacteristicBuffer = 1; - ble.gattServer().notify(buttonBDataCharacteristicHandle,(uint8_t *)buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer)); - } + if (e.value == MICROBIT_BUTTON_EVT_DOWN) + { + buttonBDataCharacteristicBuffer = 1; + ble.gattServer().notify(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer)); + } - if (e.value == MICROBIT_BUTTON_EVT_HOLD) - { - buttonBDataCharacteristicBuffer = 2; - ble.gattServer().notify(buttonBDataCharacteristicHandle,(uint8_t *)buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer)); + if (e.value == MICROBIT_BUTTON_EVT_HOLD) + { + buttonBDataCharacteristicBuffer = 2; + ble.gattServer().notify(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer)); + } } } diff --git a/source/ble-services/MicroBitEventService.cpp b/source/ble-services/MicroBitEventService.cpp index 0963168..6719d98 100644 --- a/source/ble-services/MicroBitEventService.cpp +++ b/source/ble-services/MicroBitEventService.cpp @@ -21,21 +21,31 @@ MicroBitEventService::MicroBitEventService(BLEDevice &_ble) : GattCharacteristic clientEventCharacteristic(MicroBitEventServiceClientEventCharacteristicUUID, (uint8_t *)&clientEventBuffer, 0, sizeof(EventServiceEvent), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE); + GattCharacteristic clientRequirementsCharacteristic(MicroBitEventServiceClientRequirementsCharacteristicUUID, (uint8_t *)&clientRequirementsBuffer, 0, sizeof(EventServiceEvent), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE); + + microBitRequirementsCharacteristic = new GattCharacteristic(MicroBitEventServiceMicroBitRequirementsCharacteristicUUID, (uint8_t *)µBitRequirementsBuffer, 0, sizeof(EventServiceEvent), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); + + microBitRequirementsCharacteristic->setReadAuthorizationCallback(this, &MicroBitEventService::onRequirementsRead); + clientEventBuffer.type = 0x00; clientEventBuffer.reason = 0x00; - microBitEventBuffer.type = 0x00; - microBitEventBuffer.reason = 0x00; + microBitEventBuffer = microBitRequirementsBuffer = clientRequirementsBuffer = clientEventBuffer; + + messageBusListenerOffset = 0; - GattCharacteristic *characteristics[] = {µBitEventCharacteristic, &clientEventCharacteristic}; + GattCharacteristic *characteristics[] = {µBitEventCharacteristic, &clientEventCharacteristic, &clientRequirementsCharacteristic, microBitRequirementsCharacteristic}; GattService service(MicroBitEventServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *)); ble.addService(service); microBitEventCharacteristicHandle = microBitEventCharacteristic.getValueHandle(); clientEventCharacteristicHandle = clientEventCharacteristic.getValueHandle(); + clientRequirementsCharacteristicHandle = clientRequirementsCharacteristic.getValueHandle(); ble.onDataWritten(this, &MicroBitEventService::onDataWritten); + + uBit.addIdleComponent(this); } @@ -56,6 +66,19 @@ void MicroBitEventService::onDataWritten(const GattWriteCallbackParams *params) len-=4; e++; } + return; + } + + if (params->handle == clientRequirementsCharacteristicHandle) { + // Read and register for all the events given... + while (len >= 4) + { + uBit.MessageBus.listen(e->type, e->reason, this, &MicroBitEventService::onMicroBitEvent, MESSAGE_BUS_LISTENER_NONBLOCKING | MESSAGE_BUS_LISTENER_URGENT); + + len-=4; + e++; + } + return; } } @@ -70,19 +93,62 @@ void MicroBitEventService::onMicroBitEvent(MicroBitEvent evt) e->type = evt.source; e->reason = evt.value; - ble.updateCharacteristicValue(microBitEventCharacteristicHandle, (const uint8_t *)e, sizeof(EventServiceEvent)); + ble.gattServer().notify(microBitEventCharacteristicHandle, (const uint8_t *)e, sizeof(EventServiceEvent)); + } +} + +/** + * Periodic callback from MicroBit scheduler. + * If we're no longer connected, remove any registered Message Bus listeners. + */ +void MicroBitEventService::idleTick() +{ + if (!ble.getGapState().connected && messageBusListenerOffset >0) { + messageBusListenerOffset = 0; + uBit.MessageBus.ignore(MICROBIT_ID_ANY, MICROBIT_EVT_ANY, this, &MicroBitEventService::onMicroBitEvent); } } -const uint8_t MicroBitEventServiceUUID[] = { +/** + * read callback on data characteristic. + * reads all the pins marked as inputs, and updates the data stored in the BLE stack. + */ +void MicroBitEventService::onRequirementsRead(GattReadAuthCallbackParams *params) +{ + if (params->handle == microBitRequirementsCharacteristic->getValueHandle()) + { + // Walk through the lsit of message bus listeners. + // We send one at a time, and our client can keep reading from this characterisitic until we return an emtpy value. + MicroBitListener *l = uBit.MessageBus.elementAt(messageBusListenerOffset++); + + if (l != NULL) + { + microBitRequirementsBuffer.type = l->id; + microBitRequirementsBuffer.reason = l->value; + ble.gattServer().write(microBitRequirementsCharacteristic->getValueHandle(), (uint8_t *)µBitRequirementsBuffer, sizeof(EventServiceEvent)); + } else { + ble.gattServer().write(microBitRequirementsCharacteristic->getValueHandle(), (uint8_t *)µBitRequirementsBuffer, 0); + } + } +} + +const uint8_t MicroBitEventServiceUUID[] = { 0xe9,0x5d,0x93,0xaf,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8 }; -const uint8_t MicroBitEventServiceMicroBitEventCharacteristicUUID[] = { +const uint8_t MicroBitEventServiceMicroBitEventCharacteristicUUID[] = { 0xe9,0x5d,0x97,0x75,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8 }; -const uint8_t MicroBitEventServiceClientEventCharacteristicUUID[] = { +const uint8_t MicroBitEventServiceClientEventCharacteristicUUID[] = { 0xe9,0x5d,0x54,0x04,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8 }; +const uint8_t MicroBitEventServiceMicroBitRequirementsCharacteristicUUID[] = { + 0xe9,0x5d,0xb8,0x4c,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8 +}; + +const uint8_t MicroBitEventServiceClientRequirementsCharacteristicUUID[] = { + 0xe9,0x5d,0x23,0xc4,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8 +}; + diff --git a/source/ble-services/MicroBitIOPinService.cpp b/source/ble-services/MicroBitIOPinService.cpp index d178641..38319c7 100644 --- a/source/ble-services/MicroBitIOPinService.cpp +++ b/source/ble-services/MicroBitIOPinService.cpp @@ -23,7 +23,7 @@ MicroBitIOPinService::MicroBitIOPinService(BLEDevice &_ble) : GattCharacteristic ioPinServiceIOCharacteristic(MicroBitIOPinServiceIOConfigurationUUID, (uint8_t *)&ioPinServiceIOCharacteristicBuffer, 0, sizeof(ioPinServiceIOCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE); // Create the Data characteristic, that allows the actual read and write operations. - ioPinServiceDataCharacteristic = new GattCharacteristic(MicroBitIOPinServiceDataUUID, (uint8_t *)&ioPinServiceDataCharacteristicBuffer, 0, sizeof(ioPinServiceDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); + ioPinServiceDataCharacteristic = new GattCharacteristic(MicroBitIOPinServiceDataUUID, (uint8_t *)ioPinServiceDataCharacteristicBuffer, 0, sizeof(ioPinServiceDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); ioPinServiceDataCharacteristic->setReadAuthorizationCallback(this, &MicroBitIOPinService::onDataRead); @@ -39,10 +39,11 @@ MicroBitIOPinService::MicroBitIOPinService(BLEDevice &_ble) : ioPinServiceADCharacteristicHandle = ioPinServiceADCharacteristic.getValueHandle(); ioPinServiceIOCharacteristicHandle = ioPinServiceIOCharacteristic.getValueHandle(); - ble.updateCharacteristicValue(ioPinServiceADCharacteristicHandle, (const uint8_t *)&ioPinServiceADCharacteristicBuffer, sizeof(ioPinServiceADCharacteristicBuffer)); - ble.updateCharacteristicValue(ioPinServiceIOCharacteristicHandle, (const uint8_t *)&ioPinServiceIOCharacteristicBuffer, sizeof(ioPinServiceIOCharacteristicBuffer)); + ble.gattServer().write(ioPinServiceADCharacteristicHandle, (const uint8_t *)&ioPinServiceADCharacteristicBuffer, sizeof(ioPinServiceADCharacteristicBuffer)); + ble.gattServer().write(ioPinServiceIOCharacteristicHandle, (const uint8_t *)&ioPinServiceIOCharacteristicBuffer, sizeof(ioPinServiceIOCharacteristicBuffer)); ble.onDataWritten(this, &MicroBitIOPinService::onDataWritten); + uBit.addIdleComponent(this); } /** @@ -75,7 +76,7 @@ int MicroBitIOPinService::isAnalog(int i) */ int MicroBitIOPinService::isInput(int i) { - return ((ioPinServiceIOCharacteristicBuffer & (1 << i)) == 0); + return ((ioPinServiceIOCharacteristicBuffer & (1 << i)) != 0); } /** @@ -86,7 +87,7 @@ int MicroBitIOPinService::isInput(int i) */ int MicroBitIOPinService::isOutput(int i) { - return ((ioPinServiceIOCharacteristicBuffer & (1 << i)) != 0); + return ((ioPinServiceIOCharacteristicBuffer & (1 << i)) == 0); } /** @@ -101,7 +102,7 @@ void MicroBitIOPinService::onDataWritten(const GattWriteCallbackParams *params) // Our IO configuration may be changing... read the new value, and push it back into the BLE stack. ioPinServiceIOCharacteristicBuffer = *value; - ble.updateCharacteristicValue(ioPinServiceIOCharacteristicHandle, (const uint8_t *)&ioPinServiceIOCharacteristicBuffer, sizeof(ioPinServiceIOCharacteristicBuffer)); + ble.gattServer().write(ioPinServiceIOCharacteristicHandle, (const uint8_t *)&ioPinServiceIOCharacteristicBuffer, sizeof(ioPinServiceIOCharacteristicBuffer)); // Also, drop any selected pins into input mode, so we can pick up changes later for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++) @@ -121,7 +122,7 @@ void MicroBitIOPinService::onDataWritten(const GattWriteCallbackParams *params) // Our IO configuration may be changing... read the new value, and push it back into the BLE stack. ioPinServiceADCharacteristicBuffer = *value; - ble.updateCharacteristicValue(ioPinServiceADCharacteristicHandle, (const uint8_t *)&ioPinServiceADCharacteristicBuffer, sizeof(ioPinServiceADCharacteristicBuffer)); + ble.gattServer().write(ioPinServiceADCharacteristicHandle, (const uint8_t *)&ioPinServiceADCharacteristicBuffer, sizeof(ioPinServiceADCharacteristicBuffer)); // Also, drop any selected pins into input mode, so we can pick up changes later for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++) @@ -173,7 +174,7 @@ void MicroBitIOPinService::onDataRead(GattReadAuthCallbackParams *params) { if (isInput(i)) { - uint8_t value; + uint8_t value; if (isDigital(i)) value = MicroBitIOPins[i]->getDigitalValue(); @@ -193,7 +194,7 @@ void MicroBitIOPinService::onDataRead(GattReadAuthCallbackParams *params) // If there's any data, issue a BLE notification. if (pairs > 0) - ble.updateCharacteristicValue(ioPinServiceDataCharacteristic->getValueHandle(), (uint8_t *)&ioPinServiceDataCharacteristic, pairs * sizeof(IOData)); + ble.gattServer().notify(ioPinServiceDataCharacteristic->getValueHandle(), (uint8_t *)ioPinServiceDataCharacteristicBuffer, pairs * sizeof(IOData)); } } @@ -215,7 +216,7 @@ void MicroBitIOPinService::idleTick() { if (isInput(i)) { - uint8_t value; + uint8_t value; if (isDigital(i)) value = MicroBitIOPins[i]->getDigitalValue(); @@ -240,7 +241,7 @@ void MicroBitIOPinService::idleTick() // If there were any changes, issue a BLE notification. if (pairs > 0) - ble.gattServer().notify(ioPinServiceDataCharacteristic->getValueHandle(), (uint8_t *)&ioPinServiceDataCharacteristic, pairs * sizeof(IOData)); + ble.gattServer().notify(ioPinServiceDataCharacteristic->getValueHandle(), (uint8_t *)ioPinServiceDataCharacteristicBuffer, pairs * sizeof(IOData)); } const uint8_t MicroBitIOPinServiceUUID[] = { diff --git a/source/ble-services/MicroBitLEDService.cpp b/source/ble-services/MicroBitLEDService.cpp index ae8c301..99538ae 100644 --- a/source/ble-services/MicroBitLEDService.cpp +++ b/source/ble-services/MicroBitLEDService.cpp @@ -32,7 +32,6 @@ MicroBitLEDService::MicroBitLEDService(BLEDevice &_ble) : matrixCharacteristic.setReadAuthorizationCallback(this, &MicroBitLEDService::onDataRead); - GattCharacteristic *characteristics[] = {&matrixCharacteristic, &textCharacteristic, &scrollingSpeedCharacteristic}; GattService service(MicroBitLEDServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *)); @@ -42,12 +41,10 @@ MicroBitLEDService::MicroBitLEDService(BLEDevice &_ble) : textCharacteristicHandle = textCharacteristic.getValueHandle(); scrollingSpeedCharacteristicHandle = scrollingSpeedCharacteristic.getValueHandle(); - ble.updateCharacteristicValue(scrollingSpeedCharacteristicHandle, (const uint8_t *)&scrollingSpeedCharacteristicBuffer, sizeof(scrollingSpeedCharacteristicBuffer)); - ble.updateCharacteristicValue(matrixCharacteristicHandle, (const uint8_t *)&matrixCharacteristicBuffer, sizeof(matrixCharacteristicBuffer)); + ble.gattServer().write(scrollingSpeedCharacteristicHandle, (const uint8_t *)&scrollingSpeedCharacteristicBuffer, sizeof(scrollingSpeedCharacteristicBuffer)); + ble.gattServer().write(matrixCharacteristicHandle, (const uint8_t *)&matrixCharacteristicBuffer, sizeof(matrixCharacteristicBuffer)); ble.onDataWritten(this, &MicroBitLEDService::onDataWritten); - - } @@ -111,7 +108,7 @@ void MicroBitLEDService::onDataRead(GattReadAuthCallbackParams *params) } } - ble.updateCharacteristicValue(matrixCharacteristicHandle, (const uint8_t *)&matrixCharacteristicBuffer, sizeof(matrixCharacteristicBuffer)); + ble.gattServer().write(matrixCharacteristicHandle, (const uint8_t *)&matrixCharacteristicBuffer, sizeof(matrixCharacteristicBuffer)); } } diff --git a/source/ble-services/MicroBitMagnetometerService.cpp b/source/ble-services/MicroBitMagnetometerService.cpp index 268e37c..b4d4b47 100644 --- a/source/ble-services/MicroBitMagnetometerService.cpp +++ b/source/ble-services/MicroBitMagnetometerService.cpp @@ -20,10 +20,10 @@ MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble) : GattCharacteristic magnetometerDataCharacteristic(MicroBitMagnetometerServiceDataUUID, (uint8_t *)magnetometerDataCharacteristicBuffer, 0, sizeof(magnetometerDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); - GattCharacteristic magnetometerBearingCharacteristic(MicroBitMagnetometerServiceBearingUUID, (uint8_t *)magnetometerBearingCharacteristicBuffer, 0, + GattCharacteristic magnetometerBearingCharacteristic(MicroBitMagnetometerServiceBearingUUID, (uint8_t *)&magnetometerBearingCharacteristicBuffer, 0, sizeof(magnetometerBearingCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); - GattCharacteristic magnetometerPeriodCharacteristic(MicroBitMagnetometerServicePeriodUUID, (uint8_t *)magnetometerPeriodCharacteristicBuffer, 0, + GattCharacteristic magnetometerPeriodCharacteristic(MicroBitMagnetometerServicePeriodUUID, (uint8_t *)&magnetometerPeriodCharacteristicBuffer, 0, sizeof(magnetometerPeriodCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE); @@ -32,7 +32,7 @@ MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble) : magnetometerDataCharacteristicBuffer[1] = 0; magnetometerDataCharacteristicBuffer[2] = 0; magnetometerBearingCharacteristicBuffer = 0; - magnetometerPeriodCharacteristicBuffer = 0; + magnetometerPeriodCharacteristicBuffer = uBit.compass.getPeriod(); GattCharacteristic *characteristics[] = {&magnetometerDataCharacteristic, &magnetometerBearingCharacteristic, &magnetometerPeriodCharacteristic}; GattService service(MicroBitMagnetometerServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *)); @@ -43,12 +43,14 @@ MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble) : magnetometerBearingCharacteristicHandle = magnetometerBearingCharacteristic.getValueHandle(); magnetometerPeriodCharacteristicHandle = magnetometerPeriodCharacteristic.getValueHandle(); - ble.updateCharacteristicValue(magnetometerDataCharacteristicHandle, (const uint8_t *)&magnetometerDataCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer)); - ble.updateCharacteristicValue(magnetometerBearingCharacteristicHandle, (const uint8_t *)&magnetometerDataCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer)); - ble.updateCharacteristicValue(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer)); + ble.gattServer().notify(magnetometerDataCharacteristicHandle,(uint8_t *)magnetometerDataCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer)); + ble.gattServer().notify(magnetometerBearingCharacteristicHandle,(uint8_t *)&magnetometerBearingCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer)); + ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer)); ble.onDataWritten(this, &MicroBitMagnetometerService::onDataWritten); uBit.MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_DATA_UPDATE, this, &MicroBitMagnetometerService::magnetometerUpdate, MESSAGE_BUS_LISTENER_NONBLOCKING | MESSAGE_BUS_LISTENER_URGENT); + + uBit.MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CONFIG_NEEDED, this, &MicroBitMagnetometerService::samplePeriodUpdateNeeded); } /** @@ -58,8 +60,8 @@ void MicroBitMagnetometerService::onDataWritten(const GattWriteCallbackParams *p { if (params->handle == magnetometerPeriodCharacteristicHandle && params->len >= sizeof(magnetometerPeriodCharacteristicBuffer)) { - magnetometerPeriodCharacteristicBuffer = *((uint8_t *)params->data); - uBit.compass.setPeriod(magnetometerPeriodCharacteristicBuffer); + magnetometerPeriodCharacteristicBuffer = *((uint16_t *)params->data); + MicroBitEvent evt(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CONFIG_NEEDED); } } @@ -68,13 +70,37 @@ void MicroBitMagnetometerService::onDataWritten(const GattWriteCallbackParams *p */ void MicroBitMagnetometerService::magnetometerUpdate(MicroBitEvent e) { - magnetometerDataCharacteristicBuffer[0] = uBit.compass.getX(); - magnetometerDataCharacteristicBuffer[1] = uBit.compass.getY(); - magnetometerDataCharacteristicBuffer[2] = uBit.compass.getZ(); - magnetometerBearingCharacteristicBuffer = (uint16_t) uBit.compass.heading(); + if (ble.getGapState().connected) + { + magnetometerDataCharacteristicBuffer[0] = uBit.compass.getX(); + magnetometerDataCharacteristicBuffer[1] = uBit.compass.getY(); + magnetometerDataCharacteristicBuffer[2] = uBit.compass.getZ(); + magnetometerBearingCharacteristicBuffer = (uint16_t) uBit.compass.heading(); + magnetometerPeriodCharacteristicBuffer = uBit.compass.getPeriod(); + + ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer)); + ble.gattServer().notify(magnetometerDataCharacteristicHandle,(uint8_t *)magnetometerDataCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer)); + ble.gattServer().notify(magnetometerBearingCharacteristicHandle,(uint8_t *)&magnetometerBearingCharacteristicBuffer, sizeof(magnetometerBearingCharacteristicBuffer)); + } +} + +/** + * Sample Period Change Needed callback. + * Reconfiguring the magnetometer can to a REALLY long time (sometimes even seconds to complete) + * So we do this in the background when necessary, through this event handler. + */ +void MicroBitMagnetometerService::samplePeriodUpdateNeeded(MicroBitEvent e) +{ + // Reconfigure the compass. This might take a while... + uBit.compass.setPeriod(magnetometerPeriodCharacteristicBuffer); + + // The compass will choose the nearest sample period to that we've specified. + // Read the ACTUAL sample period back. + magnetometerPeriodCharacteristicBuffer = uBit.compass.getPeriod(); + + // Ensure this is reflected in our BLE connection. + ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer)); - ble.gattServer().notify(magnetometerDataCharacteristicHandle,(uint8_t *)magnetometerDataCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer)); - ble.gattServer().notify(magnetometerDataCharacteristicHandle,(uint8_t *)magnetometerBearingCharacteristicBuffer, sizeof(magnetometerDataCharacteristicBuffer)); } const uint8_t MicroBitMagnetometerServiceUUID[] = { @@ -89,9 +115,8 @@ const uint8_t MicroBitMagnetometerServicePeriodUUID[] = { 0xe9,0x5d,0x38,0x6c,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8 }; -// TODO: Need an assigned UUID from martin here.. const uint8_t MicroBitMagnetometerServiceBearingUUID[] = { - 0xe9,0x5d,0xde,0xad,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8 + 0xe9,0x5d,0x97,0x15,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8 }; diff --git a/source/ble-services/MicroBitTemperatureService.cpp b/source/ble-services/MicroBitTemperatureService.cpp index 6012696..014737f 100644 --- a/source/ble-services/MicroBitTemperatureService.cpp +++ b/source/ble-services/MicroBitTemperatureService.cpp @@ -17,7 +17,7 @@ MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble) : ble(_ble) { // Create the data structures that represent each of our characteristics in Soft Device. - GattCharacteristic temperatureDataCharacteristic(MicroBitTemperatureServiceDataUUID, (uint8_t *)temperatureDataCharacteristicBuffer, 0, + GattCharacteristic temperatureDataCharacteristic(MicroBitTemperatureServiceDataUUID, (uint8_t *)&temperatureDataCharacteristicBuffer, 0, sizeof(temperatureDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY); // Initialise our characteristic values. @@ -29,9 +29,9 @@ MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble) : ble.addService(service); temperatureDataCharacteristicHandle = temperatureDataCharacteristic.getValueHandle(); - ble.updateCharacteristicValue(temperatureDataCharacteristicHandle, (const uint8_t *)&temperatureDataCharacteristicBuffer, sizeof(temperatureDataCharacteristicBuffer)); + ble.gattServer().write(temperatureDataCharacteristicHandle,(uint8_t *)&temperatureDataCharacteristicBuffer, sizeof(temperatureDataCharacteristicBuffer)); - uBit.MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_TEMPERATURE_UPDATE, this, &MicroBitTemperatureService::temperatureUpdate, MESSAGE_BUS_LISTENER_NONBLOCKING | MESSAGE_BUS_LISTENER_URGENT); + uBit.MessageBus.listen(MICROBIT_ID_THERMOMETER, MICROBIT_THERMOMETER_EVT_UPDATE, this, &MicroBitTemperatureService::temperatureUpdate, MESSAGE_BUS_LISTENER_NONBLOCKING | MESSAGE_BUS_LISTENER_URGENT); } /** @@ -39,8 +39,11 @@ MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble) : */ void MicroBitTemperatureService::temperatureUpdate(MicroBitEvent e) { - temperatureDataCharacteristicBuffer = uBit.compass.getTemperature(); - ble.gattServer().notify(temperatureDataCharacteristicHandle,(uint8_t *)temperatureDataCharacteristicBuffer, sizeof(temperatureDataCharacteristicBuffer)); + if (ble.getGapState().connected) + { + temperatureDataCharacteristicBuffer = uBit.thermometer.getTemperature(); + ble.gattServer().notify(temperatureDataCharacteristicHandle,(uint8_t *)&temperatureDataCharacteristicBuffer, sizeof(temperatureDataCharacteristicBuffer)); + } } const uint8_t MicroBitTemperatureServiceUUID[] = {