microbit-dal: Initial Commit

This is the first commit of the microbit-dal on GitHub.
This repository contains the runtime, which is a light
weight operating system developed by Lancaster University.
This commit is contained in:
James Devine 2015-08-12 11:53:41 +01:00
commit 538e1c48bd
51 changed files with 9353 additions and 0 deletions

104
inc/DynamicPwm.h Normal file
View file

@ -0,0 +1,104 @@
#include "mbed.h"
#ifndef MICROBIT_DYNAMIC_PWM_H
#define MICROBIT_DYNAMIC_PWM_H
#define NO_PWMS 3
#define MICROBIT_DISPLAY_PWM_PERIOD 1000
enum PwmPersistence
{
PWM_PERSISTENCE_TRANSIENT = 1,
PWM_PERSISTENCE_PERSISTENT = 2,
};
/**
* Class definition for DynamicPwm.
*
* 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:
static DynamicPwm* pwms[NO_PWMS];
static uint8_t lastUsed;
uint8_t flags;
/**
* 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.)
* 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:
/**
* Redirects the pwm channel to point at a different pin.
* @param pin the new pin to direct PWM at.
*
* Example:
* @code
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
* pwm->redirect(PinName n2); // pwm is now produced on n2
* @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.)
* 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.
*
* Example:
* @code
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
* @endcode
*/
static DynamicPwm* allocate(PinName pin, PwmPersistence persistence = PWM_PERSISTENCE_TRANSIENT, int period = MICROBIT_DISPLAY_PWM_PERIOD);
/**
* Frees this DynamicPwm instance if the pointer is valid.
*
* Example:
* @code
* DynamicPwm* pwm = DynamicPwm::allocate();
* pwm->free();
* @endcode
*/
void free();
/**
* Retreives the pin name associated with this DynamicPwm instance.
*
* Example:
* @code
* DynamicPwm* pwm = DynamicPwm::allocate(PinName n);
* pwm->getPinName(); // equal to n
* @endcode
*/
PinName getPinName();
/**
* Sets the period used by the WHOLE PWM module. Any changes to the period will AFFECT ALL CHANNELS.
*
* 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);
};
#endif

15
inc/ErrorNo.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef ERROR_NO_H
#define ERROR_NO_H
/**
* Error codes using in the Micro:bit runtime.
*/
enum Error{
MICROBIT_INVALID_VALUE = -1, // currently only used in MicroBit.cpp rand function when the max is less or equal to 0.
MICROBIT_IO_OP_NA = -2, // used in MicroBitPin.cpp for when a pin cannot perform a transition. (microbit io operation not allowed)
MICROBIT_COMPASS_IS_CALIBRATING = -3, // used in MicroBitPin.cpp for when a pin cannot perform a transition. (microbit io operation not allowed)
MICROBIT_COMPASS_CALIBRATE_REQUIRED = -4,
MICROBIT_OOM = 20, // the MicroBit Out of memory error code...
MICROBIT_I2C_LOCKUP = 10 // the MicroBit I2C bus has locked up
};
#endif

8
inc/ExternalEvents.h Normal file
View file

@ -0,0 +1,8 @@
#ifndef EXTERNAL_EVENTS_H
#define EXTERNAL_EVENTS_H
#define MICROBIT_ID_BLE 1000
#include "MESEvents.h"
#endif

82
inc/MESEvents.h Normal file
View file

@ -0,0 +1,82 @@
#ifndef MES_EVENTS_H
#define MES_EVENTS_H
//
// MicroBit Event Service Event ID's and values
//
//
// 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_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_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
//
// 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_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
#endif

306
inc/ManagedString.h Normal file
View file

@ -0,0 +1,306 @@
#ifndef MANAGED_STRING_H
#define MANAGED_STRING_H
#include "mbed.h"
/**
* Class definition for a ManagedString.
*
* Uses basic reference counting to implement a copy-assignable, immutable string.
* This maps closely to the constructs found in many high level application languages,
* such as Touch Develop.
*
* Written from first principles here, for several reasons:
* 1) std::shared_ptr is not yet availiable on the ARMCC compiler
* 2) to reduce memory footprint - we don't need many of the other features in the std library
* 3) it makes an interestin case study for anyone interested in seeing how it works!
*/
class ManagedString
{
// Internally we record the string as a char *, but control access to this to proide immutability
// and reference counting.
char *data;
int16_t *ref;
int16_t len;
public:
/**
* Constructor.
* Create a managed string from a pointer to an 8-bit character buffer.
* The buffer is copied to ensure sage memory management (the supplied
* character buffer may be decalred on the stack for instance).
*
* @param str The character array on which to base the new ManagedString.
*
* Example:
* @code
* ManagedString s("abcdefg");
* @endcode
*/
ManagedString(const char *str);
/**
* Constructor.
* Create a managed string from a given integer.
*
* @param value The integer from which to create the ManagedString
*
* Example:
* @code
* ManagedString s(20);
* @endcode
*/
ManagedString(const int value);
/**
* Constructor.
* Create a managed string from a given char.
*
* @param value The char from which to create the ManagedString
*
* Example:
* @code
* ManagedString s('a');
* @endcode
*/
ManagedString(const char value);
/**
* Constructor.
* Create a managed string from a pointer to an 8-bit character buffer of a given length.
* The buffer is copied to ensure sane memory management (the supplied
* character buffer may be declared on the stack for instance).
*
* @param str The character array on which to base the new ManagedString.
* @param length The length of the character array
*
* Example:
* @code
* ManagedString s("abcdefg",7); // this is generally used for substring... why not use a normal char * constructor?
* @endcode
*/
ManagedString(const char *str, const int16_t length);
/**
* Copy constructor.
* Makes a new ManagedString identical to the one supplied.
* Shares the character buffer and reference count with the supplied ManagedString.
*
* @param s The ManagedString to copy.
*
* Example:
* @code
* ManagedString s("abcdefg");
* ManagedString p(s);
* @endcode
*/
ManagedString(const ManagedString &s);
/**
* Default constructor.
*
* Create an empty ManagedString.
*
* Example:
* @code
* ManagedString s();
* @endcode
*/
ManagedString();
/**
* Destructor.
*
* Free this ManagedString, and decrement the reference count to the
* internal character buffer. If we're holding the last reference,
* also free the character buffer and reference counter.
*/
~ManagedString();
/**
* Copy assign operation.
*
* Called when one ManagedString is assigned the value of another.
* If the ManagedString being assigned is already refering to a character buffer,
* decrement the reference count and free up the buffer as necessary.
* Then, update our character buffer to refer to that of the supplied ManagedString,
* and increase its reference count.
*
* @param s The ManagedString to copy.
*
* Example:
* @code
* ManagedString s("abcd");
* ManagedString p("efgh");
* p = s // p now points to s, s' ref is incremented
* @endcode
*/
ManagedString& operator = (const ManagedString& s);
/**
* Equality operation.
*
* Called when one ManagedString is tested to be equal to another using the '==' operator.
*
* @param s The ManagedString to test ourselves against.
* @return true if this ManagedString is identical to the one supplied, false otherwise.
*
* Example:
* @code
* ManagedString s("abcd");
* ManagedString p("efgh");
*
* if(p==s)
* print("We are the same!");
* else
* print("We are different!"); //p is not equal to s - this will be called
* @endcode
*/
bool operator== (const ManagedString& s);
/**
* Inequality operation.
*
* Called when one ManagedString is tested to be less than another using the '<' operator.
*
* @param s The ManagedString to test ourselves against.
* @return true if this ManagedString is alphabetically less than to the one supplied, false otherwise.
*
* Example:
* @code
* ManagedString s("a");
* ManagedString p("b");
*
* if(s<p)
* print("a is before b!"); //a is before b
* else
* print("b is before a!");
* @endcode
*/
bool operator< (const ManagedString& s);
/**
* Inequality operation.
*
* Called when one ManagedString is tested to be greater than another using the '>' operator.
*
* @param s The ManagedString to test ourselves against.
* @return true if this ManagedString is alphabetically greater than to the one supplied, false otherwise.
*
* Example:
* @code
* ManagedString s("a");
* ManagedString p("b");
*
* if(p>a)
* print("b is after a!"); //b is after a
* else
* print("a is after b!");
* @endcode
*/
bool operator> (const ManagedString& s);
/**
* Extracts a ManagedString from this string, at the position provided.
*
* @param start The index of the first character to extract, indexed from zero.
* @param length The number of characters to extract from the start position
* @return a ManagedString representing the requested substring.
*
* Example:
* @code
* ManagedString s("abcdefg");
*
* print(s.substring(0,2)) // prints "ab"
* @endcode
*/
ManagedString substring(int16_t start, int16_t length);
/**
* Concatenates this string with the one provided.
*
* @param s The ManagedString to concatenate.
* @return a new ManagedString representing the joined strings.
*
* Example:
* @code
* ManagedString s("abcd");
* ManagedString p("efgh")
*
* print(s + p) // prints "abcdefgh"
* @endcode
*/
ManagedString operator+ (ManagedString& s);
/**
* Provides a character value at a given position in the string, indexed from zero.
*
* @param index The position of the character to return.
* @return the character at posisiton index, zero if index is invalid.
*
* Example:
* @code
* ManagedString s("abcd");
*
* print(s.charAt(1)) // prints "b"
* @endcode
*/
char charAt(int16_t index);
/**
* Provides an immutable 8 bit wide haracter buffer representing this string.
*
* @return a pointer to the character buffer.
*/
const char *toCharArray();
/**
* Determines the length of this ManagedString in characters.
*
* @return the length of the string in characters.
*
* Example:
* @code
* ManagedString s("abcd");
*
* print(s.length()) // prints "4"
* @endcode
*/
int16_t length();
/**
* Empty String constant
*/
static ManagedString EmptyString;
private:
/**
* Internal constructor helper.
* Configures this ManagedString to refer to the static EmptyString
*/
void initEmpty();
/**
* Internal constructor helper.
* creates this ManagedString based on a given null terminated char array.
*/
void initString(const char *str);
/**
* Private Constructor.
* Create a managed string based on a concat of two strings.
* The buffer is copied to ensure sane memory management (the supplied
* character buffer may be decalred on the stack for instance).
*
* @param str1 The first string on which to base the new ManagedString
* @param str2 The second string on which to base the new ManagedString
*/
ManagedString(const ManagedString &s1, const ManagedString &s2);
};
#endif

