microbit: First cut at MicroBitButtonService and microBitIOPinService
Strictly still development - untested code.
This commit is contained in:
parent
ef613e9d86
commit
eb5ed28f74
|
@ -38,6 +38,8 @@
|
||||||
#include "MicroBitLEDService.h"
|
#include "MicroBitLEDService.h"
|
||||||
#include "MicroBitAccelerometerService.h"
|
#include "MicroBitAccelerometerService.h"
|
||||||
#include "MicroBitMagnetometerService.h"
|
#include "MicroBitMagnetometerService.h"
|
||||||
|
#include "MicroBitButtonService.h"
|
||||||
|
#include "MicroBitIOPinService.h"
|
||||||
#include "ExternalEvents.h"
|
#include "ExternalEvents.h"
|
||||||
|
|
||||||
// MicroBit::flags values
|
// MicroBit::flags values
|
||||||
|
@ -113,6 +115,8 @@ class MicroBit
|
||||||
MicroBitLEDService *ble_led_service;
|
MicroBitLEDService *ble_led_service;
|
||||||
MicroBitAccelerometerService *ble_accelerometer_service;
|
MicroBitAccelerometerService *ble_accelerometer_service;
|
||||||
MicroBitMagnetometerService *ble_magnetometer_service;
|
MicroBitMagnetometerService *ble_magnetometer_service;
|
||||||
|
MicroBitButtonService *ble_button_service;
|
||||||
|
MicroBitIOPinService *ble_io_pin_service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -171,7 +171,20 @@
|
||||||
// This enables live access to the on board 3 axis magnetometer.
|
// This enables live access to the on board 3 axis magnetometer.
|
||||||
// Set '1' to enable.
|
// Set '1' to enable.
|
||||||
#ifndef MICROBIT_BLE_MAGNETOMETER_SERVICE
|
#ifndef MICROBIT_BLE_MAGNETOMETER_SERVICE
|
||||||
#define MICROBIT_BLE_MAGNETOMETER_SERVICE 1
|
#define MICROBIT_BLE_MAGNETOMETER_SERVICE 1
|
||||||
|
#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
|
||||||
|
#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
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Defines the maximum length strong that can be written to the
|
// Defines the maximum length strong that can be written to the
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -42,7 +42,7 @@ class MicroBitMagnetometerService
|
||||||
BLEDevice &ble;
|
BLEDevice &ble;
|
||||||
|
|
||||||
// memory for our 8 bit control characteristics.
|
// memory for our 8 bit control characteristics.
|
||||||
uint16_t magnetometerDataCharacteristicBuffer[3];
|
int16_t magnetometerDataCharacteristicBuffer[3];
|
||||||
uint16_t magnetometerBearingCharacteristicBuffer;
|
uint16_t magnetometerBearingCharacteristicBuffer;
|
||||||
uint16_t magnetometerPeriodCharacteristicBuffer;
|
uint16_t magnetometerPeriodCharacteristicBuffer;
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,30 @@ class MicroBitPin : public MicroBitComponent
|
||||||
*/
|
*/
|
||||||
int getAnalogValue();
|
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.
|
* 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.
|
* @return 1 if pin is touched, 0 otherwise.
|
||||||
|
|
|
@ -33,6 +33,8 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES
|
||||||
"ble-services/MicroBitLEDService.cpp"
|
"ble-services/MicroBitLEDService.cpp"
|
||||||
"ble-services/MicroBitAccelerometerService.cpp"
|
"ble-services/MicroBitAccelerometerService.cpp"
|
||||||
"ble-services/MicroBitMagnetometerService.cpp"
|
"ble-services/MicroBitMagnetometerService.cpp"
|
||||||
|
"ble-services/MicroBitButtonService.cpp"
|
||||||
|
"ble-services/MicroBitIOPinService.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
if (YOTTA_CFG_MICROBIT_CONFIGFILE)
|
if (YOTTA_CFG_MICROBIT_CONFIGFILE)
|
||||||
|
|
|
@ -129,6 +129,14 @@ void MicroBit::init()
|
||||||
ble_magnetometer_service = new MicroBitMagnetometerService(*ble);
|
ble_magnetometer_service = new MicroBitMagnetometerService(*ble);
|
||||||
#endif
|
#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
|
||||||
|
|
||||||
// Setup advertising.
|
// Setup advertising.
|
||||||
ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
|
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));
|
ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)MICROBIT_BLE_DEVICE_NAME, sizeof(MICROBIT_BLE_DEVICE_NAME));
|
||||||
|
|
|
@ -40,7 +40,7 @@ MicroBitCompass::MicroBitCompass(uint16_t id, uint16_t address) : average(), sam
|
||||||
average.x = read16(MAG_OFF_X_MSB);
|
average.x = read16(MAG_OFF_X_MSB);
|
||||||
average.y = read16(MAG_OFF_Y_MSB);
|
average.y = read16(MAG_OFF_Y_MSB);
|
||||||
average.z = read16(MAG_OFF_Z_MSB);
|
average.z = read16(MAG_OFF_Z_MSB);
|
||||||
|
|
||||||
if(average.x == 0 && average.y == 0 && average.z == 0)
|
if(average.x == 0 && average.y == 0 && average.z == 0)
|
||||||
status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED;
|
status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED;
|
||||||
|
|
||||||
|
@ -132,6 +132,7 @@ int MicroBitCompass::heading()
|
||||||
{
|
{
|
||||||
if(status & MICROBIT_COMPASS_STATUS_CALIBRATING)
|
if(status & MICROBIT_COMPASS_STATUS_CALIBRATING)
|
||||||
return MICROBIT_COMPASS_IS_CALIBRATING;
|
return MICROBIT_COMPASS_IS_CALIBRATING;
|
||||||
|
|
||||||
else if(!(status & MICROBIT_COMPASS_STATUS_CALIBRATED))
|
else if(!(status & MICROBIT_COMPASS_STATUS_CALIBRATED))
|
||||||
{
|
{
|
||||||
MicroBitEvent(id, MICROBIT_COMPASS_EVT_CAL_REQUIRED);
|
MicroBitEvent(id, MICROBIT_COMPASS_EVT_CAL_REQUIRED);
|
||||||
|
@ -337,7 +338,7 @@ void MicroBitCompass::calibrateEnd()
|
||||||
|
|
||||||
status &= ~MICROBIT_COMPASS_STATUS_CALIBRATING;
|
status &= ~MICROBIT_COMPASS_STATUS_CALIBRATING;
|
||||||
status |= MICROBIT_COMPASS_STATUS_CALIBRATED;
|
status |= MICROBIT_COMPASS_STATUS_CALIBRATED;
|
||||||
|
|
||||||
//Store x, y and z values in persistent storage on the MAG3110
|
//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_LSB, (uint8_t)average.x);
|
||||||
writeCommand(MAG_OFF_X_MSB, (uint8_t)(average.x >> 8));
|
writeCommand(MAG_OFF_X_MSB, (uint8_t)(average.x >> 8));
|
||||||
|
|
|
@ -109,8 +109,6 @@ void MicroBitMessageBus::queueEvent(MicroBitEvent &evt)
|
||||||
// Firstly, process all handler regsitered as URGENT. These pre-empt the queue, and are useful for fast, high priority services.
|
// 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);
|
processingComplete = this->process(evt, MESSAGE_BUS_LISTENER_URGENT);
|
||||||
|
|
||||||
pc.printf("QueueEvent: Queueing: %d\n", !processingComplete);
|
|
||||||
|
|
||||||
if (!processingComplete)
|
if (!processingComplete)
|
||||||
{
|
{
|
||||||
// We need to queue this event for later processing...
|
// We need to queue this event for later processing...
|
||||||
|
|
|
@ -171,6 +171,42 @@ int MicroBitPin::getAnalogValue()
|
||||||
return ((AnalogIn *)pin)->read_u16();
|
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.
|
* 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.
|
* @return 1 if pin is touched, 0 otherwise.
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
/**
|
||||||
|
* 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.updateCharacteristicValue(buttonADataCharacteristicHandle, (const uint8_t *)&buttonADataCharacteristicBuffer, sizeof(buttonADataCharacteristicBuffer));
|
||||||
|
ble.updateCharacteristicValue(buttonBDataCharacteristicHandle, (const 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 (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 (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
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,284 @@
|
||||||
|
/**
|
||||||
|
* 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.updateCharacteristicValue(ioPinServiceADCharacteristicHandle, (const uint8_t *)&ioPinServiceADCharacteristicBuffer, sizeof(ioPinServiceADCharacteristicBuffer));
|
||||||
|
ble.updateCharacteristicValue(ioPinServiceIOCharacteristicHandle, (const uint8_t *)&ioPinServiceIOCharacteristicBuffer, sizeof(ioPinServiceIOCharacteristicBuffer));
|
||||||
|
|
||||||
|
ble.onDataWritten(this, &MicroBitIOPinService::onDataWritten);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.updateCharacteristicValue(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.updateCharacteristicValue(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.updateCharacteristicValue(ioPinServiceDataCharacteristic->getValueHandle(), (uint8_t *)&ioPinServiceDataCharacteristic, 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 *)&ioPinServiceDataCharacteristic, 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,0x58,0x99,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t MicroBitIOPinServiceADConfigurationUUID[] = {
|
||||||
|
0xe9,0x5d,0x8d,0x00,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t MicroBitIOPinServiceDataUUID[] = {
|
||||||
|
0xe9,0x5d,0xc5,0x8c,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
|
||||||
|
};
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,6 @@ const uint8_t MicroBitMagnetometerServiceDataUUID[] = {
|
||||||
0xe9,0x5d,0xfb,0x11,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
0xe9,0x5d,0xfb,0x11,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const uint8_t MicroBitMagnetometerServicePeriodUUID[] = {
|
const uint8_t MicroBitMagnetometerServicePeriodUUID[] = {
|
||||||
0xe9,0x5d,0x38,0x6c,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
0xe9,0x5d,0x38,0x6c,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue