Merge lancaster-university/master and silence warnings.

This commit is contained in:
Robert May 2016-01-13 20:51:49 +01:00
commit 098a2378e3
38 changed files with 3153 additions and 1363 deletions

View file

@ -56,9 +56,12 @@ Either (1) the client does not possess the flash code and therefore must somehow
Stage 1 - Client Does Not Possess flash code
------------------------------------------
MicroBit has a special mode of operation or state known currently as "Blue Zone". The device enters this state when rebooted by pressing the reset button whilst at the same time holding down both buttons A and B. The device indicates itself to be in the Blue Zone mode by scrolling "BLUEZONE" across the display.
MicroBit has a special mode of operation or state known currently as "Pairing
Mode". The device enters this state when rebooted by pressing the reset button
whilst at the same time holding down both buttons A and B. The device
indicates itself to be in the pairing mode by scrolling "PAIRING MODE!" across the display.
Once in the Blue Zone state, the MicroBit DFU Service also enables another command via the ControlPoint characteristic known as 'REQUEST_FLASHCODE' which is represented by a value of 0x02.
Once in the pairin mode state, the MicroBit DFU Service also enables another command via the ControlPoint characteristic known as 'REQUEST_FLASHCODE' which is represented by a value of 0x02.
To obtain the flash code the client should enable GATT notifications on the FlashCode characteristic and then write 0x02 to the Control characteristic. The micro:bit will respond by displaying "PAIR?" on the LED display.
@ -66,7 +69,12 @@ The user must now press Button A on the micro:bit. This is an "authorization to
Stage 2 - Client in Possession of flash code
-------------------------------------------
If a device already knows the flashcode, it can connect any time and initiate rebooting into "Nordic DFU mode" by writing the FlashCode characteristic with the previously cached value and then writing the 'ENTER NORDIC BOOTLOADER' command (0x01) to the Control characteristic. The device will reboot into the stock nordic bootloader and then the attached device can interact with that to reflash the device. The device does NOT need to be in Blue Zone mode.
If a device already knows the flashcode, it can connect any time and initiate
rebooting into "Nordic DFU mode" by writing the FlashCode characteristic with
the previously cached value and then writing the 'ENTER NORDIC BOOTLOADER'
command (0x01) to the Control characteristic. The device will reboot into the
stock nordic bootloader and then the attached device can interact with that to
reflash the device. The device does NOT need to be in pairing mode.
Issues for Client Application Developers
----------------------------------------
@ -80,14 +88,16 @@ micro:bit human identifiers
---------------------------
In addition to a secret key (flash code) used in the FOTA process as described, micro:bits have a human readable identifier (public name) which is included in BLE advertising packets and can be discovered and used by human users during any process, including FOTA, where there needs to be a confirmation that the device which is to be interacted with is the one the human intends to interact with. In the context of this document, "interact with" means update using the FOTA procedure.
The public name is generated by the run time from the other half of the Nordic serial number. Humans can discover the public name of a device by switching into BLUEZONE mode. The public name is displayed in a coded but simple graphical form on the LED display and can then be entered into (say) a mobile application screen to verify the device to be updated is the one we mean to update.
The public name is generated by the run time from the other half of the Nordic
serial number. Humans can discover the public name of a device by switching
into pairing mode mode. The public name is displayed in a coded but simple graphical form on the LED display and can then be entered into (say) a mobile application screen to verify the device to be updated is the one we mean to update.
Summary of the FOTA Process
---------------------------
Case 1 - Client does not know the flash code
--------------------------------------------
a) User switches micro:bit into BLUEZONE mode - must do this first since it involves a reboot and will therefore disconnect the client
a) User switches micro:bit into pairing mode - must do this first since it involves a reboot and will therefore disconnect the client
b) Client connects to micro:bit
c) Client discovers MicroBit DFU service
d) Client enables notifications on the MicroBit DFU Service::FlashCode characteristic

View file

@ -4,7 +4,7 @@
#define MICROBIT_DYNAMIC_PWM_H
#define NO_PWMS 3
#define MICROBIT_DISPLAY_PWM_PERIOD 1000
#define MICROBIT_DEFAULT_PWM_PERIOD 20000
enum PwmPersistence
{
@ -15,28 +15,30 @@ enum PwmPersistence
/**
* Class definition for DynamicPwm.
*
* This class addresses a few issues found in the underlying libraries.
* This class addresses a few issues found in the underlying libraries.
* This provides the ability for a neat, clean swap between PWM channels.
*/
class DynamicPwm : public PwmOut
{
private:
private:
static DynamicPwm* pwms[NO_PWMS];
static uint8_t lastUsed;
static uint16_t sharedPeriod;
uint8_t flags;
float lastValue;
/**
* An internal constructor used when allocating a new DynamicPwm representation
* @param pin the name of the pin for the pwm to target
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
* or PWM_PERSISTENCE_TRANSIENT (can be replaced at any point if a channel is required.)
* @param period the frequency of the pwm channel in us.
*/
DynamicPwm(PinName pin, PwmPersistence persistence = PWM_PERSISTENCE_TRANSIENT, int period = MICROBIT_DISPLAY_PWM_PERIOD);
public:
DynamicPwm(PinName pin, PwmPersistence persistence = PWM_PERSISTENCE_TRANSIENT);
public:
/**
* Redirects the pwm channel to point at a different pin.
* @param pin the new pin to direct PWM at.
@ -48,12 +50,12 @@ class DynamicPwm : public PwmOut
* @endcode
*/
void redirect(PinName pin);
/**
* Retrieves a pointer to the first available free pwm channel - or the first one that can be reallocated.
* @param pin the name of the pin for the pwm to target
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
* @param persistance the level of persistence for this pin PWM_PERSISTENCE_PERSISTENT (can not be replaced until freed, should only be used for system services really.)
* or PWM_PERSISTENCE_TRANSIENT (can be replaced at any point if a channel is required.)
* @param period the frequency of the pwm channel in us.
*
@ -62,8 +64,8 @@ class DynamicPwm : public PwmOut
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
* @endcode
*/
static DynamicPwm* allocate(PinName pin, PwmPersistence persistence = PWM_PERSISTENCE_TRANSIENT, int period = MICROBIT_DISPLAY_PWM_PERIOD);
static DynamicPwm* allocate(PinName pin, PwmPersistence persistence = PWM_PERSISTENCE_TRANSIENT);
/**
* Frees this DynamicPwm instance if the pointer is valid.
*
@ -74,31 +76,95 @@ class DynamicPwm : public PwmOut
* @endcode
*/
void release();
/**
* A lightweight wrapper around the super class' write in order to capture the value
*
* @param value the duty cycle percentage in floating point format.
*
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
*
* Example:
* @code
* DynamicPwm* pwm = DynamicPwm::allocate();
* pwm->write(0.5);
* @endcode
*/
int write(float value);
/**
* Retreives the pin name associated with this DynamicPwm instance.
*
* Example:
* @code
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
* pwm->getPinName(); // equal to n
* pwm->getPinName();
* @endcode
*/
PinName getPinName();
/**
* Retreives the last value that has been written to this pwm channel.
*
* Example:
* @code
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
* pwm->getPeriod();
* @endcode
*/
int getValue();
/**
* Retreives the current period in use by the entire PWM module in microseconds.
*
* Example:
* @code
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
* pwm->getPeriod();
* @endcode
*/
int getPeriodUs();
/**
* Retreives the current period in use by the entire PWM module in milliseconds.
*
* Example:
* @code
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
* pwm->getPeriod();
* @endcode
*/
int getPeriod();
/**
* Sets the period used by the WHOLE PWM module. Any changes to the period will AFFECT ALL CHANNELS.
*
* @param period the desired period in microseconds.
*
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
*
* Example:
* @code
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
* pwm->setPeriodUs(1000); // period now is 1ms
* @endcode
*
* @note The display uses the pwm module, if you change this value the display may flicker.
*/
void setPeriodUs(int period);
int setPeriodUs(int period);
/**
* Sets the period used by the WHOLE PWM module. Any changes to the period will AFFECT ALL CHANNELS.
*
* @param period the desired period in milliseconds.
*
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range
*
* Example:
* @code
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
* pwm->setPeriod(1); // period now is 1ms
* @endcode
*/
int setPeriod(int period);
};
#endif

View file

@ -9,74 +9,63 @@
// Events that master devices respond to:
//
#define MES_REMOTE_CONTROL_ID 1001
#define MES_REMOTE_CONTROL_EVT_PLAY 0
#define MES_REMOTE_CONTROL_EVT_PAUSE 1
#define MES_REMOTE_CONTROL_EVT_STOP 2
#define MES_REMOTE_CONTROL_EVT_NEXTTRACK 3
#define MES_REMOTE_CONTROL_EVT_PREVTRACK 4
#define MES_REMOTE_CONTROL_EVT_FORWARD 5
#define MES_REMOTE_CONTROL_EVT_REWIND 6
#define MES_REMOTE_CONTROL_EVT_VOLUMEUP 7
#define MES_REMOTE_CONTROL_EVT_VOLUMEDOWN 8
#define MES_REMOTE_CONTROL_EVT_PLAY 1
#define MES_REMOTE_CONTROL_EVT_PAUSE 2
#define MES_REMOTE_CONTROL_EVT_STOP 3
#define MES_REMOTE_CONTROL_EVT_NEXTTRACK 4
#define MES_REMOTE_CONTROL_EVT_PREVTRACK 5
#define MES_REMOTE_CONTROL_EVT_FORWARD 6
#define MES_REMOTE_CONTROL_EVT_REWIND 7
#define MES_REMOTE_CONTROL_EVT_VOLUMEUP 8
#define MES_REMOTE_CONTROL_EVT_VOLUMEDOWN 9
#define MES_CAMERA_ID 1002
#define MES_CAMERA_EVT_LAUNCH_PHOTO_MODE 0
#define MES_CAMERA_EVT_LAUNCH_VIDEO_MODE 1
#define MES_CAMERA_EVT_TAKE_PHOTO 2
#define MES_CAMERA_EVT_START_VIDEO_CAPTURE 3
#define MES_CAMERA_EVT_STOP_VIDEO_CAPTURE 4
#define MES_CAMERA_EVT_STOP_PHOTO_MODE 5
#define MES_CAMERA_EVT_STOP_VIDEO_MODE 6
#define MES_CAMERA_EVT_TOGGLE_FRONT_REAR 7
#define MES_AUDIO_RECORDER_ID 1003
#define MES_AUDIO_RECORDER_EVT_LAUNCH 0
#define MES_AUDIO_RECORDER_EVT_START_CAPTURE 1
#define MES_AUDIO_RECORDER_EVT_STOP_CAPTURE 2
#define MES_AUDIO_RECORDER_EVT_STOP 3
#define MES_CAMERA_EVT_LAUNCH_PHOTO_MODE 1
#define MES_CAMERA_EVT_LAUNCH_VIDEO_MODE 2
#define MES_CAMERA_EVT_TAKE_PHOTO 3
#define MES_CAMERA_EVT_START_VIDEO_CAPTURE 4
#define MES_CAMERA_EVT_STOP_VIDEO_CAPTURE 5
#define MES_CAMERA_EVT_STOP_PHOTO_MODE 6
#define MES_CAMERA_EVT_STOP_VIDEO_MODE 7
#define MES_CAMERA_EVT_TOGGLE_FRONT_REAR 8
#define MES_ALERTS_ID 1004
#define MES_ALERT_EVT_DISPLAY_TOAST 0
#define MES_ALERT_EVT_VIBRATE 1
#define MES_ALERT_EVT_PLAY_SOUND 2
#define MES_ALERT_EVT_PLAY_RINGTONE 3
#define MES_ALERT_EVT_FIND_MY_PHONE 4
#define MES_ALERT_EVT_ALARM1 5
#define MES_ALERT_EVT_ALARM2 6
#define MES_ALERT_EVT_ALARM3 7
#define MES_ALERT_EVT_ALARM4 8
#define MES_ALERT_EVT_ALARM5 9
#define MES_ALERT_EVT_ALARM6 10
// TODO Multiple DISPLAY_TOAST event values
#define MES_ALERT_EVT_DISPLAY_TOAST 1
#define MES_ALERT_EVT_VIBRATE 2
// TODO PLAY_SOUND and ALARMN to be combined
#define MES_ALERT_EVT_PLAY_SOUND 3
#define MES_ALERT_EVT_PLAY_RINGTONE 4
#define MES_ALERT_EVT_FIND_MY_PHONE 5
#define MES_ALERT_EVT_ALARM1 6
#define MES_ALERT_EVT_ALARM2 7
#define MES_ALERT_EVT_ALARM3 8
#define MES_ALERT_EVT_ALARM4 9
#define MES_ALERT_EVT_ALARM5 10
#define MES_ALERT_EVT_ALARM6 11
//
// Events that master devices generate:
//
#define MES_SIGNAL_STRENGTH_ID 1101
#define MES_SIGNAL_STRENGTH_EVT_NO_BAR 0
#define MES_SIGNAL_STRENGTH_EVT_ONE_BAR 1
#define MES_SIGNAL_STRENGTH_EVT_TWO_BAR 2
#define MES_SIGNAL_STRENGTH_EVT_THREE_BAR 3
#define MES_SIGNAL_STRENGTH_EVT_FOUR_BAR 4
#define MES_SIGNAL_STRENGTH_EVT_NO_BAR 1
#define MES_SIGNAL_STRENGTH_EVT_ONE_BAR 2
#define MES_SIGNAL_STRENGTH_EVT_TWO_BAR 3
#define MES_SIGNAL_STRENGTH_EVT_THREE_BAR 4
#define MES_SIGNAL_STRENGTH_EVT_FOUR_BAR 5
#define MES_PLAY_CONTROLLER_ID 1102
#define MES_BUTTON_UP 0
#define MES_BUTTON_DOWN 1
#define MES_BUTTON_RIGHT 2
#define MES_BUTTON_LEFT 3
#define MES_BUTTON_A 4
#define MES_BUTTON_B 5
#define MES_BUTTON_C 6
#define MES_BUTTON_D 7
#define MES_DEVICE_INFO_ID 1103
#define MES_DEVICE_ORIENTATION_LANDSCAPE 0
#define MES_DEVICE_ORIENTATION_PORTRAIT 1
#define MES_DEVICE_GESTURE_NONE 2
#define MES_DEVICE_GESTURE_DEVICE_SHAKEN 3
#define MES_DEVICE_DISPLAY_OFF 4
#define MES_DEVICE_DISPLAY_ON 5
#define MES_DEVICE_ORIENTATION_LANDSCAPE 1
#define MES_DEVICE_ORIENTATION_PORTRAIT 2
#define MES_DEVICE_GESTURE_NONE 3
#define MES_DEVICE_GESTURE_DEVICE_SHAKEN 4
#define MES_DEVICE_DISPLAY_OFF 5
#define MES_DEVICE_DISPLAY_ON 6
#define MES_DEVICE_INCOMING_CALL 7
#define MES_DEVICE_INCOMING_MESSAGE 8
#endif

143
inc/Matrix4.h Normal file
View file

@ -0,0 +1,143 @@
#ifndef MICROBIT_MATRIX4_H
#define MICROBIT_MATRIX4_H
/**
* Class definition for a simple matrix, that is optimised for nx4 or 4xn matrices.
*
* This class is heavily optimised for these commonly used matrices as used in 3D geometry.
* Whilst this class does support basic operations on matrices of any dimension, it is not intended as a
* general purpose matrix class as inversion operations are only provided for 4x4 matrices.
* For programmers needing more flexible Matrix support, the Matrix and MatrixMath classes from
* Ernsesto Palacios provide a good basis:
*
* https://developer.mbed.org/cookbook/MatrixClass
* https://developer.mbed.org/users/Yo_Robot/code/MatrixMath/
*/
class Matrix4
{
double *data; // Linear buffer representing the matrix.
int rows; // The number of rows in the matrix.
int cols; // The number of columns in the matrix.
public:
/**
* Constructor.
* Create a matrix of the given size.
* @param rows the number of rows in the matrix to be created.
* @param cols the number of columns in the matrix to be created.
*
* Example:
* @code
* Matrix4(10, 4); // Creates a Matrix with 10 rows and 4 columns.
* @endcode
*/
Matrix4(int rows, int cols);
/**
* Constructor.
* Create a matrix that is an identical copy of the given matrix.
* @param matrix The matrix to copy.
*
* Example:
* @code
*
* Matrix newMatrix(matrix); .
* @endcode
*/
Matrix4(const Matrix4 &matrix);
/**
* Determines the number of columns in this matrix.
*
* @return The number of columns in the matrix.
*
* Example:
* @code
* int c = matrix.width();
* @endcode
*/
int width();
/**
* Determines the number of rows in this matrix.
*
* @return The number of rows in the matrix.
*
* Example:
* @code
* int r = matrix.height();
* @endcode
*/
int height();
/**
* Reads the matrix element at the given position.
*
* @param row The row of the element to read
* @param col The column of the element to read
* @return The value of the matrix element at the given position. NAN is returned if the given index is out of range.
*
* Example:
* @code
* double v = matrix.get(1,2);
* @endcode
*/
double get(int row, int col);
/**
* Writes the matrix element at the given position.
*
* @param row The row of the element to write
* @param col The column of the element to write
* @param v The new value of the element
*
* Example:
* @code
* matrix.set(1,2,42.0);
* @endcode
*/
void set(int row, int col, double v);
/**
* Transposes this matrix.
* @return the resultant matrix.
*
* Example:
* @code
* matrix.transpose();
* @endcode
*/
Matrix4 transpose();
/**
* Multiplies this matrix with the given matrix (if possible).
* @return the resultant matrix. An empty matrix is returned if the operation canot be completed.
*
* Example:
* @code
* Matrix result = matrixA.multiply(matrixB);
* @endcode
*/
Matrix4 multiply(Matrix4 &matrix);
/**
* Performs an optimisaed inversion of a 4x4 matrix.
* Only 4x4 matrics are supported by this operation.
*
* @return the resultant matrix. An empty matrix is returned if the operation canot be completed.
*
* Example:
* @code
* Matrix result = matrixA.invert();
* @endcode
*/
Matrix4 invert();
/**
* Destructor.
*/
~Matrix4();
};
#endif

View file

@ -3,15 +3,16 @@
#include "mbed.h"
#include "MicroBitConfig.h"
#include "MicroBitConfig.h"
#include "MicroBitHeapAllocator.h"
#include "MicroBitPanic.h"
#include "ErrorNo.h"
#include "Matrix4.h"
#include "MicroBitCompat.h"
#include "MicroBitComponent.h"
#include "ManagedType.h"
#include "ManagedString.h"
#include "MicroBitImage.h"
#include "MicroBitImage.h"
#include "MicroBitFont.h"
#include "MicroBitEvent.h"
#include "DynamicPwm.h"
@ -32,35 +33,7 @@
#include "MicroBitFiber.h"
#include "MicroBitMessageBus.h"
/*
* The underlying Nordic libraries that support BLE do not compile cleanly with the stringent GCC settings we employ
* If we're compiling under GCC, then we suppress any warnings generated from this code (but not the rest of the DAL)
* The ARM cc compiler is more tolerant. We don't test __GNUC__ here to detect GCC as ARMCC also typically sets this
* as a compatability option, but does not support the options used...
*/
#if !defined (__arm)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include "ble/BLE.h"
/*
* Return to our predefined compiler settings.
*/
#if !defined (__arm)
#pragma GCC diagnostic pop
#endif
#include "ble/services/DeviceInformationService.h"
#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"
#include "MicroBitBLEManager.h"
// MicroBit::flags values
#define MICROBIT_FLAG_SCHEDULER_RUNNING 0x00000001
@ -86,14 +59,16 @@
* Represents the device as a whole, and includes member variables to that reflect the components of the system.
*/
class MicroBit
{
{
private:
void seedRandom();
void compassCalibrator(MicroBitEvent e);
uint32_t randomValue;
public:
// Map of device state.
uint32_t flags;
@ -101,43 +76,43 @@ class MicroBit
Ticker systemTicker;
// I2C Interface
MicroBitI2C i2c;
MicroBitI2C i2c;
// Serial Interface
MicroBitSerial serial;
MicroBitSerial serial;
// Array of components which are iterated during a system tick
MicroBitComponent* systemTickComponents[MICROBIT_SYSTEM_COMPONENTS];
// Array of components which are iterated during idle thread execution, isIdleCallbackNeeded is polled during a systemTick.
MicroBitComponent* idleThreadComponents[MICROBIT_IDLE_COMPONENTS];
// Device level Message Bus abstraction
MicroBitMessageBus MessageBus;
MicroBitMessageBus MessageBus;
// Member variables to represent each of the core components on the device.
MicroBitDisplay display;
MicroBitButton buttonA;
MicroBitButton buttonB;
MicroBitMultiButton buttonAB;
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;
MicroBitBLEManager bleManager;
BLEDevice *ble;
/**
* Constructor.
* Constructor.
* Create a representation of a MicroBit device as a global singleton.
* @param messageBus callback function to receive MicroBitMessageBus events.
*
* Exposed objects:
* @code
* @code
* uBit.systemTicker; //the Ticker callback that performs routines like updating the display.
* uBit.MessageBus; //The message bus where events are fired.
* uBit.display; //The display object for the LED matrix.
@ -149,26 +124,21 @@ class MicroBit
* uBit.io.P*; //Where P* is P0 to P16, P19 & P20 on the edge connector
* @endcode
*/
MicroBit();
MicroBit();
/**
* Post constructor initialisation method.
* After *MUCH* pain, it's noted that the BLE stack can't be brought up in a
* After *MUCH* pain, it's noted that the BLE stack can't be brought up in a
* static context, so we bring it up here rather than in the constructor.
* n.b. This method *must* be called in main() or later, not before.
*
* Example:
* @code
* @code
* uBit.init();
* @endcode
*/
void init();
/**
* Derives the friendly name for this device, autogenerated from our hardware Device ID.
*/
void deriveName();
/**
* Return the friendly name for this device.
*
@ -187,7 +157,7 @@ class MicroBit
* Will reset the micro:bit when called.
*
* Example:
* @code
* @code
* uBit.reset();
* @endcode
*/
@ -198,15 +168,15 @@ class MicroBit
* If the scheduler is running, this will deschedule the current fiber and perform
* a power efficent, concurrent sleep operation.
* If the scheduler is disabled or we're running in an interrupt context, this
* will revert to a busy wait.
*
* will revert to a busy wait.
*
* @note Values of 6 and below tend to lose resolution - do you really need to sleep for this short amount of time?
*
* @param milliseconds the amount of time, in ms, to wait for. This number cannot be negative.
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER milliseconds is less than zero.
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER milliseconds is less than zero.
*
* Example:
* @code
* @code
* uBit.sleep(20); //sleep for 20ms
* @endcode
*/
@ -221,7 +191,7 @@ class MicroBit
* @return A random, natural number between 0 and the max-1. Or MICROBIT_INVALID_PARAMETER if max is <= 0.
*
* Example:
* @code
* @code
* uBit.random(200); //a number between 0 and 199
* @endcode
*/
@ -232,27 +202,27 @@ class MicroBit
* provide a power efficient sense of time.
*/
void systemTick();
/**
* System tasks to be executed by the idle thread when the Micro:Bit isn't busy or when data needs to be read.
*/
void systemTasks();
/**
* add a component to the array of system components which invocate the systemTick member function during a systemTick
* add a component to the array of system components which invocate the systemTick member function during a systemTick
*
* @param component The component to add.
* @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported.
*/
int addSystemComponent(MicroBitComponent *component);
/**
* remove a component from the array of system components
* @param component The component to remove.
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previous added.
*/
int removeSystemComponent(MicroBitComponent *component);
/**
* add a component to the array of of idle thread components.
* isIdleCallbackNeeded is polled during a systemTick to determine if the idle thread should jump to the front of the queue
@ -260,7 +230,7 @@ class MicroBit
* @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported.
*/
int addIdleComponent(MicroBitComponent *component);
/**
* remove a component from the array of idle thread components
* @param component The component to remove.
@ -275,7 +245,7 @@ class MicroBit
* TODO: handle overflow case.
*/
unsigned long systemTime();
/**
* Determine the version of the micro:bit runtime currently in use.
*
@ -286,7 +256,7 @@ class MicroBit
/**
* Triggers a microbit panic where an infinite loop will occur swapping between the panicFace and statusCode if provided.
*
*
* @param statusCode the status code of the associated error. Status codes must be in the range 0-255.
*/
void panic(int statusCode = 0);
@ -298,16 +268,9 @@ class MicroBit
// code integration a little bit easier for third parties.
extern MicroBit uBit;
//
// BLE callback when an active GATT session with another device is terminated.
// Used to reset state and restart advertising ourselves.
//
void bleDisconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason);
// Entry point for application programs. Called after the super-main function
// has initialized the device and runtime environment.
extern "C" void app_main();
#endif

View file

@ -3,12 +3,18 @@
#include "mbed.h"
#include "MicroBitComponent.h"
#include "MicroBitCoordinateSystem.h"
/**
* Relevant pin assignments
*/
* Relevant pin assignments
*/
#define MICROBIT_PIN_ACCEL_DATA_READY P0_28
/**
* Status flags
*/
#define MICROBIT_ACCEL_PITCH_ROLL_VALID 0x01
/*
* I2C constants
*/
@ -29,8 +35,8 @@
/**
* MMA8653 constants
*/
* MMA8653 constants
*/
#define MMA8653_WHOAMI_VAL 0x5A
#define MMA8653_SAMPLE_RANGES 3
@ -39,7 +45,42 @@
/*
* Accelerometer events
*/
#define MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE 1
#define MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE 1
/*
* Gesture events
*/
#define MICROBIT_ACCELEROMETER_EVT_TILT_UP 1
#define MICROBIT_ACCELEROMETER_EVT_TILT_DOWN 2
#define MICROBIT_ACCELEROMETER_EVT_TILT_LEFT 3
#define MICROBIT_ACCELEROMETER_EVT_TILT_RIGHT 4
#define MICROBIT_ACCELEROMETER_EVT_FACE_UP 5
#define MICROBIT_ACCELEROMETER_EVT_FACE_DOWN 6
#define MICROBIT_ACCELEROMETER_EVT_FREEFALL 7
#define MICROBIT_ACCELEROMETER_EVT_3G 8
#define MICROBIT_ACCELEROMETER_EVT_6G 9
#define MICROBIT_ACCELEROMETER_EVT_8G 10
#define MICROBIT_ACCELEROMETER_EVT_SHAKE 11
/*
* Gesture recogniser constants
*/
#define MICROBIT_ACCELEROMETER_REST_TOLERANCE 200
#define MICROBIT_ACCELEROMETER_TILT_TOLERANCE 200
#define MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE 400
#define MICROBIT_ACCELEROMETER_SHAKE_TOLERANCE 1000
#define MICROBIT_ACCELEROMETER_3G_TOLERANCE 3072
#define MICROBIT_ACCELEROMETER_6G_TOLERANCE 6144
#define MICROBIT_ACCELEROMETER_8G_TOLERANCE 8192
#define MICROBIT_ACCELEROMETER_GESTURE_DAMPING 10
#define MICROBIT_ACCELEROMETER_SHAKE_DAMPING 10
#define MICROBIT_ACCELEROMETER_REST_THRESHOLD (MICROBIT_ACCELEROMETER_REST_TOLERANCE * MICROBIT_ACCELEROMETER_REST_TOLERANCE)
#define MICROBIT_ACCELEROMETER_FREEFALL_THRESHOLD (MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE * MICROBIT_ACCELEROMETER_FREEFALL_TOLERANCE)
#define MICROBIT_ACCELEROMETER_3G_THRESHOLD (MICROBIT_ACCELEROMETER_3G_TOLERANCE * MICROBIT_ACCELEROMETER_3G_TOLERANCE)
#define MICROBIT_ACCELEROMETER_6G_THRESHOLD (MICROBIT_ACCELEROMETER_6G_TOLERANCE * MICROBIT_ACCELEROMETER_6G_TOLERANCE)
#define MICROBIT_ACCELEROMETER_8G_THRESHOLD (MICROBIT_ACCELEROMETER_8G_TOLERANCE * MICROBIT_ACCELEROMETER_8G_TOLERANCE)
#define MICROBIT_ACCELEROMETER_SHAKE_COUNT_THRESHOLD 4
struct MMA8653Sample
{
@ -60,43 +101,76 @@ struct MMA8653SampleRangeConfig
uint8_t xyz_data_cfg;
};
extern const MMA8653SampleRangeConfig MMA8653SampleRange[];
extern const MMA8653SampleRateConfig MMA8653SampleRate[];
enum BasicGesture
{
GESTURE_NONE,
GESTURE_UP,
GESTURE_DOWN,
GESTURE_LEFT,
GESTURE_RIGHT,
GESTURE_FACE_UP,
GESTURE_FACE_DOWN,
GESTURE_FREEFALL,
GESTURE_3G,
GESTURE_6G,
GESTURE_8G,
GESTURE_SHAKE
};
struct ShakeHistory
{
uint16_t shaken:1,
x:1,
y:1,
z:1,
count:4,
timer:8;
};
/**
* Class definition for MicroBit Accelerometer.
*
* Represents an implementation of the Freescale MMA8653 3 axis accelerometer
* Also includes basic data caching and on demand activation.
*/
* Class definition for MicroBit Accelerometer.
*
* Represents an implementation of the Freescale MMA8653 3 axis accelerometer
* Also includes basic data caching and on demand activation.
*/
class MicroBitAccelerometer : public MicroBitComponent
{
/**
* Unique, enumerated ID for this component.
* Unique, enumerated ID for this component.
* Used to track asynchronous events in the event bus.
*/
uint16_t address; // I2C address of this accelerometer.
uint16_t samplePeriod; // The time between samples, in milliseconds.
uint8_t sampleRange; // The sample range of the accelerometer in g.
MMA8653Sample sample; // The last sample read.
DigitalIn int1; // Data ready interrupt.
uint16_t address; // I2C address of this accelerometer.
uint16_t samplePeriod; // The time between samples, in milliseconds.
uint8_t sampleRange; // The sample range of the accelerometer in g.
MMA8653Sample sample; // The last sample read.
DigitalIn int1; // Data ready interrupt.
float pitch; // Pitch of the device, in radians.
float roll; // Roll of the device, in radians.
uint8_t sigma; // the number of ticks that the instantaneous gesture has been stable.
BasicGesture lastGesture; // the last, stable gesture recorded.
BasicGesture currentGesture; // the instantaneous, unfiltered gesture detected.
ShakeHistory shake; // State information needed to detect shake events.
public:
/**
* Constructor.
* Create an accelerometer representation with the given ID.
* @param id the ID of the new object.
* @param address the default base address of the accelerometer.
*
* Example:
* @code
* accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR)
* @endcode
*/
* Constructor.
* Create an accelerometer representation with the given ID.
* @param id the ID of the new object.
* @param address the default base address of the accelerometer.
*
* Example:
* @code
* accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR)
* @endcode
*/
MicroBitAccelerometer(uint16_t id, uint16_t address);
/**
* Configures the accelerometer for G range and sample rate defined
* in this object. The nearest values are chosen to those defined
@ -108,26 +182,26 @@ class MicroBitAccelerometer : public MicroBitComponent
int configure();
/**
* Reads the acceleration data from the accelerometer, and stores it in our buffer.
* This is called by the tick() member function, if the interrupt is set.
*
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the read request fails.
*/
* Reads the acceleration data from the accelerometer, and stores it in our buffer.
* This is called by the tick() member function, if the interrupt is set.
*
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the read request fails.
*/
int update();
/**
* Attempts to set the sample rate of the accelerometer 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.
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
*/
* Attempts to set the sample rate of the accelerometer 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.
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
*/
int setPeriod(int period);
/**
* Reads the currently configured sample rate of the accelerometer.
* @return The time between samples, in milliseconds.
*/
* Reads the currently configured sample rate of the accelerometer.
* @return The time between samples, in milliseconds.
*/
int getPeriod();
/**
@ -140,90 +214,157 @@ class MicroBitAccelerometer : public MicroBitComponent
int setRange(int range);
/**
* Reads the currently configured sample range of the accelerometer.
* Reads the currently configured sample range of the accelerometer.
* @return The sample range, in g.
*/
int getRange();
/**
* Attempts to determine the 8 bit ID from the accelerometer.
* @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
*
* Example:
* @code
* uBit.accelerometer.whoAmI();
* @endcode
*/
* Attempts to determine the 8 bit ID from the accelerometer.
* @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
*
* Example:
* @code
* uBit.accelerometer.whoAmI();
* @endcode
*/
int whoAmI();
/**
* Reads the X axis value of the latest update from the accelerometer.
* Currently limited to +/- 2g
* @param system The coordinate system to use. By default, a simple cartesian system is provided.
* @return The force measured in the X axis, in milli-g.
*
* Example:
* @code
* @code
* uBit.accelerometer.getX();
* @endcode
*/
int getX();
int getX(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
/**
* Reads the Y axis value of the latest update from the accelerometer.
* Currently limited to +/- 2g
* @return The force measured in the Y axis, in milli-g.
*
* Example:
* @code
* @code
* uBit.accelerometer.getY();
* @endcode
*/
int getY();
*/
int getY(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
/**
* Reads the Z axis value of the latest update from the accelerometer.
* Currently limited to +/- 2g
* @return The force measured in the Z axis, in milli-g.
*
* Example:
* @code
* @code
* uBit.accelerometer.getZ();
* @endcode
*/
int getZ();
*/
int getZ(MicroBitCoordinateSystem system = SIMPLE_CARTESIAN);
/**
* periodic callback from MicroBit idle thread.
* Check if any data is ready for reading by checking the interrupt flag on the accelerometer
*/
virtual void idleTick();
/**
* Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read.
* Provides a rotation compensated pitch of the device, based on the latest update from the accelerometer.
* @return The pitch of the device, in degrees.
*
* Example:
* @code
* uBit.accelerometer.getPitch();
* @endcode
*/
int getPitch();
float getPitchRadians();
/**
* Provides a rotation compensated roll of the device, based on the latest update from the accelerometer.
* @return The roll of the device, in degrees.
*
* Example:
* @code
* uBit.accelerometer.getRoll();
* @endcode
*/
int getRoll();
float getRollRadians();
/**
* Reads the last recorded gesture detected.
* @return The last gesture detected.
*
* Example:
* @code
* if (uBit.accelerometer.getGesture() == SHAKE)
* @endcode
*/
BasicGesture getGesture();
/**
* periodic callback from MicroBit idle thread.
* Check if any data is ready for reading by checking the interrupt flag on the accelerometer
*/
virtual void idleTick();
/**
* Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read.
*/
virtual int isIdleCallbackNeeded();
/**
* Destructor for MicroBitButton, so that we deregister ourselves as an idleComponent
*/
~MicroBitAccelerometer();
private:
/**
* Issues a standard, 2 byte I2C command write to the accelerometer.
* Blocks the calling thread until complete.
*
* @param reg The address of the register to write to.
* @param value The value to write.
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
*/
* Issues a standard, 2 byte I2C command write to the accelerometer.
* Blocks the calling thread until complete.
*
* @param reg The address of the register to write to.
* @param value The value to write.
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the the write request failed.
*/
int writeCommand(uint8_t reg, uint8_t value);
/**
* Issues a read command into the specified buffer.
* Blocks the calling thread until complete.
*
* @param reg The address of the register to access.
* @param buffer Memory area to read the data into.
* @param length The number of bytes to read.
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
*/
* Issues a read command into the specified buffer.
* Blocks the calling thread until complete.
*
* @param reg The address of the register to access.
* @param buffer Memory area to read the data into.
* @param length The number of bytes to read.
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER or MICROBIT_I2C_ERROR if the the read request failed.
*/
int readCommand(uint8_t reg, uint8_t* buffer, int length);
/**
* Recalculate roll and pitch values for the current sample.
* We only do this at most once per sample, as the necessary trigonemteric functions are rather
* heavyweight for a CPU without a floating point unit...
*/
void recalculatePitchRoll();
/**
*
* Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote
* stability.
*/
void updateGesture();
/**
* Service function. Calculates the current scalar acceleration of the device (x^2 + y^2 + z^2).
* It does not, however, square root the result, as this is a relatively high cost operation.
* This is left to application code should it be needed.
* @return the sum of the square of the acceleration of the device across all axes.
*/
int instantaneousAccelerationSquared();
/**
* Service function. Determines the best guess posture of the device based on instantaneous data.
* This makes no use of historic data, and forms this input to th filter implemented in updateGesture().
* @return A best guess of the curret posture of the device, based on instanataneous data.
*/
BasicGesture instantaneousPosture();
};
#endif

116
inc/MicroBitBLEManager.h Normal file
View file

@ -0,0 +1,116 @@
#ifndef MICROBIT_BLE_MANAGER_H
#define MICROBIT_BLE_MANAGER_H
#include "mbed.h"
/*
* The underlying Nordic libraries that support BLE do not compile cleanly with the stringent GCC settings we employ
* If we're compiling under GCC, then we suppress any warnings generated from this code (but not the rest of the DAL)
* The ARM cc compiler is more tolerant. We don't test __GNUC__ here to detect GCC as ARMCC also typically sets this
* as a compatability option, but does not support the options used...
*/
#if !defined (__arm)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include "ble/BLE.h"
/*
* Return to our predefined compiler settings.
*/
#if !defined (__arm)
#pragma GCC diagnostic pop
#endif
#include "ble/services/DeviceInformationService.h"
#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"
#define MICROBIT_BLE_PAIR_REQUEST 0x01
#define MICROBIT_BLE_PAIR_COMPLETE 0x02
#define MICROBIT_BLE_PAIR_PASSCODE 0x04
#define MICROBIT_BLE_PAIR_SUCCESSFUL 0x08
/**
* Class definition for the MicroBitBLEManager.
*
*/
class MicroBitBLEManager
{
public:
// The mbed abstraction of the BlueTooth Low Energy (BLE) hardware
BLEDevice *ble;
/**
* Constructor.
*
* Configure and manage the micro:bit's Bluetooth Low Energy (BLE) stack.
* Note that the BLE stack *cannot* be brought up in a static context.
* (the software simply hangs or corrupts itself).
* Hence, we bring it up in an explicit init() method, rather than in the constructor.
*/
MicroBitBLEManager();
/**
* Post constructor initialisation method.
* After *MUCH* pain, it's noted that the BLE stack can't be brought up in a
* static context, so we bring it up here rather than in the constructor.
* n.b. This method *must* be called in main() or later, not before.
*
* Example:
* @code
* uBit.init();
* @endcode
*/
void init(ManagedString deviceName, ManagedString serialNumber);
/**
* Enter pairing mode. This is mode is called to initiate pairing, and to enable FOTA programming
* of the micro:bit in cases where BLE is disabled during normal operation.
*
* @param display a MicroBitDisplay to use when displaying pairing information.
*/
void pairingMode(MicroBitDisplay &display);
/**
* Method that is called whenever a BLE device disconnects from us.
* The nordic stack stops dvertising whenever a device connects, so we use
* this callback to restart advertising.
*/
void onDisconnectionCallback();
/**
* Displays the device's ID code as a histogram on the LED matrix display.
*/
void showNameHistogram(MicroBitDisplay &display);
/**
* A request to pair has been received from a BLE device.
* If we're in pairing mode, display the passkey to the user.
*/
void pairingRequested(ManagedString passKey);
/**
* A pairing request has been sucesfully completed.
* If we're in pairing mode, display feedback to the user.
*/
void pairingComplete(bool success);
private:
int pairingStatus;
ManagedString passKey;
ManagedString deviceName;
};
#endif

View file

@ -17,8 +17,8 @@
#define MICROBIT_BUTTON_EVT_HOLD 5
#define MICROBIT_BUTTON_EVT_DOUBLE_CLICK 6
#define MICROBIT_BUTTON_LONG_CLICK_TIME 1000
#define MICROBIT_BUTTON_HOLD_TIME 1500
#define MICROBIT_BUTTON_LONG_CLICK_TIME 1000
#define MICROBIT_BUTTON_HOLD_TIME 1500
#define MICROBIT_BUTTON_STATE 1
#define MICROBIT_BUTTON_STATE_HOLD_TRIGGERED 2
@ -47,27 +47,27 @@ class MicroBitButton : public MicroBitComponent
{
PinName name; // mbed pin name of this pin.
DigitalIn pin; // The mbed object looking after this pin at any point in time (may change!).
unsigned long downStartTime; // used to store the current system clock when a button down event occurs
uint8_t sigma; // integration of samples over time. We use this for debouncing, and noise tolerance for touch sensing
MicroBitButtonEventConfiguration eventConfiguration; // Do we want to generate high level event (clicks), or defer this to another service.
public:
/**
* Constructor.
* Constructor.
* Create a pin representation with the given ID.
* @param id the ID of the new MicroBitButton object.
* @param name the physical pin on the processor that this butotn is connected to.
* @param mode the configuration of internal pullups/pulldowns, as define in the mbed PinMode class. PullNone by default.
*
* Example:
* @code
* @code
* buttonA(MICROBIT_ID_BUTTON_A,MICROBIT_PIN_BUTTON_A); //a number between 0 and 200 inclusive
* @endcode
*
* Possible Events:
* @code
* @code
* MICROBIT_BUTTON_EVT_DOWN
* MICROBIT_BUTTON_EVT_UP
* MICROBIT_BUTTON_EVT_CLICK
@ -77,25 +77,29 @@ class MicroBitButton : public MicroBitComponent
* @endcode
*/
MicroBitButton(uint16_t id, PinName name, MicroBitButtonEventConfiguration eventConfiguration = MICROBIT_BUTTON_ALL_EVENTS, PinMode mode = PullNone);
/**
* Tests if this Button is currently pressed.
* @return 1 if this button is pressed, 0 otherwise.
*
* Example:
* @code
* @code
* if(uBit.buttonA.isPressed())
* print("Pressed!");
* @endcode
*/
int isPressed();
/**
* periodic callback from MicroBit clock.
* Check for state change for this button, and fires a hold event if button is pressed.
*/
*/
virtual void systemTick();
/**
* Destructor for MicroBitButton, so that we deregister ourselves as a systemComponent
*/
~MicroBitButton();
};
#endif

View file

@ -3,6 +3,7 @@
#include "mbed.h"
#include "MicroBitComponent.h"
#include "MicroBitCoordinateSystem.h"
/**
* Relevant pin assignments
@ -47,25 +48,29 @@ struct MAG3110SampleRateConfig
extern const MAG3110SampleRateConfig MAG3110SampleRate[];
#define MAG3110_SAMPLE_RATES 11
#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_CAL_REQUIRED 1 // DEPRECATED
#define MICROBIT_COMPASS_EVT_CAL_START 2 // DEPRECATED
#define MICROBIT_COMPASS_EVT_CAL_END 3 // DEPRECATED
#define MICROBIT_COMPASS_EVT_DATA_UPDATE 4
#define MICROBIT_COMPASS_EVT_CONFIG_NEEDED 5
#define MICROBIT_COMPASS_EVT_CALIBRATE 6
/*
* Status Bits
*/
#define MICROBIT_COMPASS_STATUS_CALIBRATED 1
#define MICROBIT_COMPASS_STATUS_CALIBRATING 2
#define MICROBIT_COMPASS_CALIBRATE_PERIOD 10000
/*
* Term to convert sample data into SI units
*/
#define MAG3110_NORMALIZE_SAMPLE(x) (100*x)
/*
* MAG3110 MAGIC ID value
@ -75,15 +80,22 @@ extern const MAG3110SampleRateConfig MAG3110SampleRate[];