162
inc/ManagedType.h Normal file
View file

@ -0,0 +1,162 @@
#ifndef MICROBIT_MANAGED_TYPE
#define MICROBIT_MANAGED_TYPE
/**
* Class definition for a Generic Managed Type.
*
* Represents a reference counted object.
*
* @info When the destructor is called delete is called on the object - implicitly calling the given objects destructor.
*/
template <class T>
class ManagedType
{
private:
int *ref;
public:
T *object;
/**
* Constructor for the managed type, given a class space T.
* @param object the object that you would like to be ref counted - of class T
*
* Example:
* @code
* T object = new T();
* ManagedType<T> mt(t);
* @endcode
*/
ManagedType(T* object);
/**
* Default constructor for the managed type, given a class space T.
*/
ManagedType();
/**
* Copy constructor for the managed type, given a class space T.
* @param t another managed type instance of class type T.
*
* Example:
* @code
* T* object = new T();
* ManagedType<T> mt(t);
* ManagedType<T> mt1(mt);
* @endcode
*/
ManagedType(const ManagedType<T> &t);
/**
* Destructor for the managed type, given a class space T.
*/
~ManagedType();
/**
* Copy-assign member function for the managed type, given a class space.
*
* Example:
* @code
* T* object = new T();
* ManagedType<T> mt(t);
* ManagedType<T> mt1 = mt;
* @endcode
*/
ManagedType<T>& operator = (const ManagedType<T>&i);
/**
* Returns the references to this ManagedType
*
* Example:
* @code
* T* object = new T();
* ManagedType<T> mt(t);
* ManagedType<T> mt1(mt);
*
* mt.getReferences // this will be 2!
* @endcode
*/
int getReferences();
};
/**
* Constructor for the managed type, given a class space.
*/
template<typename T>
ManagedType<T>::ManagedType(T* object)
{
this->object = object;
ref = (int *)malloc(sizeof(int));
*ref = 1;
}
/**
* Default constructor for the managed type, given a class space.
*/
template<typename T>
ManagedType<T>::ManagedType()
{
this->object = NULL;
ref = (int *)malloc(sizeof(int));
*ref = 0;
}
/**
* Copy constructor for the managed type, given a class space.
*/
template<typename T>
ManagedType<T>::ManagedType(const ManagedType<T> &t)
{
this->object = t.object;
this->ref = t.ref;
(*ref)++;
}
/**
* Destructor for the managed type, given a class space.
*/
template<typename T>
ManagedType<T>::~ManagedType()
{
if (--(*ref) == 0)
{
delete object;
free(ref);
}
}
/**
* Copy-assign member function for the managed type, given a class space.
*/
template<typename T>
ManagedType<T>& ManagedType<T>::operator = (const ManagedType<T>&t)
{
if (this == &t)
return *this;
if (--(*ref) == 0)
{
delete object;
free(ref);
}
object = t.object;
ref = t.ref;
(*ref)++;
return *this;
}
/**
* Returns the references to this ManagedType
*/
template<typename T>
int ManagedType<T>::getReferences()
{
return (*ref);
}
#endif

