Merge branch 'ble-profile' of https://github.com/lancaster-university/microbit-dal into ble-profile
This commit is contained in:
commit
7459213d10
|
@ -22,6 +22,7 @@
|
|||
#include "MicroBitPin.h"
|
||||
#include "MicroBitCompass.h"
|
||||
#include "MicroBitAccelerometer.h"
|
||||
#include "MicroBitThermometer.h"
|
||||
#include "MicroBitMultiButton.h"
|
||||
|
||||
#include "MicroBitSerial.h"
|
||||
|
@ -36,6 +37,11 @@
|
|||
#include "MicroBitDFUService.h"
|
||||
#include "MicroBitEventService.h"
|
||||
#include "MicroBitLEDService.h"
|
||||
#include "MicroBitAccelerometerService.h"
|
||||
#include "MicroBitMagnetometerService.h"
|
||||
#include "MicroBitButtonService.h"
|
||||
#include "MicroBitIOPinService.h"
|
||||
#include "MicroBitTemperatureService.h"
|
||||
#include "ExternalEvents.h"
|
||||
|
||||
// MicroBit::flags values
|
||||
|
@ -100,15 +106,21 @@ class MicroBit
|
|||
MicroBitMultiButton buttonAB;
|
||||
MicroBitAccelerometer accelerometer;
|
||||
MicroBitCompass compass;
|
||||
MicroBitThermometer thermometer;
|
||||
|
||||
//An object of available IO pins on the device
|
||||
MicroBitIO io;
|
||||
|
||||
// Bluetooth related member variables.
|
||||
BLEDevice *ble;
|
||||
MicroBitDFUService *ble_firmware_update_service;
|
||||
MicroBitEventService *ble_event_service;
|
||||
MicroBitLEDService *ble_led_service;
|
||||
BLEDevice *ble;
|
||||
MicroBitDFUService *ble_firmware_update_service;
|
||||
MicroBitEventService *ble_event_service;
|
||||
MicroBitLEDService *ble_led_service;
|
||||
MicroBitAccelerometerService *ble_accelerometer_service;
|
||||
MicroBitMagnetometerService *ble_magnetometer_service;
|
||||
MicroBitButtonService *ble_button_service;
|
||||
MicroBitIOPinService *ble_io_pin_service;
|
||||
MicroBitTemperatureService *ble_temperature_service;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
|
|
@ -36,6 +36,10 @@
|
|||
#define MMA8653_SAMPLE_RANGES 3
|
||||
#define MMA8653_SAMPLE_RATES 8
|
||||
|
||||
/*
|
||||
* Accelerometer events
|
||||
*/
|
||||
#define MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE 1
|
||||
|
||||
struct MMA8653Sample
|
||||
{
|
||||
|
|
|
@ -24,19 +24,25 @@ class MicroBitAccelerometerService
|
|||
*/
|
||||
MicroBitAccelerometerService(BLEDevice &_ble);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Callback. Invoked when any of our attributes are written via BLE.
|
||||
*/
|
||||
void onDataWritten(const GattWriteCallbackParams *params);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Accelerometer update callback
|
||||
*/
|
||||
void accelerometerUpdate(MicroBitEvent e);
|
||||
|
||||
// Bluetooth stack we're running on.
|
||||
BLEDevice &ble;
|
||||
|
||||
// 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;
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef MICROBIT_BUTTON_SERVICE_H
|
||||
#define MICROBIT_BUTTON_SERVICE_H
|
||||
|
||||
#include "MicroBit.h"
|
||||
|
||||
// UUIDs for our service and characteristics
|
||||
extern const uint8_t MicroBitButtonServiceUUID[];
|
||||
extern const uint8_t MicroBitButtonAServiceDataUUID[];
|
||||
extern const uint8_t MicroBitButtonBServiceDataUUID[];
|
||||
|
||||
|
||||
/**
|
||||
* Class definition for a MicroBit BLE Button Service.
|
||||
* Provides access to live button data via BLE, and provides basic configuration options.
|
||||
*/
|
||||
class MicroBitButtonService
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a representation of the ButtonService
|
||||
* @param _ble The instance of a BLE device that we're running on.
|
||||
*/
|
||||
MicroBitButtonService(BLEDevice &_ble);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Button A update callback
|
||||
*/
|
||||
void buttonAUpdate(MicroBitEvent e);
|
||||
|
||||
/**
|
||||
* Button B update callback
|
||||
*/
|
||||
void buttonBUpdate(MicroBitEvent e);
|
||||
|
||||
// Bluetooth stack we're running on.
|
||||
BLEDevice &ble;
|
||||
|
||||
// memory for our 8 bit control characteristics.
|
||||
uint8_t buttonADataCharacteristicBuffer;
|
||||
uint8_t buttonBDataCharacteristicBuffer;
|
||||
|
||||
// Handles to access each characteristic when they are held by Soft Device.
|
||||
GattAttribute::Handle_t buttonADataCharacteristicHandle;
|
||||
GattAttribute::Handle_t buttonBDataCharacteristicHandle;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -36,12 +36,27 @@
|
|||
#define MAG_CTRL_REG1 0x10
|
||||
#define MAG_CTRL_REG2 0x11
|
||||
|
||||
/**
|
||||
* Configuration options
|
||||
*/
|
||||
struct MAG3110SampleRateConfig
|
||||
{
|
||||
uint32_t sample_period;
|
||||
uint8_t ctrl_reg1;
|
||||
};
|
||||
|
||||
extern const MAG3110SampleRateConfig MAG3110SampleRate[];
|
||||
|
||||
#define MAG3110_SAMPLE_RATES 11
|
||||
|
||||
/*
|
||||
* Compass events
|
||||
*/
|
||||
#define MICROBIT_COMPASS_EVT_CAL_REQUIRED 1
|
||||
#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_CONFIG_NEEDED 5
|
||||
|
||||
/*
|
||||
* Status Bits
|
||||
|
@ -85,17 +100,17 @@ class MicroBitCompass : public MicroBitComponent
|
|||
* Used to track asynchronous events in the event bus.
|
||||
*/
|
||||
|
||||
uint16_t address; // I2C address of the magnetmometer.
|
||||
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 eventStartTime; // used to store the current system clock when async calibration has started
|
||||
|
||||
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.
|
||||
|
@ -116,7 +131,29 @@ class MicroBitCompass : public MicroBitComponent
|
|||
* @endcode
|
||||
*/
|
||||
MicroBitCompass(uint16_t id, uint16_t address);
|
||||
|
||||
|
||||
/**
|
||||
* Configures the compass for the sample rate defined
|
||||
* in this object. The nearest values are chosen to those defined
|
||||
* that are supported by the hardware. The instance variables are then
|
||||
* updated to reflect reality.
|
||||
*/
|
||||
void configure();
|
||||
|
||||
/**
|
||||
* 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
|
||||
* nearest lower rate is chosen.
|
||||
* @param period the requested time between samples, in milliseconds.
|
||||
*/
|
||||
void setPeriod(int period);
|
||||
|
||||
/**
|
||||
* Reads the currently configured sample rate of the compass.
|
||||
* @return The time between samples, in milliseconds.
|
||||
*/
|
||||
int getPeriod();
|
||||
|
||||
/**
|
||||
* Gets the current heading of the device, relative to magnetic north.
|
||||
* @return the current heading, in degrees.
|
||||
|
@ -172,6 +209,12 @@ class MicroBitCompass : public MicroBitComponent
|
|||
*/
|
||||
int getZ();
|
||||
|
||||
/**
|
||||
* Reads the currently die temperature of the compass.
|
||||
* @return The temperature, in degrees celsius.
|
||||
*/
|
||||
int readTemperature();
|
||||
|
||||
/**
|
||||
* Perform the asynchronous calibration of the compass.
|
||||
* This will fire MICROBIT_COMPASS_EVT_CAL_START and MICROBIT_COMPASS_EVT_CAL_END when finished.
|
||||
|
@ -257,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,9 +157,41 @@
|
|||
// 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 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 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 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 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 0
|
||||
#endif
|
||||
|
||||
// Defines the maximum length strong that can be written to the
|
||||
// display over BLE.
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
#ifndef MICROBIT_IO_PIN_SERVICE_H
|
||||
#define MICROBIT_IO_PIN_SERVICE_H
|
||||
|
||||
#include "MicroBit.h"
|
||||
|
||||
#define MICROBIT_IO_PIN_SERVICE_PINCOUNT 20
|
||||
#define MICROBIT_IO_PIN_SERVICE_DATA_SIZE 10
|
||||
|
||||
// UUIDs for our service and characteristics
|
||||
extern const uint8_t MicroBitIOPinServiceUUID[];
|
||||
extern const uint8_t MicroBitIOPinServiceADConfigurationUUID[];
|
||||
extern const uint8_t MicroBitIOPinServiceIOConfigurationUUID[];
|
||||
extern const uint8_t MicroBitIOPinServiceDataUUID[];
|
||||
extern MicroBitPin * const MicroBitIOPins[];
|
||||
|
||||
/**
|
||||
* Name value pair definition, as used to read abd write pin values over BLE.
|
||||
*/
|
||||
struct IOData
|
||||
{
|
||||
uint8_t pin;
|
||||
uint8_t value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Class definition for a MicroBit BLE IOPin Service.
|
||||
* Provides access to live ioPin data via BLE, and provides basic configuration options.
|
||||
*/
|
||||
class MicroBitIOPinService : public MicroBitComponent
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a representation of the IOPinService
|
||||
* @param _ble The instance of a BLE device that we're running on.
|
||||
*/
|
||||
MicroBitIOPinService(BLEDevice &_ble);
|
||||
|
||||
/**
|
||||
* periodic callback from MicroBit scheduler.
|
||||
* Check if any of the pins we're watching need updating. Apply a BLE NOTIFY if so...
|
||||
*/
|
||||
virtual void idleTick();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Callback. Invoked when any of our attributes are written via BLE.
|
||||
*/
|
||||
void onDataWritten(const GattWriteCallbackParams *params);
|
||||
|
||||
/**
|
||||
* Callback. invoked when the BLE data characteristic is read.
|
||||
* reads all the pins marked as inputs, and updates the data stored in the BLE stack.
|
||||
*/
|
||||
void onDataRead(GattReadAuthCallbackParams *params);
|
||||
|
||||
/**
|
||||
* Determines if the given pin was configured as a digital pin by the BLE ADPinConfigurationCharacterisitic.
|
||||
*
|
||||
* @param pin the enumeration of the pin to test
|
||||
* @return 1 if this pin is configured as a digital value, 0 otherwise
|
||||
*/
|
||||
int isDigital(int i);
|
||||
|
||||
/**
|
||||
* Determines if the given pin was configured as an analog pin by the BLE ADPinConfigurationCharacterisitic.
|
||||
*
|
||||
* @param pin the enumeration of the pin to test
|
||||
* @return 1 if this pin is configured as a analog value, 0 otherwise
|
||||
*/
|
||||
int isAnalog(int i);
|
||||
|
||||
/**
|
||||
* Determines if the given pin was configured as an input by the BLE IOPinConfigurationCharacterisitic.
|
||||
*
|
||||
* @param pin the enumeration of the pin to test
|
||||
* @return 1 if this pin is configured as an input, 0 otherwise
|
||||
*/
|
||||
int isInput(int i);
|
||||
|
||||
/**
|
||||
* Determines if the given pin was configured as output by the BLE IOPinConfigurationCharacterisitic.
|
||||
*
|
||||
* @param pin the enumeration of the pin to test
|
||||
* @return 1 if this pin is configured as an output, 0 otherwise
|
||||
*/
|
||||
int isOutput(int i);
|
||||
|
||||
|
||||
// Bluetooth stack we're running on.
|
||||
BLEDevice &ble;
|
||||
|
||||
// memory for our 8 bit control characteristics.
|
||||
uint32_t ioPinServiceADCharacteristicBuffer;
|
||||
uint32_t ioPinServiceIOCharacteristicBuffer;
|
||||
IOData ioPinServiceDataCharacteristicBuffer[MICROBIT_IO_PIN_SERVICE_DATA_SIZE];
|
||||
|
||||
// Historic information about our pin data data.
|
||||
uint8_t ioPinServiceIOData[MICROBIT_IO_PIN_SERVICE_PINCOUNT];
|
||||
|
||||
// Handles to access each characteristic when they are held by Soft Device.
|
||||
GattAttribute::Handle_t ioPinServiceADCharacteristicHandle;
|
||||
GattAttribute::Handle_t ioPinServiceIOCharacteristicHandle;
|
||||
GattCharacteristic *ioPinServiceDataCharacteristic;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
#include "MicroBitEvent.h"
|
||||
#include "MemberFunctionCallback.h"
|
||||
|
||||
// MessageBusListener flags...
|
||||
// MicroBitListener flags...
|
||||
#define MESSAGE_BUS_LISTENER_PARAMETERISED 0x0001
|
||||
#define MESSAGE_BUS_LISTENER_METHOD 0x0002
|
||||
#define MESSAGE_BUS_LISTENER_BUSY 0x0004
|
||||
|
@ -13,6 +13,7 @@
|
|||
#define MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY 0x0010
|
||||
#define MESSAGE_BUS_LISTENER_DROP_IF_BUSY 0x0020
|
||||
#define MESSAGE_BUS_LISTENER_NONBLOCKING 0x0040
|
||||
#define MESSAGE_BUS_LISTENER_URGENT 0x0080
|
||||
|
||||
struct MicroBitListener
|
||||
{
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef MICROBIT_MAGNETOMETER_SERVICE_H
|
||||
#define MICROBIT_MAGNETOMETER_SERVICE_H
|
||||
|
||||
#include "MicroBit.h"
|
||||
|
||||
// UUIDs for our service and characteristics
|
||||
extern const uint8_t MicroBitMagnetometerServiceUUID[];
|
||||
extern const uint8_t MicroBitMagnetometerServiceDataUUID[];
|
||||
extern const uint8_t MicroBitMagnetometerServiceBearingUUID[];
|
||||
extern const uint8_t MicroBitMagnetometerServicePeriodUUID[];
|
||||
|
||||
|
||||
/**
|
||||
* Class definition for a MicroBit BLE Magnetometer Service.
|
||||
* Provides access to live magnetometer data via BLE, and provides basic configuration options.
|
||||
*/
|
||||
class MicroBitMagnetometerService
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a representation of the MagnetometerService
|
||||
* @param _ble The instance of a BLE device that we're running on.
|
||||
*/
|
||||
MicroBitMagnetometerService(BLEDevice &_ble);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Callback. Invoked when any of our attributes are written via BLE.
|
||||
*/
|
||||
void onDataWritten(const GattWriteCallbackParams *params);
|
||||
|
||||
/**
|
||||
* Magnetometer update callback
|
||||
*/
|
||||
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;
|
||||
|
||||
// memory for our 8 bit control characteristics.
|
||||
int16_t magnetometerDataCharacteristicBuffer[3];
|
||||
uint16_t magnetometerBearingCharacteristicBuffer;
|
||||
uint16_t magnetometerPeriodCharacteristicBuffer;
|
||||
|
||||
// Handles to access each characteristic when they are held by Soft Device.
|
||||
GattAttribute::Handle_t magnetometerDataCharacteristicHandle;
|
||||
GattAttribute::Handle_t magnetometerBearingCharacteristicHandle;
|
||||
GattAttribute::Handle_t magnetometerPeriodCharacteristicHandle;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -64,8 +64,10 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
* or the constructors provided by MicroBitEvent.
|
||||
*
|
||||
* @param evt The event to send.
|
||||
* @param mask The type of listeners to process (optional). Matches MicroBitListener flags. If not defined, all standard listeners will be processed.
|
||||
* @return The 1 if all matching listeners were processed, 0 if further processing is required.
|
||||
*/
|
||||
void process(MicroBitEvent evt);
|
||||
int process(MicroBitEvent &evt, uint32_t mask = MESSAGE_BUS_LISTENER_REENTRANT | MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY | MESSAGE_BUS_LISTENER_DROP_IF_BUSY | MESSAGE_BUS_LISTENER_NONBLOCKING);
|
||||
|
||||
/**
|
||||
* Register a listener function.
|
||||
|
@ -203,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.
|
||||
*/
|
||||
|
|
|
@ -131,6 +131,30 @@ class MicroBitPin : public MicroBitComponent
|
|||
*/
|
||||
int getAnalogValue();
|
||||
|
||||
/**
|
||||
* Determines if this IO pin is currently configured as an input.
|
||||
* @return 1 if pin is an analog or digital input, 0 otherwise.
|
||||
*/
|
||||
int isInput();
|
||||
|
||||
/**
|
||||
* Determines if this IO pin is currently configured as an output.
|
||||
* @return 1 if pin is an analog or digital output, 0 otherwise.
|
||||
*/
|
||||
int isOutput();
|
||||
|
||||
/**
|
||||
* Determines if this IO pin is currently configured for digital use.
|
||||
* @return 1 if pin is digital, 0 otherwise.
|
||||
*/
|
||||
int isDigital();
|
||||
|
||||
/**
|
||||
* Determines if this IO pin is currently configured for analog use.
|
||||
* @return 1 if pin is analog, 0 otherwise.
|
||||
*/
|
||||
int isAnalog();
|
||||
|
||||
/**
|
||||
* Configures this IO pin as a makey makey style touch sensor (if necessary) and tests its current debounced state.
|
||||
* @return 1 if pin is touched, 0 otherwise.
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef MICROBIT_TEMPERATURE_SERVICE_H
|
||||
#define MICROBIT_TEMPERATURE_SERVICE_H
|
||||
|
||||
#include "MicroBit.h"
|
||||
|
||||
// UUIDs for our service and characteristics
|
||||
extern const uint8_t MicroBitTemperatureServiceUUID[];
|
||||
extern const uint8_t MicroBitTemperatureServiceDataUUID[];
|
||||
|
||||
|
||||
/**
|
||||
* Class definition for a MicroBit BLE Temperture Service.
|
||||
* Provides access to live temperature data via BLE.
|
||||
*/
|
||||
class MicroBitTemperatureService
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a representation of the TempertureService
|
||||
* @param _ble The instance of a BLE device that we're running on.
|
||||
*/
|
||||
MicroBitTemperatureService(BLEDevice &_ble);
|
||||
|
||||
/**
|
||||
* Temperature update callback
|
||||
*/
|
||||
void temperatureUpdate(MicroBitEvent e);
|
||||
|
||||
private:
|
||||
|
||||
// Bluetooth stack we're running on.
|
||||
BLEDevice &ble;
|
||||
|
||||
// memory for our 8 bit temperature characteristic.
|
||||
int8_t temperatureDataCharacteristicBuffer;
|
||||
|
||||
// Handles to access each characteristic when they are held by Soft Device.
|
||||
GattAttribute::Handle_t temperatureDataCharacteristicHandle;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -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"
|
||||
|
@ -32,6 +33,10 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES
|
|||
"ble-services/MicroBitEventService.cpp"
|
||||
"ble-services/MicroBitLEDService.cpp"
|
||||
"ble-services/MicroBitAccelerometerService.cpp"
|
||||
"ble-services/MicroBitMagnetometerService.cpp"
|
||||
"ble-services/MicroBitButtonService.cpp"
|
||||
"ble-services/MicroBitIOPinService.cpp"
|
||||
"ble-services/MicroBitTemperatureService.cpp"
|
||||
)
|
||||
|
||||
if (YOTTA_CFG_MICROBIT_CONFIGFILE)
|
||||
|
|
|
@ -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,
|
||||
|
@ -121,6 +122,26 @@ void MicroBit::init()
|
|||
ble_led_service = new MicroBitLEDService(*ble);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_ACCELEROMETER_SERVICE)
|
||||
ble_accelerometer_service = new MicroBitAccelerometerService(*ble);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_MAGNETOMETER_SERVICE)
|
||||
ble_magnetometer_service = new MicroBitMagnetometerService(*ble);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_BUTTON_SERVICE)
|
||||
ble_button_service = new MicroBitButtonService(*ble);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_IO_PIN_SERVICE)
|
||||
ble_io_pin_service = new MicroBitIOPinService(*ble);
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_BLE_TEMPERATURE_SERVICE)
|
||||
ble_temperature_service = new MicroBitTemperatureService(*ble);
|
||||
#endif
|
||||
|
||||
// Setup advertising.
|
||||
ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
|
||||
ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)MICROBIT_BLE_DEVICE_NAME, sizeof(MICROBIT_BLE_DEVICE_NAME));
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -174,7 +173,8 @@ void MicroBitAccelerometer::update()
|
|||
sample.y *= this->sampleRange;
|
||||
sample.z *= this->sampleRange;
|
||||
|
||||
//TODO: Issue an event.
|
||||
// Indicate that a new sample is available
|
||||
MicroBitEvent e(id, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -263,7 +263,7 @@ int MicroBitAccelerometer::getZ()
|
|||
{
|
||||
return sample.z;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* periodic callback from MicroBit clock.
|
||||
|
|
|
@ -23,23 +23,21 @@ 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;
|
||||
|
||||
// Enable automatic reset after each sample;
|
||||
writeCommand(MAG_CTRL_REG2, 0xA0);
|
||||
|
||||
// Select 10Hz update rate, with oversampling. Also enables the device.
|
||||
writeCommand(MAG_CTRL_REG1, 0x61);
|
||||
// Select 10Hz update rate, with oversampling, and enable the device.
|
||||
this->samplePeriod = 100;
|
||||
this->configure();
|
||||
|
||||
//fetch our previous average values
|
||||
average.x = read16(MAG_OFF_X_MSB);
|
||||
average.y = read16(MAG_OFF_Y_MSB);
|
||||
average.z = read16(MAG_OFF_Z_MSB);
|
||||
|
||||
|
||||
if(average.x == 0 && average.y == 0 && average.z == 0)
|
||||
status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED;
|
||||
|
||||
|
@ -106,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);
|
||||
|
@ -131,6 +129,7 @@ int MicroBitCompass::heading()
|
|||
{
|
||||
if(status & MICROBIT_COMPASS_STATUS_CALIBRATING)
|
||||
return MICROBIT_COMPASS_IS_CALIBRATING;
|
||||
|
||||
else if(!(status & MICROBIT_COMPASS_STATUS_CALIBRATED))
|
||||
{
|
||||
MicroBitEvent(id, MICROBIT_COMPASS_EVT_CAL_REQUIRED);
|
||||
|
@ -174,8 +173,14 @@ void MicroBitCompass::idleTick()
|
|||
eventStartTime = 0;
|
||||
calibrateEnd();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Indicate that a new sample is available
|
||||
MicroBitEvent e(id, MICROBIT_COMPASS_EVT_DATA_UPDATE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -220,6 +225,65 @@ int MicroBitCompass::getZ()
|
|||
return sample.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the compass for the sample rate defined
|
||||
* in this object. The nearest values are chosen to those defined
|
||||
* that are supported by the hardware. The instance variables are then
|
||||
* updated to reflect reality.
|
||||
*/
|
||||
void MicroBitCompass::configure()
|
||||
{
|
||||
const MAG3110SampleRateConfig *actualSampleRate;
|
||||
|
||||
// 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--)
|
||||
{
|
||||
if(MAG3110SampleRate[i].sample_period < this->samplePeriod * 1000)
|
||||
break;
|
||||
|
||||
actualSampleRate = &MAG3110SampleRate[i];
|
||||
}
|
||||
|
||||
// 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
|
||||
* nearest lower rate is chosen.
|
||||
* @param period the requested time between samples, in milliseconds.
|
||||
*/
|
||||
void MicroBitCompass::setPeriod(int period)
|
||||
{
|
||||
this->samplePeriod = period;
|
||||
this->configure();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the currently configured sample rate of the compass.
|
||||
* @return The time between samples, in milliseconds.
|
||||
*/
|
||||
int MicroBitCompass::getPeriod()
|
||||
{
|
||||
return (int)samplePeriod;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to determine the 8 bit ID from the magnetometer.
|
||||
* @return the id of the compass (magnetometer)
|
||||
|
@ -237,6 +301,18 @@ int MicroBitCompass::whoAmI()
|
|||
return (int)data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the currently die temperature of the compass.
|
||||
* @return The temperature, in degrees celsius.
|
||||
*/
|
||||
int MicroBitCompass::readTemperature()
|
||||
{
|
||||
int8_t temperature;
|
||||
readCommand(MAG_DIE_TEMP, (uint8_t *)&temperature, 1);
|
||||
|
||||
return temperature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a calibration of the compass.
|
||||
* This will fire MICROBIT_COMPASS_EVT_CAL_START.
|
||||
|
@ -281,7 +357,7 @@ void MicroBitCompass::calibrateEnd()
|
|||
|
||||
status &= ~MICROBIT_COMPASS_STATUS_CALIBRATING;
|
||||
status |= MICROBIT_COMPASS_STATUS_CALIBRATED;
|
||||
|
||||
|
||||
//Store x, y and z values in persistent storage on the MAG3110
|
||||
writeCommand(MAG_OFF_X_LSB, (uint8_t)average.x);
|
||||
writeCommand(MAG_OFF_X_MSB, (uint8_t)(average.x >> 8));
|
||||
|
@ -333,6 +409,21 @@ void MicroBitCompass::clearCalibration()
|
|||
*/
|
||||
int MicroBitCompass::isIdleCallbackNeeded()
|
||||
{
|
||||
//Active HI
|
||||
// The MAG3110 raises an interrupt line when data is ready, which we sample here.
|
||||
// The interrupt line is active HI, so simply return the state of the pin.
|
||||
return int1;
|
||||
}
|
||||
|
||||
const MAG3110SampleRateConfig MAG3110SampleRate[MAG3110_SAMPLE_RATES] = {
|
||||
{12500, 0x00}, // 80 Hz
|
||||
{25000, 0x20}, // 40 Hz
|
||||
{50000, 0x40}, // 20 Hz
|
||||
{100000, 0x60}, // 10 hz
|
||||
{200000, 0x80}, // 5 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, 0xf8} // 0.08 hz
|
||||
};
|
||||
|
|
|
@ -162,7 +162,7 @@ void scheduler_init()
|
|||
idle = getFiberContext();
|
||||
idle->tcb.SP = CORTEX_M0_STACK_BASE - 0x04;
|
||||
idle->tcb.LR = (uint32_t) &idle_task;
|
||||
|
||||
|
||||
// Flag that we now have a scheduler running
|
||||
uBit.flags |= MICROBIT_FLAG_SCHEDULER_RUNNING;
|
||||
}
|
||||
|
@ -224,6 +224,9 @@ void scheduler_event(MicroBitEvent evt)
|
|||
|
||||
f = t;
|
||||
}
|
||||
|
||||
// Unregister this event, as we've woken up all the fibers with this match.
|
||||
uBit.MessageBus.ignore(evt.source, evt.value, scheduler_event);
|
||||
}
|
||||
|
||||
|
||||
|
@ -306,6 +309,9 @@ void fiber_wait_for_event(uint16_t id, uint16_t value)
|
|||
// Add ourselves to the sleep queue. We maintain strict ordering here to reduce lookup times.
|
||||
queue_fiber(f, &waitQueue);
|
||||
|
||||
// Register to receive this event, so we can wake up the fiber when it happens.
|
||||
uBit.MessageBus.listen(id, value, scheduler_event, MESSAGE_BUS_LISTENER_NONBLOCKING);
|
||||
|
||||
// Finally, enter the scheduler.
|
||||
schedule();
|
||||
}
|
||||
|
|
|
@ -104,16 +104,25 @@ void async_callback(void *param)
|
|||
*/
|
||||
void MicroBitMessageBus::queueEvent(MicroBitEvent &evt)
|
||||
{
|
||||
MicroBitEventQueueItem *item = new MicroBitEventQueueItem(evt);
|
||||
int processingComplete;
|
||||
|
||||
__disable_irq();
|
||||
|
||||
if (evt_queue_tail == NULL)
|
||||
evt_queue_head = evt_queue_tail = item;
|
||||
else
|
||||
evt_queue_tail->next = item;
|
||||
// Firstly, process all handler regsitered as URGENT. These pre-empt the queue, and are useful for fast, high priority services.
|
||||
processingComplete = this->process(evt, MESSAGE_BUS_LISTENER_URGENT);
|
||||
|
||||
__enable_irq();
|
||||
if (!processingComplete)
|
||||
{
|
||||
// We need to queue this event for later processing...
|
||||
MicroBitEventQueueItem *item = new MicroBitEventQueueItem(evt);
|
||||
|
||||
__disable_irq();
|
||||
|
||||
if (evt_queue_tail == NULL)
|
||||
evt_queue_head = evt_queue_tail = item;
|
||||
else
|
||||
evt_queue_tail->next = item;
|
||||
|
||||
__enable_irq();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,7 +163,7 @@ void MicroBitMessageBus::idleTick()
|
|||
// Whilst there are events to process and we have no useful other work to do, pull them off the queue and process them.
|
||||
while (item)
|
||||
{
|
||||
// send the event.
|
||||
// send the event to all standard event listeners.
|
||||
this->process(item->evt);
|
||||
|
||||
// Free the queue item.
|
||||
|
@ -212,43 +221,43 @@ void MicroBitMessageBus::send(MicroBitEvent evt)
|
|||
* This will attempt to call the event handler directly, but spawn a fiber should that
|
||||
* event handler attempt a blocking operation.
|
||||
* @param evt The event to be delivered.
|
||||
* @param mask The type of listeners to process (optional). Matches MicroBitListener flags. If not defined, all standard listeners will be processed.
|
||||
* @return The 1 if all matching listeners were processed, 0 if further processing is required.
|
||||
*/
|
||||
void MicroBitMessageBus::process(MicroBitEvent evt)
|
||||
int MicroBitMessageBus::process(MicroBitEvent &evt, uint32_t mask)
|
||||
{
|
||||
MicroBitListener *l;
|
||||
int complete = 1;
|
||||
|
||||
l = listeners;
|
||||
while (l != NULL)
|
||||
{
|
||||
if((l->id == evt.source || l->id == MICROBIT_ID_ANY) && (l->value == evt.value || l->value == MICROBIT_EVT_ANY))
|
||||
{
|
||||
l->evt = evt;
|
||||
if(l->flags & mask)
|
||||
{
|
||||
l->evt = evt;
|
||||
|
||||
// OK, if this handler has regisitered itself as non-blocking, we just execute it directly...
|
||||
// This is normally only done for trusted system components.
|
||||
// Otherwise, we invoke it in a 'fork on block' context, that will automatically create a fiber
|
||||
// should the event handler attempt a blocking operation, but doesn't have the overhead
|
||||
// of creating a fiber needlessly. (cool huh?)
|
||||
if (l->flags & MESSAGE_BUS_LISTENER_NONBLOCKING)
|
||||
async_callback(l);
|
||||
// OK, if this handler has regisitered itself as non-blocking, we just execute it directly...
|
||||
// This is normally only done for trusted system components.
|
||||
// Otherwise, we invoke it in a 'fork on block' context, that will automatically create a fiber
|
||||
// should the event handler attempt a blocking operation, but doesn't have the overhead
|
||||
// of creating a fiber needlessly. (cool huh?)
|
||||
if (l->flags & MESSAGE_BUS_LISTENER_NONBLOCKING)
|
||||
async_callback(l);
|
||||
else
|
||||
invoke(async_callback, l);
|
||||
}
|
||||
else
|
||||
invoke(async_callback, l);
|
||||
{
|
||||
complete = 0;
|
||||
}
|
||||
}
|
||||
|
||||
l = l->next;
|
||||
}
|
||||
|
||||
// Finally, forward the event to any other internal subsystems that may be interested.
|
||||
// We *could* do this through the message bus of course, but this saves additional RAM,
|
||||
// and procssor time (as we know these are non-blocking calls).
|
||||
|
||||
// Wake up any fibers that are blocked on this event
|
||||
if (uBit.flags & MICROBIT_FLAG_SCHEDULER_RUNNING)
|
||||
scheduler_event(evt);
|
||||
|
||||
// See if this event needs to be propogated through our BLE interface
|
||||
if (uBit.ble_event_service)
|
||||
uBit.ble_event_service->onMicroBitEvent(evt);
|
||||
return complete;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -365,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
|
||||
|
@ -450,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -479,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;
|
||||
}
|
||||
|
||||
|
|
|
@ -171,6 +171,42 @@ int MicroBitPin::getAnalogValue()
|
|||
return ((AnalogIn *)pin)->read_u16();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this IO pin is currently configured as an input.
|
||||
* @return 1 if pin is an analog or digital input, 0 otherwise.
|
||||
*/
|
||||
int MicroBitPin::isInput()
|
||||
{
|
||||
return (status & (IO_STATUS_DIGITAL_IN | IO_STATUS_ANALOG_IN)) == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this IO pin is currently configured as an output.
|
||||
* @return 1 if pin is an analog or digital output, 0 otherwise.
|
||||
*/
|
||||
int MicroBitPin::isOutput()
|
||||
{
|
||||
return (status & (IO_STATUS_DIGITAL_OUT | IO_STATUS_ANALOG_OUT)) == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this IO pin is currently configured for digital use.
|
||||
* @return 1 if pin is digital, 0 otherwise.
|
||||
*/
|
||||
int MicroBitPin::isDigital()
|
||||
{
|
||||
return (status & (IO_STATUS_DIGITAL_IN | IO_STATUS_DIGITAL_OUT)) == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this IO pin is currently configured for analog use.
|
||||
* @return 1 if pin is analog, 0 otherwise.
|
||||
*/
|
||||
int MicroBitPin::isAnalog()
|
||||
{
|
||||
return (status & (IO_STATUS_ANALOG_IN | IO_STATUS_ANALOG_OUT)) == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this IO pin as a makey makey style touch sensor (if necessary) and tests its current debounced state.
|
||||
* @return 1 if pin is touched, 0 otherwise.
|
||||
|
|
|
@ -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,13 +38,13 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback. Invoked when any of our attributes are written via BLE.
|
||||
*/
|
||||
|
@ -52,11 +52,30 @@ 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));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accelerometer update callback
|
||||
*/
|
||||
void MicroBitAccelerometerService::accelerometerUpdate(MicroBitEvent e)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t MicroBitAccelerometerServiceUUID[] = {
|
||||
0xe9,0x5d,0x07,0x53,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
* Class definition for the custom MicroBit Button Service.
|
||||
* Provides a BLE service to remotely read the state of each button, and configure its behaviour.
|
||||
*/
|
||||
|
||||
#include "MicroBit.h"
|
||||
#include "ble/UUID.h"
|
||||
|
||||
#include "MicroBitButtonService.h"
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a representation of the ButtonService
|
||||
* @param _ble The instance of a BLE device that we're running on.
|
||||
*/
|
||||
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,
|
||||
sizeof(buttonADataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
|
||||
|
||||
GattCharacteristic buttonBDataCharacteristic(MicroBitButtonBServiceDataUUID, (uint8_t *)&buttonADataCharacteristicBuffer, 0,
|
||||
sizeof(buttonADataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
|
||||
|
||||
|
||||
// Initialise our characteristic values.
|
||||
buttonADataCharacteristicBuffer = 0;
|
||||
buttonBDataCharacteristicBuffer = 0;
|
||||
|
||||
GattCharacteristic *characteristics[] = {&buttonADataCharacteristic, &buttonBDataCharacteristic};
|
||||
GattService service(MicroBitButtonServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
|
||||
|
||||
ble.addService(service);
|
||||
|
||||
buttonADataCharacteristicHandle = buttonADataCharacteristic.getValueHandle();
|
||||
buttonBDataCharacteristicHandle = buttonBDataCharacteristic.getValueHandle();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Button B update callback
|
||||
*/
|
||||
void MicroBitButtonService::buttonAUpdate(MicroBitEvent e)
|
||||
{
|
||||
if (ble.getGapState().connected)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Button A update callback
|
||||
*/
|
||||
void MicroBitButtonService::buttonBUpdate(MicroBitEvent e)
|
||||
{
|
||||
if (ble.getGapState().connected)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t MicroBitButtonServiceUUID[] = {
|
||||
0xe9,0x5d,0x98,0x82,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
||||
const uint8_t MicroBitButtonAServiceDataUUID[] = {
|
||||
0xe9,0x5d,0xda,0x90,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
}
|
||||
;
|
||||
const uint8_t MicroBitButtonBServiceDataUUID[] = {
|
||||
0xe9,0x5d,0xda,0x91,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
|
@ -242,13 +242,13 @@ void MicroBitDFUService::releaseFlashCode()
|
|||
*/
|
||||
|
||||
const uint8_t MicroBitDFUServiceUUID[] = {
|
||||
0xd8,0xaf,0x99,0x1c,0x71,0x44,0x43,0xd7,0x95,0x4b,0x99,0x51,0x2f,0x95,0xf9,0x9c
|
||||
0xe9,0x5d,0x93,0xb0,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
||||
const uint8_t MicroBitDFUServiceControlCharacteristicUUID[] = {
|
||||
0x97,0x10,0x95,0x47,0xe6,0x3a,0x44,0x2a,0xbf,0x89,0x9d,0x73,0x04,0x13,0xdc,0x2f
|
||||
0xe9,0x5d,0x93,0xb1,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
||||
const uint8_t MicroBitDFUServiceFlashCodeCharacteristicUUID[] = {
|
||||
0x94,0x7b,0x69,0x34,0x64,0xd1,0x4f,0xad,0x9b,0xd0,0xcc,0x9d,0x6e,0x9f,0x3e,0xa3
|
||||
0xe9,0x5d,0x93,0xb2,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,285 @@
|
|||
/**
|
||||
* Class definition for the custom MicroBit IOPin Service.
|
||||
* Provides a BLE service to remotely read the state of the ioPin, and configure its behaviour.
|
||||
*/
|
||||
|
||||
#include "MicroBit.h"
|
||||
#include "ble/UUID.h"
|
||||
|
||||
#include "MicroBitIOPinService.h"
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a representation of the IOPinService
|
||||
* @param _ble The instance of a BLE device that we're running on.
|
||||
*/
|
||||
MicroBitIOPinService::MicroBitIOPinService(BLEDevice &_ble) :
|
||||
ble(_ble)
|
||||
{
|
||||
// Create the AD characteristic, that defines whether each pin is treated as analogue or digital
|
||||
GattCharacteristic ioPinServiceADCharacteristic(MicroBitIOPinServiceADConfigurationUUID, (uint8_t *)&ioPinServiceADCharacteristicBuffer, 0, sizeof(ioPinServiceADCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
|
||||
|
||||
// Create the IO characteristic, that defines whether each pin is treated as input or output
|
||||
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->setReadAuthorizationCallback(this, &MicroBitIOPinService::onDataRead);
|
||||
|
||||
ioPinServiceADCharacteristicBuffer = 0;
|
||||
ioPinServiceIOCharacteristicBuffer = 0;
|
||||
memset(ioPinServiceIOData, 0, sizeof(ioPinServiceIOData));
|
||||
|
||||
GattCharacteristic *characteristics[] = {&ioPinServiceADCharacteristic, &ioPinServiceIOCharacteristic, ioPinServiceDataCharacteristic};
|
||||
GattService service(MicroBitIOPinServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
|
||||
|
||||
ble.addService(service);
|
||||
|
||||
ioPinServiceADCharacteristicHandle = ioPinServiceADCharacteristic.getValueHandle();
|
||||
ioPinServiceIOCharacteristicHandle = ioPinServiceIOCharacteristic.getValueHandle();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given pin was configured as a digital pin by the BLE IOPinConfigurationCharacterisitic.
|
||||
*
|
||||
* @param pin the enumeration of the pin to test
|
||||
* @return 1 if this pin is configured as a digital value, 0 otherwise
|
||||
*/
|
||||
int MicroBitIOPinService::isDigital(int i)
|
||||
{
|
||||
return ((ioPinServiceADCharacteristicBuffer & (1 << i)) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given pin was configured as an analog pin by the BLE IOPinConfigurationCharacterisitic.
|
||||
*
|
||||
* @param pin the enumeration of the pin to test
|
||||
* @return 1 if this pin is configured as a analog value, 0 otherwise
|
||||
*/
|
||||
int MicroBitIOPinService::isAnalog(int i)
|
||||
{
|
||||
return ((ioPinServiceADCharacteristicBuffer & (1 << i)) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given pin was configured as an input by the BLE IOPinConfigurationCharacterisitic.
|
||||
*
|
||||
* @param pin the enumeration of the pin to test
|
||||
* @return 1 if this pin is configured as an input, 0 otherwise
|
||||
*/
|
||||
int MicroBitIOPinService::isInput(int i)
|
||||
{
|
||||
return ((ioPinServiceIOCharacteristicBuffer & (1 << i)) != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the given pin was configured as output by the BLE IOPinConfigurationCharacterisitic.
|
||||
*
|
||||
* @param pin the enumeration of the pin to test
|
||||
* @return 1 if this pin is configured as an output, 0 otherwise
|
||||
*/
|
||||
int MicroBitIOPinService::isOutput(int i)
|
||||
{
|
||||
return ((ioPinServiceIOCharacteristicBuffer & (1 << i)) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback. Invoked when any of our attributes are written via BLE.
|
||||
*/
|
||||
void MicroBitIOPinService::onDataWritten(const GattWriteCallbackParams *params)
|
||||
{
|
||||
// Check for writes to the IO configuration characteristic
|
||||
if (params->handle == ioPinServiceIOCharacteristicHandle && params->len >= sizeof(ioPinServiceIOCharacteristicBuffer))
|
||||
{
|
||||
uint32_t *value = (uint32_t *)params->data;
|
||||
|
||||
// Our IO configuration may be changing... read the new value, and push it back into the BLE stack.
|
||||
ioPinServiceIOCharacteristicBuffer = *value;
|
||||
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++)
|
||||
{
|
||||
if(isDigital(i) && isInput(i))
|
||||
MicroBitIOPins[i]->getDigitalValue();
|
||||
|
||||
if(isAnalog(i) && isInput(i))
|
||||
MicroBitIOPins[i]->getAnalogValue();
|
||||
}
|
||||
}
|
||||
|
||||
// Check for writes to the IO configuration characteristic
|
||||
if (params->handle == ioPinServiceADCharacteristicHandle && params->len >= sizeof(ioPinServiceADCharacteristicBuffer))
|
||||
{
|
||||
uint32_t *value = (uint32_t *)params->data;
|
||||
|
||||
// Our IO configuration may be changing... read the new value, and push it back into the BLE stack.
|
||||
ioPinServiceADCharacteristicBuffer = *value;
|
||||
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++)
|
||||
{
|
||||
if(isDigital(i) && isInput(i))
|
||||
MicroBitIOPins[i]->getDigitalValue();
|
||||
|
||||
if(isAnalog(i) && isInput(i))
|
||||
MicroBitIOPins[i]->getAnalogValue();
|
||||
}
|
||||
}
|
||||
|
||||
if (params->handle == ioPinServiceDataCharacteristic->getValueHandle())
|
||||
{
|
||||
// We have some pin data to change...
|
||||
int len = params->len;
|
||||
IOData *data = (IOData *)params->data;
|
||||
|
||||
// There may be multiple write operaitons... take each in turn and update the pin values
|
||||
while (len >= sizeof(IOData))
|
||||
{
|
||||
if (isOutput(data->pin))
|
||||
{
|
||||
if (isDigital(data->pin))
|
||||
MicroBitIOPins[data->pin]->setDigitalValue(data->value);
|
||||
else
|
||||
MicroBitIOPins[data->pin]->setAnalogValue(data->value*4);
|
||||
}
|
||||
|
||||
data++;
|
||||
len -= sizeof(IOData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* read callback on data characteristic.
|
||||
* reads all the pins marked as inputs, and updates the data stored in the BLE stack.
|
||||
*/
|
||||
void MicroBitIOPinService::onDataRead(GattReadAuthCallbackParams *params)
|
||||
{
|
||||
if (params->handle == ioPinServiceDataCharacteristic->getValueHandle())
|
||||
{
|
||||
|
||||
// Scan through all pins that our BLE client may be listening for. If any have changed value, update the BLE characterisitc, and NOTIFY our client.
|
||||
int pairs = 0;
|
||||
|
||||
for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
|
||||
{
|
||||
if (isInput(i))
|
||||
{
|
||||
uint8_t value;
|
||||
|
||||
if (isDigital(i))
|
||||
value = MicroBitIOPins[i]->getDigitalValue();
|
||||
else
|
||||
value = MicroBitIOPins[i]->getAnalogValue();
|
||||
|
||||
ioPinServiceIOData[i] = value;
|
||||
ioPinServiceDataCharacteristicBuffer[pairs].pin = i;
|
||||
ioPinServiceDataCharacteristicBuffer[pairs].value = value;
|
||||
|
||||
pairs++;
|
||||
|
||||
if (pairs >= MICROBIT_IO_PIN_SERVICE_DATA_SIZE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If there's any data, issue a BLE notification.
|
||||
if (pairs > 0)
|
||||
ble.gattServer().notify(ioPinServiceDataCharacteristic->getValueHandle(), (uint8_t *)ioPinServiceDataCharacteristicBuffer, pairs * sizeof(IOData));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Periodic callback from MicroBit scheduler.
|
||||
* Check if any of the pins we're watching need updating. Apply a BLE NOTIFY if so...
|
||||
*/
|
||||
void MicroBitIOPinService::idleTick()
|
||||
{
|
||||
// If we're not we're connected, then there's nothing to do...
|
||||
if (!ble.getGapState().connected)
|
||||
return;
|
||||
|
||||
// Scan through all pins that our BLE client may be listening for. If any have changed value, update the BLE characterisitc, and NOTIFY our client.
|
||||
int pairs = 0;
|
||||
|
||||
for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
|
||||
{
|
||||
if (isInput(i))
|
||||
{
|
||||
uint8_t value;
|
||||
|
||||
if (isDigital(i))
|
||||
value = MicroBitIOPins[i]->getDigitalValue();
|
||||
else
|
||||
value = MicroBitIOPins[i]->getAnalogValue();
|
||||
|
||||
// If the data has changed, send an update.
|
||||
if (value != ioPinServiceIOData[i])
|
||||
{
|
||||
ioPinServiceIOData[i] = value;
|
||||
|
||||
ioPinServiceDataCharacteristicBuffer[pairs].pin = i;
|
||||
ioPinServiceDataCharacteristicBuffer[pairs].value = value;
|
||||
|
||||
pairs++;
|
||||
|
||||
if (pairs >= MICROBIT_IO_PIN_SERVICE_DATA_SIZE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there were any changes, issue a BLE notification.
|
||||
if (pairs > 0)
|
||||
ble.gattServer().notify(ioPinServiceDataCharacteristic->getValueHandle(), (uint8_t *)ioPinServiceDataCharacteristicBuffer, pairs * sizeof(IOData));
|
||||
}
|
||||
|
||||
const uint8_t MicroBitIOPinServiceUUID[] = {
|
||||
0xe9,0x5d,0x12,0x7b,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
||||
const uint8_t MicroBitIOPinServiceIOConfigurationUUID[] = {
|
||||
0xe9,0x5d,0xb9,0xfe,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
||||
const uint8_t MicroBitIOPinServiceADConfigurationUUID[] = {
|
||||
0xe9,0x5d,0x58,0x99,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
||||
const uint8_t MicroBitIOPinServiceDataUUID[] = {
|
||||
0xe9,0x5d,0x8d,0x00,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
||||
MicroBitPin * const MicroBitIOPins[] = {
|
||||
&uBit.io.P0,
|
||||
&uBit.io.P1,
|
||||
&uBit.io.P2,
|
||||
&uBit.io.P3,
|
||||
&uBit.io.P4,
|
||||
&uBit.io.P5,
|
||||
&uBit.io.P6,
|
||||
&uBit.io.P7,
|
||||
&uBit.io.P8,
|
||||
&uBit.io.P9,
|
||||
&uBit.io.P10,
|
||||
&uBit.io.P11,
|
||||
&uBit.io.P12,
|
||||
&uBit.io.P13,
|
||||
&uBit.io.P14,
|
||||
&uBit.io.P15,
|
||||
&uBit.io.P16,
|
||||
&uBit.io.P19,
|
||||
&uBit.io.P20
|
||||
};
|
||||
|
||||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* Class definition for the custom MicroBit Magnetometer Service.
|
||||
* Provides a BLE service to remotely read the state of the magnetometer, and configure its behaviour.
|
||||
*/
|
||||
|
||||
#include "MicroBit.h"
|
||||
#include "ble/UUID.h"
|
||||
|
||||
#include "MicroBitMagnetometerService.h"
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a representation of the MagnetometerService
|
||||
* @param _ble The instance of a BLE device that we're running on.
|
||||
*/
|
||||
MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble) :
|
||||
ble(_ble)
|
||||
{
|
||||
// Create the data structures that represent each of our characteristics in Soft Device.
|
||||
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,
|
||||
sizeof(magnetometerBearingCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
|
||||
|
||||
GattCharacteristic magnetometerPeriodCharacteristic(MicroBitMagnetometerServicePeriodUUID, (uint8_t *)&magnetometerPeriodCharacteristicBuffer, 0,
|
||||
sizeof(magnetometerPeriodCharacteristicBuffer),
|
||||
GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE);
|
||||
|
||||
// Initialise our characteristic values.
|
||||
magnetometerDataCharacteristicBuffer[0] = 0;
|
||||
magnetometerDataCharacteristicBuffer[1] = 0;
|
||||
magnetometerDataCharacteristicBuffer[2] = 0;
|
||||
magnetometerBearingCharacteristicBuffer = 0;
|
||||
magnetometerPeriodCharacteristicBuffer = uBit.compass.getPeriod();
|
||||
|
||||
GattCharacteristic *characteristics[] = {&magnetometerDataCharacteristic, &magnetometerBearingCharacteristic, &magnetometerPeriodCharacteristic};
|
||||
GattService service(MicroBitMagnetometerServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
|
||||
|
||||
ble.addService(service);
|
||||
|
||||
magnetometerDataCharacteristicHandle = magnetometerDataCharacteristic.getValueHandle();
|
||||
magnetometerBearingCharacteristicHandle = magnetometerBearingCharacteristic.getValueHandle();
|
||||
magnetometerPeriodCharacteristicHandle = magnetometerPeriodCharacteristic.getValueHandle();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback. Invoked when any of our attributes are written via BLE.
|
||||
*/
|
||||
void MicroBitMagnetometerService::onDataWritten(const GattWriteCallbackParams *params)
|
||||
{
|
||||
if (params->handle == magnetometerPeriodCharacteristicHandle && params->len >= sizeof(magnetometerPeriodCharacteristicBuffer))
|
||||
{
|
||||
magnetometerPeriodCharacteristicBuffer = *((uint16_t *)params->data);
|
||||
MicroBitEvent evt(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CONFIG_NEEDED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Magnetometer update callback
|
||||
*/
|
||||
void MicroBitMagnetometerService::magnetometerUpdate(MicroBitEvent e)
|
||||
{
|
||||
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));
|
||||
|
||||
}
|
||||
|
||||
const uint8_t MicroBitMagnetometerServiceUUID[] = {
|
||||
0xe9,0x5d,0xf2,0xd8,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
||||
const uint8_t MicroBitMagnetometerServiceDataUUID[] = {
|
||||
0xe9,0x5d,0xfb,0x11,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
||||
const uint8_t MicroBitMagnetometerServicePeriodUUID[] = {
|
||||
0xe9,0x5d,0x38,0x6c,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
||||
const uint8_t MicroBitMagnetometerServiceBearingUUID[] = {
|
||||
0xe9,0x5d,0x97,0x15,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* Class definition for the custom MicroBit Temperature Service.
|
||||
* Provides a BLE service to remotely read the state of the temperature, and configure its behaviour.
|
||||
*/
|
||||
|
||||
#include "MicroBit.h"
|
||||
#include "ble/UUID.h"
|
||||
|
||||
#include "MicroBitTemperatureService.h"
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create a representation of the TemperatureService
|
||||
* @param _ble The instance of a BLE device that we're running on.
|
||||
*/
|
||||
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,
|
||||
sizeof(temperatureDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
|
||||
|
||||
// Initialise our characteristic values.
|
||||
temperatureDataCharacteristicBuffer = 0;
|
||||
|
||||
GattCharacteristic *characteristics[] = {&temperatureDataCharacteristic};
|
||||
GattService service(MicroBitTemperatureServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
|
||||
|
||||
ble.addService(service);
|
||||
|
||||
temperatureDataCharacteristicHandle = temperatureDataCharacteristic.getValueHandle();
|
||||
ble.gattServer().write(temperatureDataCharacteristicHandle,(uint8_t *)&temperatureDataCharacteristicBuffer, sizeof(temperatureDataCharacteristicBuffer));
|
||||
|
||||
uBit.MessageBus.listen(MICROBIT_ID_THERMOMETER, MICROBIT_THERMOMETER_EVT_UPDATE, this, &MicroBitTemperatureService::temperatureUpdate, MESSAGE_BUS_LISTENER_NONBLOCKING | MESSAGE_BUS_LISTENER_URGENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Temperature update callback
|
||||
*/
|
||||
void MicroBitTemperatureService::temperatureUpdate(MicroBitEvent e)
|
||||
{
|
||||
if (ble.getGapState().connected)
|
||||
{
|
||||
temperatureDataCharacteristicBuffer = uBit.thermometer.getTemperature();
|
||||
ble.gattServer().notify(temperatureDataCharacteristicHandle,(uint8_t *)&temperatureDataCharacteristicBuffer, sizeof(temperatureDataCharacteristicBuffer));
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t MicroBitTemperatureServiceUUID[] = {
|
||||
0xe9,0x5d,0x61,0x00,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
||||
const uint8_t MicroBitTemperatureServiceDataUUID[] = {
|
||||
0xe9,0x5d,0x8a,0x38,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue