microbit: BLE Profile Beta 1

First functionally complete BLE profile, matching BLE speicfication v1.6.
More specifically, the following services are now functional:

  - AccelerometerService
  - MeganetometerService
  - EventService
  - TemperatureServide
  - IOPinService
  - DFUService
  - ButtonService
  - LEDService

Also, updates to underlying device drivers to enable greater configurability:

  - MicroBitCompass now supports variable sample rates and temperature sensing
  - MicroBitAccelerometer now supports variable sample rates and ranges
  - MicroBitThermometer introduced
  - MicroBitMessageBus adapted to permit enumeration and block removal of listeners

Finally, MicroBit DFU Service has been changed to the new UUIDs specificed in v1.6 of BLE spec.
master
Joe Finney 8 years ago
parent 4314b68643
commit 18236810a3

@ -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;

@ -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;

@ -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

@ -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

@ -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

@ -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;

@ -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;
};

@ -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;

@ -205,6 +205,13 @@ class MicroBitMessageBus : public MicroBitComponent
template <typename T>
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.
*/

@ -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

@ -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"

@ -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,

@ -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);

@ -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
};

@ -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.

@ -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;
// delete the listener.
MicroBitListener *t = l;
l = l->next;
delete t;
removed++;
continue;
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 t;
removed++;
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;
}

@ -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);
}

@ -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[] = {

@ -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_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_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_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)
{
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_HOLD)
if (ble.getGapState().connected)
{
buttonBDataCharacteristicBuffer = 2;
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_HOLD)
{
buttonBDataCharacteristicBuffer = 2;
ble.gattServer().notify(buttonBDataCharacteristicHandle,(uint8_t *)&buttonBDataCharacteristicBuffer, sizeof(buttonBDataCharacteristicBuffer));
}
}
}

@ -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 *)&microBitRequirementsBuffer, 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[] = {&microBitEventCharacteristic, &clientEventCharacteristic};
GattCharacteristic *characteristics[] = {&microBitEventCharacteristic, &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);
}
}
/**
* 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 *)&microBitRequirementsBuffer, sizeof(EventServiceEvent));
} else {
ble.gattServer().write(microBitRequirementsCharacteristic->getValueHandle(), (uint8_t *)&microBitRequirementsBuffer, 0);
}
}
}
const uint8_t MicroBitEventServiceUUID[] = {
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
};

@ -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[] = {

@ -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));
}
}

@ -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.