279
inc/MicroBit.h Normal file
View file

@ -0,0 +1,279 @@
#ifndef MICROBIT_H
#define MICROBIT_H
// DEBUG. Enable this to get debug message routed through the USB serial interface.
//#define MICROBIT_DBG
#include "mbed.h"
#include "ble/BLE.h"
#include "ble/services/DeviceInformationService.h"
//error number enumeration
#include "ErrorNo.h"
/**
* Displays "=(" and an accompanying status code
* @param statusCode the appropriate status code - 0 means no code will be displayed. Status codes must be in the range 0-255.
*/
void panic(int statusCode);
#include "MicroBitMalloc.h"
#include "MicroBitCompat.h"
#include "MicroBitFiber.h"
#include "ManagedType.h"
#include "ManagedString.h"
#include "MicroBitFont.h"
#include "MicroBitImage.h"
#include "MicroBitEvent.h"
#include "MicroBitMessageBus.h"
#include "DynamicPwm.h"
#include "MicroBitComponent.h"
#include "MicroBitI2C.h"
#include "MicroBitSerial.h"
#include "MicroBitButton.h"
#include "MicroBitMultiButton.h"
#include "MicroBitDisplay.h"
#include "MicroBitPin.h"
#include "MicroBitIO.h"
#include "MicroBitCompass.h"
#include "MicroBitAccelerometer.h"
#include "MicroBitDFUService.h"
#include "MicroBitEventService.h"
#include "ExternalEvents.h"
// MicroBit::flags values
#define MICROBIT_FLAG_SCHEDULER_RUNNING 0x00000001
#define MICROBIT_FLAG_ACCELEROMETER_RUNNING 0x00000002
#define MICROBIT_FLAG_DISPLAY_RUNNING 0x00000004
#define MICROBIT_FLAG_COMPASS_RUNNING 0x00000008
// Random number generator
#define NRF51822_RNG_ADDRESS 0x4000D000
#define MICROBIT_IO_PINS 20 // TODO: Need to change for live, currently 3 for test
// Enumeration of core components.
#define MICROBIT_ID_BUTTON_A 1
#define MICROBIT_ID_BUTTON_B 2
#define MICROBIT_ID_BUTTON_RESET 3
#define MICROBIT_ID_ACCELEROMETER 4
#define MICROBIT_ID_COMPASS 5
#define MICROBIT_ID_DISPLAY 6
//EDGE connector events
#define MICROBIT_ID_IO_P0 7 //P0 is the left most pad (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P1 8 //P1 is the middle pad (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P2 9 //P2 is the right most pad (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P3 10 //COL1 (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P4 11 //BTN_A
#define MICROBIT_ID_IO_P5 12 //COL2 (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P6 13 //ROW2
#define MICROBIT_ID_IO_P7 14 //ROW1
#define MICROBIT_ID_IO_P8 15 //PIN 18
#define MICROBIT_ID_IO_P9 16 //ROW3
#define MICROBIT_ID_IO_P10 17 //COL3 (ANALOG/DIGITAL)
#define MICROBIT_ID_IO_P11 18 //BTN_B
#define MICROBIT_ID_IO_P12 19 //PIN 20
#define MICROBIT_ID_IO_P13 20 //SCK
#define MICROBIT_ID_IO_P14 21 //MISO
#define MICROBIT_ID_IO_P15 22 //MOSI
#define MICROBIT_ID_IO_P16 23 //PIN 16
#define MICROBIT_ID_IO_P19 24 //SCL
#define MICROBIT_ID_IO_P20 25 //SDA
#define MICROBIT_ID_BUTTON_AB 26 // Button A+B multibutton
// mBed pin assignments of core components.
//TODO: When platform is built for MB2 - pins will be defined by default, these will change...
#define MICROBIT_PIN_SDA P0_30
#define MICROBIT_PIN_SCL P0_0
#define MICROBIT_SYSTEM_COMPONENTS 10
#define MICROBIT_IDLE_COMPONENTS 6
#ifdef MICROBIT_DEBUG
extern Serial pc;
#endif
/**
* Class definition for a MicroBit device.
*
* Represents the device as a whole, and includes member variables to that reflect the components of the system.
*/
class MicroBit
{
private:
void seedRandom();
uint32_t randomValue;
public:
// Map of device state.
uint32_t flags;
// Periodic callback
Ticker systemTicker;
// I2C Interface
MicroBitI2C i2c;
// Serial Interface
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;
// Member variables to represent each of the core components on the device.
MicroBitDisplay display;
MicroBitButton buttonA;
MicroBitButton buttonB;
MicroBitMultiButton buttonAB;
MicroBitAccelerometer accelerometer;
MicroBitCompass compass;
//An object of available IO pins on the device
MicroBitIO io;
// Bluetooth related member variables.
BLEDevice *ble;
DeviceInformationService *ble_device_information_service;
MicroBitDFUService *ble_firmware_update_service;
MicroBitEventService *ble_event_service;
/**
* Constructor.
* Create a representation of a MicroBit device as a global singleton.
* @param messageBus callback function to receive MicroBitMessageBus events.
*
* Exposed objects:
* @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.
* uBit.buttonA; //The buttonA object for button a.
* uBit.buttonB; //The buttonB object for button b.
* uBit.resetButton; //The resetButton used for soft resets.
* uBit.accelerometer; //The object that represents the inbuilt accelerometer
* uBit.compass; //The object that represents the inbuilt compass(magnetometer)
* uBit.io.P*; //Where P* is P0 to P16, P19 & P20 on the edge connector
* @endcode
*/
MicroBit();
/**
* 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();
/**
* Delay for the given amount of time.
* 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.
*
* @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.
*
* Example:
* @code
* uBit.sleep(20); //sleep for 20ms
* @endcode
*/
void sleep(int milliseconds);
/**
* Generate a random number in the given range.
* We use the NRF51822 in built random number generator here
* TODO: Determine if we want to, given its relatively high power consumption!
*
* @param max the upper range to generate a number for. This number cannot be negative
* @return A random, natural number between 0 and the max-1. Or MICROBIT_INVALID_VALUE (defined in ErrorNo.h) if max is <= 0.
*
* Example:
* @code
* uBit.random(200); //a number between 0 and 199
* @endcode
*/
int random(int max);
/**
* Period callback. Used by MicroBitDisplay, FiberScheduler and I2C sensors to
* 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
*/
void addSystemComponent(MicroBitComponent *component);
/**
* remove a component from the array of system components
*/
void 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
*/
void addIdleComponent(MicroBitComponent *component);
/**
* remove a component from the array of idle thread components
*/
void removeIdleComponent(MicroBitComponent *component);
/**
* Determine the time since this MicroBit was last reset.
*
* @return The time since the last reset, in milliseconds. This will result in overflow after 1.6 months.
* TODO: handle overflow case.
*/
unsigned long systemTime();
/**
* 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);
};
// Definition of the global instance of the MicroBit class.
// Using this as a variation on the singleton pattern, just to make
// code integration a little bit easier for 3rd parties.
extern MicroBit uBit;
// Entry point for application programs. Called after the super-main function
// has initialized the device and runtime environment.
extern "C" void app_main();
#endif

161
inc/MicroBitAccelerometer.h Normal file
View file

@ -0,0 +1,161 @@
#ifndef MICROBIT_ACCELEROMETER_H
#define MICROBIT_ACCELEROMETER_H
#include "mbed.h"
/**
* Relevant pin assignments
*/
#define MICROBIT_PIN_ACCEL_DATA_READY P0_28
/*
* I2C constants
*/
#define MMA8653_DEFAULT_ADDR 0x3A
/*
* MMA8653 Register map (partial)
*/
#define MMA8653_STATUS 0x00
#define MMA8653_OUT_X_MSB 0x01
#define MMA8653_WHOAMI 0x0D
#define MMA8653_XYZ_DATA_CFG 0x0E
#define MMA8653_CTRL_REG1 0x2A
#define MMA8653_CTRL_REG2 0x2B
#define MMA8653_CTRL_REG3 0x2C
#define MMA8653_CTRL_REG4 0x2D
#define MMA8653_CTRL_REG5 0x2E
/**
* MMA8653 constants
*/
#define MMA8653_WHOAMI_VAL 0x5A
struct MMA8653Sample
{
int16_t x;
int16_t y;
int16_t z;
};
/**
* 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.
* Used to track asynchronous events in the event bus.
*/
//if you are adding status here - don't it's in MicroBitComponent!!!
uint16_t address; // I2C address of this accelerometer.
MMA8653Sample sample; // The last sample read.
DigitalIn int1; // Data ready interrupt.
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
*/
MicroBitAccelerometer(uint16_t id, uint16_t address);
/**
* 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!
*/
void update();
/**
* Attempts to determine the 8 bit ID from the accelerometer.
* @return the 8 bit ID returned by the accelerometer
*
* Example:
* @code
* uBit.accelerometer.whoAmI();
* @endcode
*/
int whoAmI();
/**
* Reads the X axis value of the latest update from the accelerometer.
* Currently limited to +/- 2g
* @return The force measured in the X axis, in milli-g.
*
* Example:
* @code
* uBit.accelerometer.getX();
* @endcode
*/
int getX();
/**
* 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
* uBit.accelerometer.getY();
* @endcode
*/
int getY();
/**
* 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
* uBit.accelerometer.getZ();
* @endcode
*/
int getZ();
/**
* 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();
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.
*/
void 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.
*/
void readCommand(uint8_t reg, uint8_t* buffer, int length);
};
#endif

92
inc/MicroBitButton.h Normal file
View file

@ -0,0 +1,92 @@
#ifndef MICROBIT_BUTTON_H
#define MICROBIT_BUTTON_H
#include "mbed.h"
//TODO: When platform is built for MB2 - pins will be defined by default, these will change...
#define MICROBIT_PIN_BUTTON_A P0_17
#define MICROBIT_PIN_BUTTON_B P0_26
#define MICROBIT_PIN_BUTTON_RESET P0_19
#define MICROBIT_BUTTON_EVT_DOWN 1
#define MICROBIT_BUTTON_EVT_UP 2
#define MICROBIT_BUTTON_EVT_CLICK 3
#define MICROBIT_BUTTON_EVT_LONG_CLICK 4
#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_STATE 1
#define MICROBIT_BUTTON_STATE_HOLD_TRIGGERED 2
#define MICROBIT_BUTTON_STATE_CLICK 4
#define MICROBIT_BUTTON_STATE_LONG_CLICK 8
#define MICROBIT_BUTTON_SIGMA_MIN 0
#define MICROBIT_BUTTON_SIGMA_MAX 12
#define MICROBIT_BUTTON_SIGMA_THRESH_HI 8
#define MICROBIT_BUTTON_SIGMA_THRESH_LO 2
#define MICROBIT_BUTTON_DOUBLE_CLICK_THRESH 50
/**
* Class definition for MicroBit Button.
*
* Represents a single, generic button on the device.
*/
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.
uint8_t doubleClickTimer; // double click timer (ticks).
public:
/**
* 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
* buttonA(MICROBIT_ID_BUTTON_A,MICROBIT_PIN_BUTTON_A); //a number between 0 and 200 inclusive
* @endcode
*
* Possible Events:
* @code
* MICROBIT_BUTTON_EVT_DOWN
* MICROBIT_BUTTON_EVT_UP
* MICROBIT_BUTTON_EVT_CLICK
* MICROBIT_BUTTON_EVT_LONG_CLICK
* MICROBIT_BUTTON_EVT_DOUBLE_CLICK
* MICROBIT_BUTTON_EVT_HOLD
* @endcode
*/
MicroBitButton(uint16_t id, PinName name, PinMode mode = PullNone);
/**
* Tests if this Button is currently pressed.
* @return 1 if this button is pressed, 0 otherwise.
*
* Example:
* @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();
};
#endif

262
inc/MicroBitCompass.h Normal file
View file

@ -0,0 +1,262 @@
#ifndef MICROBIT_COMPASS_H
#define MICROBIT_COMPASS_H
#include "mbed.h"
/**
* Relevant pin assignments
*/
#define MICROBIT_PIN_COMPASS_DATA_READY P0_29
/*
* I2C constants
*/
#define MAG3110_DEFAULT_ADDR 0x1D
/*
* MAG3110 Register map
*/
#define MAG_DR_STATUS 0x00
#define MAG_OUT_X_MSB 0x01
#define MAG_OUT_X_LSB 0x02
#define MAG_OUT_Y_MSB 0x03
#define MAG_OUT_Y_LSB 0x04
#define MAG_OUT_Z_MSB 0x05
#define MAG_OUT_Z_LSB 0x06
#define MAG_WHOAMI 0x07
#define MAG_SYSMOD 0x08
#define MAG_OFF_X_MSB 0x09
#define MAG_OFF_X_LSB 0x0A
#define MAG_OFF_Y_MSB 0x0B
#define MAG_OFF_Y_LSB 0x0C
#define MAG_OFF_Z_MSB 0x0D
#define MAG_OFF_Z_LSB 0x0E
#define MAG_DIE_TEMP 0x0F
#define MAG_CTRL_REG1 0x10
#define MAG_CTRL_REG2 0x11
/*
* Compass events
*/
#define MICROBIT_COMPASS_EVT_CAL_REQUIRED 1
#define MICROBIT_COMPASS_EVT_CAL_START 2
#define MICROBIT_COMPASS_EVT_CAL_END 3
/*
* Status Bits
*/
#define MICROBIT_COMPASS_STATUS_CALIBRATED 1
#define MICROBIT_COMPASS_STATUS_CALIBRATING 2
#define MICROBIT_COMPASS_CALIBRATE_PERIOD 10000
/*
* MAG3110 MAGIC ID value
* Returned from the MAG_WHO_AM_I register for ID purposes.
*/
#define MAG3110_WHOAMI_VAL 0xC4
struct CompassSample
{
int16_t x;
int16_t y;
int16_t z;
CompassSample()
{
this->x = 0;
this->y = 0;
this->z = 0;
}
};
/**
* Class definition for MicroBit Compass.
*
* Represents an implementation of the Freescale MAG3110 I2C Magnetmometer.
* Also includes basic caching, calibration and on demand activation.
*/
class MicroBitCompass : public MicroBitComponent
{
/**
* Unique, enumerated ID for this component.
* Used to track asynchronous events in the event bus.
*/
uint16_t address; // I2C address of the magnetmometer.
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.
/**
* Constructor.
* Create a compass representation with the given ID.
* @param id the event ID of the compass object.
* @param address the default address for the compass register
*
* Example:
* @code
* compass(MICROBIT_ID_COMPASS, MAG3110_DEFAULT_ADDR);
* @endcode
*
* Possible Events for the compass are as follows:
* @code
* MICROBIT_COMPASS_EVT_CAL_REQUIRED // triggered when no magnetometer data is available in persistent storage
* MICROBIT_COMPASS_EVT_CAL_START // triggered when calibration has begun
* MICROBIT_COMPASS_EVT_CAL_END // triggered when calibration has finished.
* @endcode
*/
MicroBitCompass(uint16_t id, uint16_t address);
/**
* Gets the current heading of the device, relative to magnetic north.
* @return the current heading, in degrees.
*
* Example:
* @code
* uBit.compass.heading();
* @endcode
*/
int heading();
/**
* Attempts to determine the 8 bit ID from the magnetometer.
* @return the id of the compass (magnetometer)
*
* Example:
* @code
* uBit.compass.whoAmI();
* @endcode
*/
int whoAmI();
/**
* Reads the X axis value of the latest update from the compass.
* @return The magnetic force measured in the X axis, in no specific units.
*
* Example:
* @code
* uBit.compass.getX();
* @endcode
*/
int getX();
/**
* Reads the Y axis value of the latest update from the compass.
* @return The magnetic force measured in the Y axis, in no specific units.
*
* Example:
* @code
* uBit.compass.getY();
* @endcode
*/
int getY();
/**
* Reads the Z axis value of the latest update from the compass.
* @return The magnetic force measured in the Z axis, in no specific units.
*
* Example:
* @code
* uBit.compass.getZ();
* @endcode
*/
int getZ();
/**
* Perform the asynchronous calibration of the compass.
* This will fire MICROBIT_COMPASS_EVT_CAL_START and MICROBIT_COMPASS_EVT_CAL_END when finished.
* @note THIS MUST BE CALLED TO GAIN RELIABLE VALUES FROM THE COMPASS
*/
void calibrateAsync();
/**
* Perform a calibration of the compass.
* This will fire MICROBIT_COMPASS_EVT_CAL_START.
* @note THIS MUST BE CALLED TO GAIN RELIABLE VALUES FROM THE COMPASS
*/
void calibrateStart();
/**
* Complete the calibration of the compass.
* This will fire MICROBIT_COMPASS_EVT_CAL_END.
* @note THIS MUST BE CALLED TO GAIN RELIABLE VALUES FROM THE COMPASS
*/
void calibrateEnd();
/**
* Periodic callback from MicroBit idle thread.
* Check if any data is ready for reading by checking the interrupt.
*/
virtual void idleTick();
/**
* Returns 0 or 1. 1 indicates that the compass is calibrated, zero means the compass requires calibration.
*/
int isCalibrated();
/**
* Returns 0 or 1. 1 indicates that the compass is calibrating, zero means the compass is not currently calibrating.
*/
int isCalibrating();
/**
* Clears the calibration held in persistent storage, and sets the calibrated flag to zero.
*/
void clearCalibration();
/**
* Returns 0 or 1. 1 indicates data is waiting to be read, zero means data is not ready to be read.
*/
virtual int isIdleCallbackNeeded();
private:
/**
* Issues a standard, 2 byte I2C command write to the magnetometer.
* Blocks the calling thread until complete.
*
* @param reg The address of the register to write to.
* @param value The value to write.
*/
void 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.
*/
void readCommand(uint8_t reg, uint8_t* buffer, int length);
/**
* Issues a read of a given address, and returns the value.
* Blocks the calling thread until complete.
*
* @param reg The based address of the 16 bit register to access.
* @return The register value, interpreted as a 16 but signed value.
*/
int16_t read16(uint8_t reg);
/**
* Issues a read of a given address, and returns the value.
* Blocks the calling thread until complete.
*
* @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);
};
#endif

73
inc/MicroBitCompat.h Normal file
View file

@ -0,0 +1,73 @@
/**
* Compatibility / portability funcitons and constants for the MicroBit DAL.
*/
#ifndef MICROBIT_COMPAT_H
#define MICROBIT_COMPAT_H
#define PI 3.14159265359
/*! \
\brief Utility functions.
Included here often to reduce the need to import a whole library for simple opertations.
This helps to minimize our SRAM footprint.
*/
/*!
\brief returns the smallest of the two numbers
\param a the first number
\param b the number to compare against a
\return whichever value is the smallest
*/
inline int min(int a, int b)
{
return (a < b ? a : b);
}
/*!
\brief returns the biggest of the two numbers
\param a the first number
\param b the number to compare against a
\return whichever value is the biggest
*/
inline int max(int a, int b)
{
return (a > b ? a : b);
}
/*!
\brief clears b number of bytes given the pointer a
\param a the pointer to the beginning of the memory to clear
\param b the number of bytes to clear.
*/
inline void *memclr(void *a, size_t b)
{
return memset(a,0,b);
}
/*!
\brief returns true if the character c lies between ascii values 48 and 57 inclusive.
\param c the character to check
\return a bool, true if it is a digit, false otherwise