Merge branch 'master' into flatstring
Conflicts: .gitignore inc/ErrorNo.h source/MicroBitDisplay.cpp source/MicroBitImage.cpp
This commit is contained in:
commit
56a560e5bc
|
@ -1,6 +1,6 @@
|
|||
.yotta.json
|
||||
build
|
||||
*.swp
|
||||
.yotta.json
|
||||
yotta_modules
|
||||
yotta_targets
|
||||
*.swp
|
||||
Makefile
|
||||
|
|
|
@ -3,25 +3,51 @@
|
|||
|
||||
/**
|
||||
* Error codes used in the micro:bit runtime.
|
||||
* These may be returned from functions implemented in the micro:bit runtime.
|
||||
*/
|
||||
enum Error{
|
||||
// Invalid parameter given.
|
||||
MICROBIT_INVALID_VALUE = -1,
|
||||
enum ErrorCode{
|
||||
|
||||
// Invalid I/O operation requested.
|
||||
MICROBIT_IO_OP_NA = -2,
|
||||
// No error occurred.
|
||||
MICROBIT_OK = 0,
|
||||
|
||||
// Invalid parameter given.
|
||||
MICROBIT_INVALID_PARAMETER = -1001,
|
||||
|
||||
// Requested operation is unspupported.
|
||||
MICROBIT_NOT_SUPPORTED = -1002,
|
||||
|
||||
// Device calibration errors
|
||||
MICROBIT_COMPASS_IS_CALIBRATING = -3,
|
||||
MICROBIT_COMPASS_CALIBRATE_REQUIRED = -4,
|
||||
MICROBIT_CALIBRATION_IN_PROGRESS = -1003,
|
||||
MICROBIT_CALIBRATION_REQUIRED = -1004,
|
||||
|
||||
// The requested operation could not be performed as the device has run out of some essential resource (e.g. allocated memory)
|
||||
MICROBIT_NO_RESOURCES = -1005,
|
||||
|
||||
// The requested operation could not be performed as some essential resource is busy (e.g. the display)
|
||||
MICROBIT_BUSY = -1006,
|
||||
|
||||
// The requested operation was cancelled before it completed.
|
||||
MICROBIT_CANCELLED = -1007,
|
||||
|
||||
// I2C Communication error occured (typically I2C module on processor has locked up.)
|
||||
MICROBIT_I2C_LOCKUP = 10,
|
||||
MICROBIT_I2C_ERROR = -1010
|
||||
};
|
||||
|
||||
/**
|
||||
* Error codes used in the micro:bit runtime.
|
||||
*/
|
||||
enum PanicCode{
|
||||
// PANIC Codes. These are not return codes, but are terminal conditions.
|
||||
// These induce a panic operation, where all code stops executing, and a panic state is
|
||||
// entered where the panic code is diplayed.
|
||||
|
||||
// Out out memory error. Heap storage was requested, but is not available.
|
||||
MICROBIT_OOM = 20,
|
||||
|
||||
// Corruption detected in the micro:bit heap space
|
||||
MICROBIT_HEAP_ERROR = 30
|
||||
MICROBIT_HEAP_ERROR = 30,
|
||||
|
||||
// Dereference of a NULL pointer through the ManagedType class,
|
||||
MICROBIT_NULL_DEREFERENCE = 40,
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
template <class T>
|
||||
class ManagedType
|
||||
{
|
||||
private:
|
||||
protected:
|
||||
|
||||
int *ref;
|
||||
|
||||
|
@ -80,10 +80,37 @@ public:
|
|||
*/
|
||||
int getReferences();
|
||||
|
||||
/**
|
||||
* De-reference operator overload. This makes modifying ref-counted POD
|
||||
* easier.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedType<int> x = 0;
|
||||
* *x = 1; // mutates the ref-counted integer
|
||||
*/
|
||||
T& operator*() {
|
||||
return *object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method call operator overload. This forwards the call to the underlying
|
||||
* object.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedType<T> x = new T();
|
||||
* x->m(); // resolves to T::m
|
||||
*/
|
||||
T* operator->() {
|
||||
if (object == NULL)
|
||||
panic(MICROBIT_NULL_DEREFERENCE);
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* x.get() is shorthand for x.operator->()
|
||||
*/
|
||||
T* get() {
|
||||
return object;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,25 @@
|
|||
#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"
|
||||
|
@ -62,10 +80,6 @@
|
|||
#define MICROBIT_PIN_SDA P0_30
|
||||
#define MICROBIT_PIN_SCL P0_0
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_DBG)
|
||||
extern Serial pc;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Class definition for a MicroBit device.
|
||||
*
|
||||
|
@ -90,9 +104,7 @@ class MicroBit
|
|||
MicroBitI2C i2c;
|
||||
|
||||
// Serial Interface
|
||||
#if CONFIG_DISABLED(MICROBIT_DBG)
|
||||
MicroBitSerial serial;
|
||||
#endif
|
||||
|
||||
// Array of components which are iterated during a system tick
|
||||
MicroBitComponent* systemTickComponents[MICROBIT_SYSTEM_COMPONENTS];
|
||||
|
@ -191,13 +203,14 @@ class MicroBit
|
|||
* @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.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.sleep(20); //sleep for 20ms
|
||||
* @endcode
|
||||
*/
|
||||
void sleep(int milliseconds);
|
||||
int sleep(int milliseconds);
|
||||
|
||||
/**
|
||||
* Generate a random number in the given range.
|
||||
|
@ -205,7 +218,7 @@ class MicroBit
|
|||
* 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.
|
||||
* @return A random, natural number between 0 and the max-1. Or MICROBIT_INVALID_PARAMETER if max is <= 0.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -227,24 +240,33 @@ class MicroBit
|
|||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void addSystemComponent(MicroBitComponent *component);
|
||||
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.
|
||||
*/
|
||||
void removeSystemComponent(MicroBitComponent *component);
|
||||
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
|
||||
* @param component The component to add.
|
||||
* @return MICROBIT_OK on success. MICROBIT_NO_RESOURCES is returned if further components cannot be supported.
|
||||
*/
|
||||
void addIdleComponent(MicroBitComponent *component);
|
||||
int addIdleComponent(MicroBitComponent *component);
|
||||
|
||||
/**
|
||||
* remove a component from the array of idle thread 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.
|
||||
*/
|
||||
void removeIdleComponent(MicroBitComponent *component);
|
||||
int removeIdleComponent(MicroBitComponent *component);
|
||||
|
||||
/**
|
||||
* Determine the time since this MicroBit was last reset.
|
||||
|
@ -260,7 +282,7 @@ class MicroBit
|
|||
* @return A textual description of the currentlt executing micro:bit runtime.
|
||||
* TODO: handle overflow case.
|
||||
*/
|
||||
char *systemVersion();
|
||||
const char *systemVersion();
|
||||
|
||||
/**
|
||||
* Triggers a microbit panic where an infinite loop will occur swapping between the panicFace and statusCode if provided.
|
||||
|
|
|
@ -102,22 +102,27 @@ class MicroBitAccelerometer : public MicroBitComponent
|
|||
* in this object. The nearest values are chosen to those defined
|
||||
* that are supported by the hardware. The instance variables are then
|
||||
* updated to reflect reality.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the accelerometer could not be configured.
|
||||
*/
|
||||
void configure();
|
||||
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!
|
||||
* 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.
|
||||
*/
|
||||
void update();
|
||||
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.
|
||||
*/
|
||||
void setPeriod(int period);
|
||||
int setPeriod(int period);
|
||||
|
||||
/**
|
||||
* Reads the currently configured sample rate of the accelerometer.
|
||||
|
@ -130,8 +135,9 @@ class MicroBitAccelerometer : public MicroBitComponent
|
|||
* n.b. the requested range may not be possible on the hardware. In this case, the
|
||||
* nearest lower rate is chosen.
|
||||
* @param range The requested sample range of samples, in g.
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
|
||||
*/
|
||||
void setRange(int range);
|
||||
int setRange(int range);
|
||||
|
||||
/**
|
||||
* Reads the currently configured sample range of the accelerometer.
|
||||
|
@ -141,7 +147,7 @@ class MicroBitAccelerometer : public MicroBitComponent
|
|||
|
||||
/**
|
||||
* Attempts to determine the 8 bit ID from the accelerometer.
|
||||
* @return the 8 bit ID returned by the accelerometer
|
||||
* @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -204,8 +210,9 @@ class MicroBitAccelerometer : public MicroBitComponent
|
|||
*
|
||||
* @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.
|
||||
*/
|
||||
void writeCommand(uint8_t reg, uint8_t value);
|
||||
int writeCommand(uint8_t reg, uint8_t value);
|
||||
|
||||
/**
|
||||
* Issues a read command into the specified buffer.
|
||||
|
@ -214,8 +221,9 @@ class MicroBitAccelerometer : public MicroBitComponent
|
|||
* @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.
|
||||
*/
|
||||
void readCommand(uint8_t reg, uint8_t* buffer, int length);
|
||||
int readCommand(uint8_t reg, uint8_t* buffer, int length);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -31,6 +31,13 @@
|
|||
#define MICROBIT_BUTTON_SIGMA_THRESH_LO 2
|
||||
#define MICROBIT_BUTTON_DOUBLE_CLICK_THRESH 50
|
||||
|
||||
enum MicroBitButtonEventConfiguration
|
||||
{
|
||||
MICROBIT_BUTTON_SIMPLE_EVENTS,
|
||||
MICROBIT_BUTTON_ALL_EVENTS
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class definition for MicroBit Button.
|
||||
*
|
||||
|
@ -38,12 +45,12 @@
|
|||
*/
|
||||
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!).
|
||||
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).
|
||||
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:
|
||||
|
||||
|
@ -69,7 +76,7 @@ class MicroBitButton : public MicroBitComponent
|
|||
* MICROBIT_BUTTON_EVT_HOLD
|
||||
* @endcode
|
||||
*/
|
||||
MicroBitButton(uint16_t id, PinName name, PinMode mode = PullNone);
|
||||
MicroBitButton(uint16_t id, PinName name, MicroBitButtonEventConfiguration eventConfiguration = MICROBIT_BUTTON_ALL_EVENTS, PinMode mode = PullNone);
|
||||
|
||||
/**
|
||||
* Tests if this Button is currently pressed.
|
||||
|
|
|
@ -137,16 +137,18 @@ class MicroBitCompass : public MicroBitComponent
|
|||
* in this object. The nearest values are chosen to those defined
|
||||
* that are supported by the hardware. The instance variables are then
|
||||
* updated to reflect reality.
|
||||
* @return MICROBIT_OK or MICROBIT_I2C_ERROR if the magnetometer could not be configured.
|
||||
*/
|
||||
void configure();
|
||||
int configure();
|
||||
|
||||
/**
|
||||
* Attempts to set the sample rate of the compass to the specified value (in ms).
|
||||
* n.b. the requested rate may not be possible on the hardware. In this case, the
|
||||
* nearest lower rate is chosen.
|
||||
* @param period the requested time between samples, in milliseconds.
|
||||
* @return MICROBIT_OK or MICROBIT_I2C_ERROR if the magnetometer could not be updated.
|
||||
*/
|
||||
void setPeriod(int period);
|
||||
int setPeriod(int period);
|
||||
|
||||
/**
|
||||
* Reads the currently configured sample rate of the compass.
|
||||
|
@ -156,7 +158,8 @@ class MicroBitCompass : public MicroBitComponent
|
|||
|
||||
/**
|
||||
* Gets the current heading of the device, relative to magnetic north.
|
||||
* @return the current heading, in degrees.
|
||||
* @return the current heading, in degrees. Or MICROBIT_COMPASS_IS_CALIBRATING if the compass is calibrating.
|
||||
* Or MICROBIT_COMPASS_CALIBRATE_REQUIRED if the compass requires calibration.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -167,7 +170,7 @@ class MicroBitCompass : public MicroBitComponent
|
|||
|
||||
/**
|
||||
* Attempts to determine the 8 bit ID from the magnetometer.
|
||||
* @return the id of the compass (magnetometer)
|
||||
* @return the id of the compass (magnetometer), or MICROBIT_I2C_ERROR if the magnetometer could not be updated.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -211,13 +214,14 @@ class MicroBitCompass : public MicroBitComponent
|
|||
|
||||
/**
|
||||
* Reads the currently die temperature of the compass.
|
||||
* @return The temperature, in degrees celsius.
|
||||
* @return the temperature in degrees celsius, or MICROBIT_I2C_ERROR if the magnetometer could not be updated.
|
||||
*/
|
||||
int readTemperature();
|
||||
|
||||
/**
|
||||
* Perform the asynchronous calibration of the compass.
|
||||
* This will fire MICROBIT_COMPASS_EVT_CAL_START and MICROBIT_COMPASS_EVT_CAL_END when finished.
|
||||
* @return MICROBIT_OK, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed.
|
||||
* @note THIS MUST BE CALLED TO GAIN RELIABLE VALUES FROM THE COMPASS
|
||||
*/
|
||||
void calibrateAsync();
|
||||
|
@ -227,7 +231,7 @@ class MicroBitCompass : public MicroBitComponent
|
|||
* This will fire MICROBIT_COMPASS_EVT_CAL_START.
|
||||
* @note THIS MUST BE CALLED TO GAIN RELIABLE VALUES FROM THE COMPASS
|
||||
*/
|
||||
void calibrateStart();
|
||||
int calibrateStart();
|
||||
|
||||
/**
|
||||
* Complete the calibration of the compass.
|
||||
|
@ -270,8 +274,9 @@ class MicroBitCompass : public MicroBitComponent
|
|||
*
|
||||
* @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 magnetometer could not be accessed.
|
||||
*/
|
||||
void writeCommand(uint8_t reg, uint8_t value);
|
||||
int writeCommand(uint8_t reg, uint8_t value);
|
||||
|
||||
/**
|
||||
* Issues a read command into the specified buffer.
|
||||
|
@ -280,17 +285,18 @@ class MicroBitCompass : public MicroBitComponent
|
|||
* @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 magnetometer could not be accessed.
|
||||
*/
|
||||
void readCommand(uint8_t reg, uint8_t* buffer, int length);
|
||||
int 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.
|
||||
* @return The register value, interpreted as a 16 but signed value, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed.
|
||||
*/
|
||||
int16_t read16(uint8_t reg);
|
||||
int read16(uint8_t reg);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -298,9 +304,9 @@ class MicroBitCompass : public MicroBitComponent
|
|||
* 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.
|
||||
* @return The register value, interpreted as a 8 bit unsigned value, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed.
|
||||
*/
|
||||
uint8_t read8(uint8_t reg);
|
||||
int read8(uint8_t reg);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -5,67 +5,65 @@
|
|||
#ifndef MICROBIT_COMPAT_H
|
||||
#define MICROBIT_COMPAT_H
|
||||
|
||||
#include "ErrorNo.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
|
||||
/**
|
||||
* Determines the smallest of the two numbers
|
||||
* @param a the first number
|
||||
* @param b the second number
|
||||
* @return The value of a or b that 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
|
||||
/**
|
||||
* Determines the largest of the two numbers
|
||||
* @param a the first number
|
||||
* @param b the second number
|
||||
* @return The value of a or b that is the largest
|
||||
*/
|
||||
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.
|
||||
/**
|
||||
* Sets a given area of memory to zero.
|
||||
*
|
||||
* @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
|
||||
/**
|
||||
* Determines if the given character is a printable ASCII/UTF8 decimal digit (0..9).
|
||||
* @param c the character to check
|
||||
* @return true if the character is a digit, false otherwise.
|
||||
*/
|
||||
inline bool isdigit(char c)
|
||||
{
|
||||
return (c > 47 && c < 58);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Performs an in buffer reverse of a given char array
|
||||
\param s the char* to reverse.
|
||||
\return the reversed char*
|
||||
/**
|
||||
* Performs an in buffer reverse of a given char array
|
||||
* @param s the string to reverse.
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
|
||||
*/
|
||||
void string_reverse(char *s);
|
||||
int string_reverse(char *s);
|
||||
|
||||
/*!
|
||||
\briefConverts a given integer into a base 10 ASCII equivalent.
|
||||
\param n The number to convert.
|
||||
\param s Pointer to a buffer in which to store the resulting string.
|
||||
/**
|
||||
* Converts a given integer into a string representation.
|
||||
* @param n The number to convert.
|
||||
* @param s A pointer to the buffer in which to store the resulting string.
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
|
||||
*/
|
||||
void itoa(int n, char *s);
|
||||
|
||||
|
|
|
@ -42,7 +42,9 @@
|
|||
#define MICROBIT_ID_IO_P20 25 //SDA
|
||||
|
||||
#define MICROBIT_ID_BUTTON_AB 26 // Button A+B multibutton
|
||||
#define MICROBIT_ID_ALERT 27 // Alert channel, used for general purpose condition synchronisation and alerting.
|
||||
|
||||
#define MICROBIT_ID_NOTIFY 1023 // Notfication channel, for general purpose synchronisation
|
||||
#define MICROBIT_ID_NOTIFY_ONE 1022 // Notfication channel, for general purpose synchronisation
|
||||
|
||||
class MicroBitComponent
|
||||
{
|
||||
|
|
|
@ -88,9 +88,16 @@
|
|||
// MESSAGE_BUS_LISTENER_NONBLOCKING
|
||||
|
||||
#ifndef MESSAGE_BUS_LISTENER_DEFAULT_FLAGS
|
||||
#define MESSAGE_BUS_LISTENER_DEFAULT_FLAGS MESSAGE_BUS_LISTENER_REENTRANT
|
||||
#define MESSAGE_BUS_LISTENER_DEFAULT_FLAGS MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY
|
||||
#endif
|
||||
|
||||
//
|
||||
// Maximum event queue depth. If a queue exceeds this depth, further events will be dropped.
|
||||
// Used to prevent message queues growing uncontrollably due to badly behaved user code and causing panic conditions.
|
||||
//
|
||||
#ifndef MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH
|
||||
#define MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH 10
|
||||
#endif
|
||||
//
|
||||
// Core micro:bit services
|
||||
//
|
||||
|
|
|
@ -1,14 +1,6 @@
|
|||
#ifndef MICROBIT_DISPLAY_H
|
||||
#define MICROBIT_DISPLAY_H
|
||||
|
||||
/**
|
||||
* User definable constants
|
||||
*/
|
||||
#define MICROBIT_DISPLAY_ROTATION_0 0
|
||||
#define MICROBIT_DISPLAY_ROTATION_90 1
|
||||
#define MICROBIT_DISPLAY_ROTATION_180 2
|
||||
#define MICROBIT_DISPLAY_ROTATION_270 3
|
||||
|
||||
|
||||
/**
|
||||
* Core Configuration settings.
|
||||
|
@ -19,6 +11,7 @@
|
|||
* MessageBus Event Codes
|
||||
*/
|
||||
#define MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE 1
|
||||
#define MICROBIT_DISPLAY_EVT_FREE 2
|
||||
|
||||
/**
|
||||
* I/O configurations for common devices.
|
||||
|
@ -70,6 +63,7 @@
|
|||
|
||||
enum AnimationMode {
|
||||
ANIMATION_MODE_NONE,
|
||||
ANIMATION_MODE_STOPPED,
|
||||
ANIMATION_MODE_SCROLL_TEXT,
|
||||
ANIMATION_MODE_PRINT_TEXT,
|
||||
ANIMATION_MODE_SCROLL_IMAGE,
|
||||
|
@ -82,6 +76,13 @@ enum DisplayMode {
|
|||
DISPLAY_MODE_GREYSCALE
|
||||
};
|
||||
|
||||
enum DisplayRotation {
|
||||
MICROBIT_DISPLAY_ROTATION_0,
|
||||
MICROBIT_DISPLAY_ROTATION_90,
|
||||
MICROBIT_DISPLAY_ROTATION_180,
|
||||
MICROBIT_DISPLAY_ROTATION_270
|
||||
};
|
||||
|
||||
struct MatrixPoint {
|
||||
uint8_t x;
|
||||
uint8_t y;
|
||||
|
@ -103,7 +104,6 @@ class MicroBitDisplay : public MicroBitComponent
|
|||
uint8_t mode;
|
||||
uint8_t greyscaleBitMsk;
|
||||
uint8_t timingCount;
|
||||
uint16_t nonce;
|
||||
Timeout renderTimer;
|
||||
|
||||
MicroBitFont font;
|
||||
|
@ -115,10 +115,10 @@ class MicroBitDisplay : public MicroBitComponent
|
|||
// The animation mode that's currently running (if any)
|
||||
AnimationMode animationMode;
|
||||
|
||||
// The time (in ticks) between each frame update.
|
||||
// The time in milliseconds between each frame update.
|
||||
uint16_t animationDelay;
|
||||
|
||||
// The time (in ticks) since the frame update.
|
||||
// The time in milliseconds since the frame update.
|
||||
uint16_t animationTick;
|
||||
|
||||
// Stop playback of any animations
|
||||
|
@ -221,6 +221,11 @@ class MicroBitDisplay : public MicroBitComponent
|
|||
*/
|
||||
void sendAnimationCompleteEvent();
|
||||
|
||||
/**
|
||||
* Blocks the current fiber until the display is available (i.e. not effect is being displayed).
|
||||
* Animations are queued until their time to display.
|
||||
*/
|
||||
void waitForFreeDisplay();
|
||||
|
||||
public:
|
||||
// The mutable bitmap buffer being rendered to the LED matrix.
|
||||
|
@ -242,64 +247,55 @@ public:
|
|||
MicroBitDisplay(uint16_t id, uint8_t x, uint8_t y);
|
||||
|
||||
/**
|
||||
* Resets the current given animation.
|
||||
* @param delay the delay after which the animation is reset.
|
||||
* Stops any currently running animation, and any that are waiting to be displayed.
|
||||
*/
|
||||
void resetAnimation(uint16_t delay);
|
||||
void stopAnimation();
|
||||
|
||||
/**
|
||||
* Frame update method, invoked periodically to strobe the display.
|
||||
*/
|
||||
virtual void systemTick();
|
||||
|
||||
/**
|
||||
* Prints the given character to the display, if it is not in use.
|
||||
*
|
||||
* @param c The character to display.
|
||||
* @param delay Optional parameter - the time for which to show the character. Zero displays the character forever.
|
||||
* @return MICROBIT_OK, MICROBIT_BUSY is the screen is in use, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.printAsync('p');
|
||||
* uBit.display.printAsync('p',100);
|
||||
* @endcode
|
||||
*/
|
||||
int printAsync(char c, int delay = 0);
|
||||
|
||||
/**
|
||||
* Prints the given string to the display, one character at a time.
|
||||
* Uses the given delay between characters.
|
||||
* Returns immediately, and executes the animation asynchronously.
|
||||
*
|
||||
* @param s The string to display.
|
||||
* @param delay The time to delay between characters, in timer ticks.
|
||||
* @param delay The time to delay between characters, in milliseconds. Must be > 0.
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.printAsync("abc123",400);
|
||||
* @endcode
|
||||
*/
|
||||
void printAsync(ManagedString s, int delay = MICROBIT_DEFAULT_PRINT_SPEED);
|
||||
int printAsync(ManagedString s, int delay = MICROBIT_DEFAULT_PRINT_SPEED);
|
||||
|
||||
/**
|
||||
* Prints the given character to the display.
|
||||
*
|
||||
* @param c The character to display.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.print('p');
|
||||
* @endcode
|
||||
*/
|
||||
void print(char c, int delay = 0);
|
||||
|
||||
/**
|
||||
* Prints the given string to the display, one character at a time.
|
||||
* Uses the given delay between characters.
|
||||
* Blocks the calling thread until all the text has been displayed.
|
||||
*
|
||||
* @param s The string to display.
|
||||
* @param delay The time to delay between characters, in timer ticks.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.print("abc123",400);
|
||||
* @endcode
|
||||
*/
|
||||
void print(ManagedString s, int delay = MICROBIT_DEFAULT_PRINT_SPEED);
|
||||
|
||||
/**
|
||||
* Prints the given image to the display.
|
||||
* Blocks the calling thread until all the text has been displayed.
|
||||
* Prints the given image to the display, if the display is not in use.
|
||||
* Returns immediately, and executes the animation asynchronously.
|
||||
*
|
||||
* @param i The image to display.
|
||||
* @param delay The time to delay between characters, in timer ticks.
|
||||
* @param x The horizontal position on the screen to display the image (default 0)
|
||||
* @param y The vertical position on the screen to display the image (default 0)
|
||||
* @param alpha Treats the brightness level '0' as transparent (default 0)
|
||||
* @param delay The time to delay between characters, in milliseconds. set to 0 to display forever. (default 0).
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -307,7 +303,53 @@ public:
|
|||
* uBit.display.print(i,400);
|
||||
* @endcode
|
||||
*/
|
||||
void print(MicroBitImage i, int x, int y, int alpha, int delay = MICROBIT_DEFAULT_PRINT_SPEED);
|
||||
int printAsync(MicroBitImage i, int x, int y, int alpha, int delay = 0);
|
||||
|
||||
/**
|
||||
* Prints the given character to the display.
|
||||
*
|
||||
* @param c The character to display.
|
||||
* @param delay The time to delay between characters, in milliseconds. Must be > 0.
|
||||
* @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.print('p');
|
||||
* @endcode
|
||||
*/
|
||||
int print(char c, int delay = 0);
|
||||
|
||||
/**
|
||||
* Prints the given string to the display, one character at a time.
|
||||
* Uses the given delay between characters.
|
||||
* Blocks the calling thread until all the text has been displayed.
|
||||
*
|
||||
* @param s The string to display.
|
||||
* @param delay The time to delay between characters, in milliseconds. Must be > 0.
|
||||
* @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.print("abc123",400);
|
||||
* @endcode
|
||||
*/
|
||||
int print(ManagedString s, int delay = MICROBIT_DEFAULT_PRINT_SPEED);
|
||||
|
||||
/**
|
||||
* Prints the given image to the display.
|
||||
* Blocks the calling thread until all the text has been displayed.
|
||||
*
|
||||
* @param i The image to display.
|
||||
* @param delay The time to display the image for, or zero to show the image forever. Must be >= 0.
|
||||
* @return MICROBIT_OK, MICROBIT_BUSY if the display is already in use, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* MicrobitImage i("1,1,1,1,1\n1,1,1,1,1\n");
|
||||
* uBit.display.print(i,400);
|
||||
* @endcode
|
||||
*/
|
||||
int print(MicroBitImage i, int x, int y, int alpha, int delay = 0);
|
||||
|
||||
/**
|
||||
* Scrolls the given string to the display, from right to left.
|
||||
|
@ -315,21 +357,24 @@ public:
|
|||
* Returns immediately, and executes the animation asynchronously.
|
||||
*
|
||||
* @param s The string to display.
|
||||
* @param delay The time to delay between characters, in timer ticks.
|
||||
* @param delay The time to delay between each update to the display, in milliseconds. Must be > 0.
|
||||
* @return MICROBIT_OK, MICROBIT_BUSY if the display is already in use, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.scrollAsync("abc123",100);
|
||||
* @endcode
|
||||
*/
|
||||
void scrollAsync(ManagedString s, int delay = MICROBIT_DEFAULT_SCROLL_SPEED);
|
||||
int scrollAsync(ManagedString s, int delay = MICROBIT_DEFAULT_SCROLL_SPEED);
|
||||
|
||||
/**
|
||||
* Scrolls the given image across the display, from right to left.
|
||||
* Returns immediately, and executes the animation asynchronously.
|
||||
*
|
||||
* @param image The image to display.
|
||||
* @param delay The time to delay between each scroll update, in timer ticks. Has a default.
|
||||
* @param stride The number of pixels to move in each quantum. Has a default.
|
||||
* @param delay The time to delay between each update to the display, in milliseconds. Must be > 0.
|
||||
* @param stride The number of pixels to move in each update. Default value is the screen width.
|
||||
* @return MICROBIT_OK, MICROBIT_BUSY if the display is already in use, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -337,7 +382,7 @@ public:
|
|||
* uBit.display.scrollAsync(i,100,1);
|
||||
* @endcode
|
||||
*/
|
||||
void scrollAsync(MicroBitImage image, int delay = MICROBIT_DEFAULT_SCROLL_SPEED, int stride = MICROBIT_DEFAULT_SCROLL_STRIDE);
|
||||
int scrollAsync(MicroBitImage image, int delay = MICROBIT_DEFAULT_SCROLL_SPEED, int stride = MICROBIT_DEFAULT_SCROLL_STRIDE);
|
||||
|
||||
/**
|
||||
* Scrolls the given string to the display, from right to left.
|
||||
|
@ -345,22 +390,24 @@ public:
|
|||
* Blocks the calling thread until all the text has been displayed.
|
||||
*
|
||||
* @param s The string to display.
|
||||
* @param delay The time to delay between characters, in timer ticks.
|
||||
* @param delay The time to delay between each update to the display, in milliseconds. Must be > 0.
|
||||
* @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.scroll("abc123",100);
|
||||
* @endcode
|
||||
*/
|
||||
void scroll(ManagedString s, int delay = MICROBIT_DEFAULT_SCROLL_SPEED);
|
||||
int scroll(ManagedString s, int delay = MICROBIT_DEFAULT_SCROLL_SPEED);
|
||||
|
||||
/**
|
||||
* Scrolls the given image across the display, from right to left.
|
||||
* Blocks the calling thread until all the text has been displayed.
|
||||
*
|
||||
* @param image The image to display.
|
||||
* @param delay The time to delay between each scroll update, in timer ticks. Has a default.
|
||||
* @param stride The number of pixels to move in each quantum. Has a default.
|
||||
* @param delay The time to delay between each update to the display, in milliseconds. Must be > 0.
|
||||
* @param stride The number of pixels to move in each update. Default value is the screen width.
|
||||
* @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -368,15 +415,16 @@ public:
|
|||
* uBit.display.scroll(i,100,1);
|
||||
* @endcode
|
||||
*/
|
||||
void scroll(MicroBitImage image, int delay = MICROBIT_DEFAULT_SCROLL_SPEED, int stride = MICROBIT_DEFAULT_SCROLL_STRIDE);
|
||||
int scroll(MicroBitImage image, int delay = MICROBIT_DEFAULT_SCROLL_SPEED, int stride = MICROBIT_DEFAULT_SCROLL_STRIDE);
|
||||
|
||||
/**
|
||||
* "Animates" the current image across the display with a given stride, finishing on the last frame of the animation.
|
||||
* Returns immediately.
|
||||
*
|
||||
* @param image The image to display.
|
||||
* @param delay The time to delay between each animation update, in timer ticks. Has a default.
|
||||
* @param stride The number of pixels to move in each quantum. Has a default.
|
||||
* @param delay The time to delay between each update to the display, in milliseconds. Must be > 0.
|
||||
* @param stride The number of pixels to move in each update. Default value is the screen width.
|
||||
* @return MICROBIT_OK, MICROBIT_BUSY if the screen is in use, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -388,15 +436,16 @@ public:
|
|||
* uBit.display.animateAsync(i,100,5);
|
||||
* @endcode
|
||||
*/
|
||||
void animateAsync(MicroBitImage image, int delay, int stride, int startingPosition = MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS);
|
||||
int animateAsync(MicroBitImage image, int delay, int stride, int startingPosition = MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS);
|
||||
|
||||
/**
|
||||
* "Animates" the current image across the display with a given stride, finishing on the last frame of the animation.
|
||||
* Blocks the calling thread until the animation is complete.
|
||||
*
|
||||
* @param image The image to display.
|
||||
* @param delay The time to delay between each animation update, in timer ticks. Has a default.
|
||||
* @param stride The number of pixels to move in each quantum. Has a default.
|
||||
* @param delay The time to delay between each update to the display, in milliseconds. Must be > 0.
|
||||
* @param stride The number of pixels to move in each update. Default value is the screen width.
|
||||
* @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -408,19 +457,19 @@ public:
|
|||
* uBit.display.animate(i,100,5);
|
||||
* @endcode
|
||||
*/
|
||||
void animate(MicroBitImage image, int delay, int stride, int startingPosition = MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS);
|
||||
int animate(MicroBitImage image, int delay, int stride, int startingPosition = MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS);
|
||||
|
||||
/**
|
||||
* Sets the display brightness to the specified level.
|
||||
* @param b The brightness to set the brightness to, in the range 0..255.
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.setBrightness(255); //max brightness
|
||||
* @endcode
|
||||
*/
|
||||
void setBrightness(int b);
|
||||
|
||||
int setBrightness(int b);
|
||||
|
||||
/**
|
||||
* Sets the mode of the display.
|
||||
|
@ -453,7 +502,7 @@ public:
|
|||
* uBit.display.rotateTo(MICROBIT_DISPLAY_ROTATION_180); //rotates 180 degrees from original orientation
|
||||
* @endcode
|
||||
*/
|
||||
void rotateTo(uint8_t position);
|
||||
void rotateTo(DisplayRotation position);
|
||||
|
||||
/**
|
||||
* Enables the display, should only be called if the display is disabled.
|
||||
|
|
|
@ -170,8 +170,9 @@ void fiber_wait_for_event(uint16_t id, uint16_t value);
|
|||
* We only create an additional fiber if that function performs a block operation.
|
||||
*
|
||||
* @param entry_fn The function to execute.
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
|
||||
*/
|
||||
void invoke(void (*entry_fn)(void));
|
||||
int invoke(void (*entry_fn)(void));
|
||||
|
||||
/**
|
||||
* Executes the given function asynchronously if necessary.
|
||||
|
@ -183,9 +184,10 @@ void invoke(void (*entry_fn)(void));
|
|||
* We only create an additional fiber if that function performs a block operation.
|
||||
*
|
||||
* @param entry_fn The function to execute.
|
||||
* @param param an untyped parameter passed into the entry_fn anf completion_fn.
|
||||
* @param param an untyped parameter passed into the entry_fn and completion_fn.
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
|
||||
*/
|
||||
void invoke(void (*entry_fn)(void *), void *param);
|
||||
int invoke(void (*entry_fn)(void *), void *param);
|
||||
|
||||
/**
|
||||
* Resizes the stack allocation of the current fiber if necessary to hold the system stack.
|
||||
|
|
|
@ -35,8 +35,29 @@
|
|||
// Flag to indicate that a given block is FREE/USED
|
||||
#define MICROBIT_HEAP_BLOCK_FREE 0x80000000
|
||||
|
||||
/**
|
||||
* Initialise the microbit heap according to the parameters defined in MicroBitConfig.h
|
||||
* After this is called, any future calls to malloc, new, free or delete will use the new heap.
|
||||
* n.b. only code that #includes MicroBitHeapAllocator.h will use this heap. This includes all micro:bit runtime
|
||||
* code, and user code targetting the runtime. External code can choose to include this file, or
|
||||
* simply use the standard mbed heap.
|
||||
*
|
||||
* @return MICROBIT_OK on success, or MICROBIT_NO_RESOURCES if the heap could not be allocted.
|
||||
*/
|
||||
int microbit_heap_init();
|
||||
|
||||
/**
|
||||
* Attempt to allocate a given amount of memory from any of our configured heap areas.
|
||||
* @param size The amount of memory, in bytes, to allocate.
|
||||
* @return A pointer to the allocated memory, or NULL if insufficient memory is available.
|
||||
*/
|
||||
void *microbit_malloc(size_t size);
|
||||
|
||||
|
||||
/**
|
||||
* Release a given area of memory from the heap.
|
||||
* @param mem The memory area to release.
|
||||
*/
|
||||
void microbit_free(void *mem);
|
||||
|
||||
/*
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
/**
|
||||
* Class definition for MicroBitI2C.
|
||||
*
|
||||
* Represents a wrapped mbed call to hopefully fix silicon issues once and for all.
|
||||
* Presents a wrapped mbed call to capture failed I2C operations caused by a known silicon bug in the nrf51822.
|
||||
* Attempts to automatically reset and restart the I2C hardware if this case is detected.
|
||||
*/
|
||||
class MicroBitI2C : public I2C
|
||||
{
|
||||
|
||||
uint8_t retries;
|
||||
|
||||
public:
|
||||
|
@ -30,8 +30,28 @@ class MicroBitI2C : public I2C
|
|||
*/
|
||||
MicroBitI2C(PinName sda, PinName scl);
|
||||
|
||||
/**
|
||||
* Performs a complete read transaction. The bottom bit of the address is forced to 1 to indicate a read.
|
||||
*
|
||||
* @address 8-bit I2C slave address [ addr | 1 ]
|
||||
* @data Pointer to the byte-array to read data in to
|
||||
* @length Number of bytes to read
|
||||
* @repeated Repeated start, true - don't send stop at end.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if an unresolved read failure is detected.
|
||||
*/
|
||||
int read(int address, char *data, int length, bool repeated = false);
|
||||
|
||||
/**
|
||||
* Performs a complete write transaction. The bottom bit of the address is forced to 0 to indicate a write.
|
||||
*
|
||||
* @address 8-bit I2C slave address [ addr | 0 ]
|
||||
* @data Pointer to the byte-arraycontaining the data to write
|
||||
* @length Number of bytes to write
|
||||
* @repeated Repeated start, true - don't send stop at end.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if an unresolved write failure is detected.
|
||||
*/
|
||||
int write(int address, const char *data, int length, bool repeated = false);
|
||||
};
|
||||
|
||||
|
|
|
@ -206,6 +206,7 @@ class MicroBitImage
|
|||
* @param x The co-ordinate of the pixel to change w.r.t. top left origin.
|
||||
* @param y The co-ordinate of the pixel to change w.r.t. top left origin.
|
||||
* @param value The new value of the pixel (the brightness level 0-255)
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -213,11 +214,14 @@ class MicroBitImage
|
|||
* i.setPixelValue(0,0,255);
|
||||
* @endcode
|
||||
*/
|
||||
void setPixelValue(int16_t x , int16_t y, uint8_t value);
|
||||
int setPixelValue(int16_t x , int16_t y, uint8_t value);
|
||||
|
||||
/**
|
||||
* Determines the value of a given pixel.
|
||||
* @return The value assigned to the given pixel location (the brightness level 0-255)
|
||||
*
|
||||
* @param x The x co-ordinate of the pixel to read. Must be within the dimensions of the image.
|
||||
* @param y The y co-ordinate of the pixel to read. Must be within the dimensions of the image.
|
||||
* @return The value assigned to the given pixel location (the brightness level 0-255), or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -232,9 +236,10 @@ class MicroBitImage
|
|||
* 2D array representing the image.
|
||||
* Origin is in the top left corner of the image.
|
||||
*
|
||||
* @param x the width of the image.
|
||||
* @param y the height of the image.
|
||||
* @param x the width of the image. Must be within the dimensions of the image.
|
||||
* @param y the width of the image. Must be within the dimensions of the image.
|
||||
* @param bitmap a 2D array representing the image.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -243,7 +248,7 @@ class MicroBitImage
|
|||
* i.printImage(0,0,heart);
|
||||
* @endcode
|
||||
*/
|
||||
void printImage(int16_t x, int16_t y, const uint8_t *bitmap);
|
||||
int printImage(int16_t x, int16_t y, const uint8_t *bitmap);
|
||||
|
||||
/**
|
||||
* Pastes a given bitmap at the given co-ordinates.
|
||||
|
@ -253,7 +258,7 @@ class MicroBitImage
|
|||
* @param x The leftmost X co-ordinate in this image where the given image should be pasted.
|
||||
* @param y The uppermost Y co-ordinate in this image where the given image should be pasted.
|
||||
* @param alpha set to 1 if transparency clear pixels in given image should be treated as transparent. Set to 0 otherwise.
|
||||
* @return The number of pixels written.
|
||||
* @return The number of pixels written, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -270,6 +275,7 @@ class MicroBitImage
|
|||
* @param c The character to display.
|
||||
* @param x The x co-ordinate of on the image to place the top left of the character
|
||||
* @param y The y co-ordinate of on the image to place the top left of the character
|
||||
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -277,12 +283,13 @@ class MicroBitImage
|
|||
* i.print('a',0,0);
|
||||
* @endcode
|
||||
*/
|
||||
void print(char c, int16_t x, int16_t y);
|
||||
int print(char c, int16_t x, int16_t y);
|
||||
|
||||
/**
|
||||
* Shifts the pixels in this Image a given number of pixels to the Left.
|
||||
*
|
||||
* @param n The number of pixels to shift.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -291,12 +298,13 @@ class MicroBitImage
|
|||
* i.shiftLeft(5); //displays a small heart :)
|
||||
* @endcode
|
||||
*/
|
||||
void shiftLeft(int16_t n);
|
||||
int shiftLeft(int16_t n);
|
||||
|
||||
/**
|
||||
* Shifts the pixels in this Image a given number of pixels to the Right.
|
||||
*
|
||||
* @param n The number of pixels to shift.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -306,12 +314,13 @@ class MicroBitImage
|
|||
* i.shiftRight(5); //displays a big heart :)
|
||||
* @endcode
|
||||
*/
|
||||
void shiftRight(int16_t n);
|
||||
int shiftRight(int16_t n);
|
||||
|
||||
/**
|
||||
* Shifts the pixels in this Image a given number of pixels to Upward.
|
||||
*
|
||||
* @param n The number of pixels to shift.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -320,12 +329,13 @@ class MicroBitImage
|
|||
* i.shiftUp(1);
|
||||
* @endcode
|
||||
*/
|
||||
void shiftUp(int16_t n);
|
||||
int shiftUp(int16_t n);
|
||||
|
||||
/**
|
||||
* Shifts the pixels in this Image a given number of pixels to Downward.
|
||||
*
|
||||
* @param n The number of pixels to shift.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -334,7 +344,7 @@ class MicroBitImage
|
|||
* i.shiftDown(1);
|
||||
* @endcode
|
||||
*/
|
||||
void shiftDown(int16_t n);
|
||||
int shiftDown(int16_t n);
|
||||
|
||||
/**
|
||||
* Gets the width of this image.
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#define MESSAGE_BUS_LISTENER_DROP_IF_BUSY 0x0020
|
||||
#define MESSAGE_BUS_LISTENER_NONBLOCKING 0x0040
|
||||
#define MESSAGE_BUS_LISTENER_URGENT 0x0080
|
||||
#define MESSAGE_BUS_LISTENER_DELETING 0x8000
|
||||
|
||||
#define MESSAGE_BUS_LISTENER_IMMEDIATE (MESSAGE_BUS_LISTENER_NONBLOCKING | MESSAGE_BUS_LISTENER_URGENT)
|
||||
|
||||
|
||||
|
|
|
@ -64,10 +64,11 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
* or the constructors provided by MicroBitEvent.
|
||||
*
|
||||
* @param evt The event to send.
|
||||
* @param mask The type of listeners to process (optional). Matches MicroBitListener flags. If not defined, all standard listeners will be processed.
|
||||
* @return The 1 if all matching listeners were processed, 0 if further processing is required.
|
||||
* @param urgent The type of listeners to process (optional). If set to true, only listeners defined as urgent and non-blocking will be processed
|
||||
* otherwise, all other (standard) listeners will be processed.
|
||||
* @return 1 if all matching listeners were processed, 0 if further processing is required.
|
||||
*/
|
||||
int process(MicroBitEvent &evt, uint32_t mask = MESSAGE_BUS_LISTENER_REENTRANT | MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY | MESSAGE_BUS_LISTENER_DROP_IF_BUSY | MESSAGE_BUS_LISTENER_NONBLOCKING);
|
||||
int process(MicroBitEvent &evt, bool urgent = false);
|
||||
|
||||
/**
|
||||
* Register a listener function.
|
||||
|
@ -78,7 +79,9 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
* @param value The value of messages to listen for. Events with any other values will be filtered.
|
||||
* Use MICROBIT_EVT_ANY to receive events of any value.
|
||||
*
|
||||
* @param hander The function to call when an event is received.
|
||||
* @param handler The function to call when an event is received.
|
||||
*
|
||||
* @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -89,7 +92,7 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
* uBit.MessageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); // call function when ever a click event is detected.
|
||||
* @endcode
|
||||
*/
|
||||
void listen(int id, int value, void (*handler)(MicroBitEvent), uint16_t flags = MESSAGE_BUS_LISTENER_DEFAULT_FLAGS);
|
||||
int listen(int id, int value, void (*handler)(MicroBitEvent), uint16_t flags = MESSAGE_BUS_LISTENER_DEFAULT_FLAGS);
|
||||
|
||||
/**
|
||||
* Register a listener function.
|
||||
|
@ -102,6 +105,8 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
*
|
||||
* @param hander The function to call when an event is received.
|
||||
*
|
||||
* @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* void onButtonBClick(void *arg)
|
||||
|
@ -111,7 +116,7 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
* uBit.MessageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick); // call function when ever a click event is detected.
|
||||
* @endcode
|
||||
*/
|
||||
void listen(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg, uint16_t flags = MESSAGE_BUS_LISTENER_DEFAULT_FLAGS);
|
||||
int listen(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg, uint16_t flags = MESSAGE_BUS_LISTENER_DEFAULT_FLAGS);
|
||||
|
||||
/**
|
||||
* Register a listener function.
|
||||
|
@ -124,6 +129,8 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
*
|
||||
* @param hander The function to call when an event is received.
|
||||
*
|
||||
* @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* void SomeClass::onButtonBClick()
|
||||
|
@ -136,7 +143,7 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
* @endcode
|
||||
*/
|
||||
template <typename T>
|
||||
void listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent), uint16_t flags = MESSAGE_BUS_LISTENER_DEFAULT_FLAGS);
|
||||
int listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent), uint16_t flags = MESSAGE_BUS_LISTENER_DEFAULT_FLAGS);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -146,6 +153,8 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
* @param id The Event ID used to register the listener.
|
||||
* @param value The Event VALUE used to register the listener.
|
||||
* @param handler The function used to register the listener.
|
||||
*
|
||||
* @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER
|
||||
*
|
||||
*
|
||||
* Example:
|
||||
|
@ -158,7 +167,7 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
* uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
|
||||
* @endcode
|
||||
*/
|
||||
void ignore(int id, int value, void (*handler)(MicroBitEvent));
|
||||
int ignore(int id, int value, void (*handler)(MicroBitEvent));
|
||||
|
||||
/**
|
||||
* Unregister a listener function.
|
||||
|
@ -168,6 +177,7 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
* @param value The Event VALUE used to register the listener.
|
||||
* @param handler The function used to register the listener.
|
||||
*
|
||||
* @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -179,7 +189,7 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
* uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
|
||||
* @endcode
|
||||
*/
|
||||
void ignore(int id, int value, void (*handler)(MicroBitEvent, void*));
|
||||
int ignore(int id, int value, void (*handler)(MicroBitEvent, void*));
|
||||
|
||||
/**
|
||||
* Unregister a listener function.
|
||||
|
@ -189,6 +199,7 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
* @param value The Event VALUE used to register the listener.
|
||||
* @param handler The function used to register the listener.
|
||||
*
|
||||
* @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -203,7 +214,7 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
* @endcode
|
||||
*/
|
||||
template <typename T>
|
||||
void ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent));
|
||||
int ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent));
|
||||
|
||||
/**
|
||||
* Returns the microBitListener with the given position in our list.
|
||||
|
@ -212,25 +223,33 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
*/
|
||||
MicroBitListener *elementAt(int n);
|
||||
|
||||
/**
|
||||
* Returns a 'nonce' for use with the NONCE_ID channel of the message bus.
|
||||
*/
|
||||
uint16_t nonce();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Add the given MicroBitListener to the list of event handlers, unconditionally.
|
||||
* @param listener The MicroBitListener to validate.
|
||||
* @return 1 if the listener is valid, 0 otherwise.
|
||||
* @param listener The MicroBitListener to add.
|
||||
* @return MICROBIT_OK if the listener is valid, MICROBIT_INVALID_PARAMETER otherwise.
|
||||
*/
|
||||
int add(MicroBitListener *newListener);
|
||||
|
||||
/**
|
||||
* Remove the given MicroBitListener from the list of event handlers.
|
||||
* @param listener The MicroBitListener to remove.
|
||||
* @return MICROBIT_OK if the listener is valid, MICROBIT_INVALID_PARAMETER otherwise.
|
||||
*/
|
||||
int remove(MicroBitListener *newListener);
|
||||
|
||||
/**
|
||||
* Cleanup any MicroBitListeners marked for deletion from the list.
|
||||
* @return The number of listeners removed from the list.
|
||||
*/
|
||||
int deleteMarkedListeners();
|
||||
|
||||
MicroBitListener *listeners; // Chain of active listeners.
|
||||
MicroBitEventQueueItem *evt_queue_head; // Head of queued events to be processed.
|
||||
MicroBitEventQueueItem *evt_queue_tail; // Tail of queued events to be processed.
|
||||
uint16_t nonce_val; // The last nonce issued.
|
||||
uint16_t queueLength; // The number of events currently waiting to be processed.
|
||||
|
||||
void queueEvent(MicroBitEvent &evt);
|
||||
MicroBitEventQueueItem* dequeueEvent();
|
||||
|
@ -240,7 +259,7 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
};
|
||||
|
||||
/**
|
||||
* A registrationt function to allow C++ member funcitons (methods) to be registered as an event
|
||||
* A registration function to allow C++ member funcitons (methods) to be registered as an event
|
||||
* listener.
|
||||
*
|
||||
* @param id The source of messages to listen for. Events sent from any other IDs will be filtered.
|
||||
|
@ -250,18 +269,23 @@ class MicroBitMessageBus : public MicroBitComponent
|
|||
* Use MICROBIT_EVT_ANY to receive events of any value.
|
||||
*
|
||||
* @param object The object on which the method should be invoked.
|
||||
* @param hander The method to call when an event is received.
|
||||
* @param handler The method to call when an event is received.
|
||||
*
|
||||
* @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER
|
||||
*/
|
||||
template <typename T>
|
||||
void MicroBitMessageBus::listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent), uint16_t flags)
|
||||
int MicroBitMessageBus::listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent), uint16_t flags)
|
||||
{
|
||||
if (object == NULL || handler == NULL)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
MicroBitListener *newListener = new MicroBitListener(id, value, object, handler, flags);
|
||||
|
||||
if(!add(newListener))
|
||||
if(add(newListener) == MICROBIT_OK)
|
||||
return MICROBIT_OK;
|
||||
|
||||
delete newListener;
|
||||
return MICROBIT_NO_RESOURCES;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -272,6 +296,7 @@ void MicroBitMessageBus::listen(uint16_t id, uint16_t value, T* object, void (T:
|
|||
* @param value The Event VALUE used to register the listener.
|
||||
* @param handler The function used to register the listener.
|
||||
*
|
||||
* @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -284,13 +309,15 @@ void MicroBitMessageBus::listen(uint16_t id, uint16_t value, T* object, void (T:
|
|||
* @endcode
|
||||
*/
|
||||
template <typename T>
|
||||
void MicroBitMessageBus::ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent))
|
||||
int MicroBitMessageBus::ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(MicroBitEvent))
|
||||
{
|
||||
if (handler == NULL)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
MicroBitListener listener(id, value, object, handler);
|
||||
remove(&listener);
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
|
||||
#include "MicroBit.h"
|
||||
|
||||
#define MICROBIT_MULTI_BUTTON_STATE_1 1
|
||||
#define MICROBIT_MULTI_BUTTON_STATE_2 2
|
||||
#define MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_1 4
|
||||
#define MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_2 8
|
||||
#define MICROBIT_MULTI_BUTTON_STATE_1 0x01
|
||||
#define MICROBIT_MULTI_BUTTON_STATE_2 0x02
|
||||
#define MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_1 0x04
|
||||
#define MICROBIT_MULTI_BUTTON_HOLD_TRIGGERED_2 0x08
|
||||
#define MICROBIT_MULTI_BUTTON_SUPRESSED_1 0X10
|
||||
#define MICROBIT_MULTI_BUTTON_SUPRESSED_2 0x20
|
||||
|
||||
/**
|
||||
* Class definition for MicroBitMultiButton.
|
||||
|
@ -22,8 +24,10 @@ class MicroBitMultiButton : public MicroBitComponent
|
|||
uint16_t otherSubButton(uint16_t b);
|
||||
int isSubButtonPressed(uint16_t button);
|
||||
int isSubButtonHeld(uint16_t button);
|
||||
int isSubButtonSupressed(uint16_t button);
|
||||
void setButtonState(uint16_t button, int value);
|
||||
void setHoldState(uint16_t button, int value);
|
||||
void setSupressedState(uint16_t button, int value);
|
||||
|
||||
public:
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ class MicroBitPin : public MicroBitComponent
|
|||
* Create a Button representation with the given ID.
|
||||
* @param id the ID of the new Pin object.
|
||||
* @param name the pin name for this MicroBitPin instance to represent
|
||||
* @param capability the capability of this pin, can it only be digital? can it only be analog? can it be both?
|
||||
* @param capability the capability of this pin.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -89,18 +89,20 @@ class MicroBitPin : public MicroBitComponent
|
|||
/**
|
||||
* Configures this IO pin as a digital output (if necessary) and sets the pin to 'value'.
|
||||
* @param value 0 (LO) or 1 (HI)
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
|
||||
* if the given pin does not have digital capability.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
|
||||
* P0.setDigitalValue(1); // P0 is now HI!
|
||||
* P0.setDigitalValue(1); // P0 is now HI
|
||||
* @endcode
|
||||
*/
|
||||
void setDigitalValue(int value);
|
||||
int setDigitalValue(int value);
|
||||
|
||||
/**
|
||||
* Configures this IO pin as a digital input (if necessary) and tests its current value.
|
||||
* @return 1 if this input is high, 0 otherwise.
|
||||
* @return 1 if this input is high, 0 if input is LO, or MICROBIT_NOT_SUPPORTED if the given pin does not have analog capability.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -111,22 +113,22 @@ class MicroBitPin : public MicroBitComponent
|
|||
int getDigitalValue();
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analogue output (if necessary and possible).
|
||||
* Change the DAC value to the given level.
|
||||
* @param value the level to set on the output pin, in the range 0..???
|
||||
* @note NOT IN USE, but may exist in the future if we do some clever rejigging! :)
|
||||
* Configures this IO pin as an analog/pwm output, and change the output value to the given level.
|
||||
* @param value the level to set on the output pin, in the range 0 - 1024
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
|
||||
* if the given pin does not have analog capability.
|
||||
*/
|
||||
void setAnalogValue(int value);
|
||||
int setAnalogValue(int value);
|
||||
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analogue input (if necessary and possible).
|
||||
* @return the current analogue level on the pin, in the range 0-0xFFFF
|
||||
* @return the current analogue level on the pin, in the range 0 - 1024, or MICROBIT_NOT_SUPPORTED if the given pin does not have analog capability.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
|
||||
* P0.getAnalogValue(); // P0 is a value in the range of 0 - 0xFFFF
|
||||
* P0.getAnalogValue(); // P0 is a value in the range of 0 - 1024
|
||||
* @endcode
|
||||
*/
|
||||
int getAnalogValue();
|
||||
|
@ -157,7 +159,7 @@ class MicroBitPin : public MicroBitComponent
|
|||
|
||||
/**
|
||||
* 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 if not, or MICROBIT_NOT_SUPPORTED if this pin does not support touch capability.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -172,17 +174,21 @@ class MicroBitPin : public MicroBitComponent
|
|||
|
||||
/**
|
||||
* Configures the PWM period of the analog output to the given value.
|
||||
* If this pin is not configured as an analog output, the operation
|
||||
* has no effect.
|
||||
*
|
||||
* @param period The new period for the analog output in milliseconds.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* given pin is not configured as an analog output.
|
||||
*/
|
||||
void setAnalogPeriod(int period);
|
||||
int setAnalogPeriod(int period);
|
||||
|
||||
/**
|
||||
* Same thing as setAnalogPeriodUs, but with microseconds.
|
||||
* Configures the PWM period of the analog output to the given value.
|
||||
*
|
||||
* @param period The new period for the analog output in microseconds.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* given pin is not configured as an analog output.
|
||||
*/
|
||||
void setAnalogPeriodUs(int period);
|
||||
int setAnalogPeriodUs(int period);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "microbit-dal",
|
||||
"version": "1.2.4",
|
||||
"version": "1.3.6",
|
||||
"license": "Apache2",
|
||||
"description": "The runtime library for the BBC micro:bit, developed by Lancaster University",
|
||||
"keywords": [
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# This file is no longer auto-generated to make the repository builds with GCC
|
||||
# and ARMCC no matter what.
|
||||
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
cmake_minimum_required(VERSION 2.8.12)
|
||||
|
||||
enable_language(ASM)
|
||||
|
||||
|
@ -43,7 +43,7 @@ set(YOTTA_AUTO_MICROBIT-DAL_CPP_FILES
|
|||
execute_process(WORKING_DIRECTORY "../../yotta_modules/${PROJECT_NAME}" COMMAND "git" "log" "--pretty=format:%h" "-n" "1" OUTPUT_VARIABLE git_hash)
|
||||
execute_process(WORKING_DIRECTORY "../../yotta_modules/${PROJECT_NAME}" COMMAND "git" "rev-parse" "--abbrev-ref" "HEAD" OUTPUT_VARIABLE git_branch OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
if (${git_branch} STREQUAL "master")
|
||||
if ("${git_branch}" STREQUAL "master")
|
||||
set(MICROBIT_DAL_VERSION_STRING "${YOTTA_MICROBIT_DAL_VERSION_STRING}")
|
||||
else()
|
||||
set(MICROBIT_DAL_VERSION_STRING "${YOTTA_MICROBIT_DAL_VERSION_STRING}-${git_branch}-g${git_hash}")
|
||||
|
@ -81,3 +81,9 @@ target_link_libraries(microbit-dal
|
|||
ble
|
||||
ble-nrf51822
|
||||
)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
target_compile_options(mbed-classic PRIVATE "-w")
|
||||
target_compile_options(ble PRIVATE "-w")
|
||||
target_compile_options(ble-nrf51822 PRIVATE "-w")
|
||||
endif()
|
||||
|
|
|
@ -139,17 +139,17 @@ ManagedString::ManagedString(const ManagedString &s1, const ManagedString &s2)
|
|||
* 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
|
||||
* @param length The number of characters to use.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* ManagedString s("abcdefg",7); // this is generally used for substring... why not use a normal char * constructor?
|
||||
* ManagedString s("abcdefg",7);
|
||||
* @endcode
|
||||
*/
|
||||
ManagedString::ManagedString(const char *str, const int16_t length)
|
||||
{
|
||||
// Sanity check. Return EmptyString for anything distasteful
|
||||
if (str == NULL || *str == 0 || length > strlen(str))
|
||||
if (str == NULL || *str == 0 || (uint16_t)length > strlen(str)) // XXX length should be unsigned on the interface
|
||||
{
|
||||
initEmpty();
|
||||
return;
|
||||
|
|
|
@ -33,6 +33,9 @@ microbit_reset()
|
|||
*/
|
||||
void bleDisconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
|
||||
{
|
||||
(void) handle; /* -Wunused-param */
|
||||
(void) reason; /* -Wunused-param */
|
||||
|
||||
uBit.ble->startAdvertising();
|
||||
}
|
||||
|
||||
|
@ -58,13 +61,11 @@ void bleDisconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t r
|
|||
MicroBit::MicroBit() :
|
||||
flags(0x00),
|
||||
i2c(MICROBIT_PIN_SDA, MICROBIT_PIN_SCL),
|
||||
#if CONFIG_DISABLED(MICROBIT_DBG)
|
||||
serial(USBTX, USBRX),
|
||||
#endif
|
||||
MessageBus(),
|
||||
display(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_WIDTH, MICROBIT_DISPLAY_HEIGHT),
|
||||
buttonA(MICROBIT_ID_BUTTON_A,MICROBIT_PIN_BUTTON_A),
|
||||
buttonB(MICROBIT_ID_BUTTON_B,MICROBIT_PIN_BUTTON_B),
|
||||
buttonA(MICROBIT_ID_BUTTON_A,MICROBIT_PIN_BUTTON_A, MICROBIT_BUTTON_SIMPLE_EVENTS),
|
||||
buttonB(MICROBIT_ID_BUTTON_B,MICROBIT_PIN_BUTTON_B, MICROBIT_BUTTON_SIMPLE_EVENTS),
|
||||
buttonAB(MICROBIT_ID_BUTTON_AB,MICROBIT_ID_BUTTON_A,MICROBIT_ID_BUTTON_B),
|
||||
accelerometer(MICROBIT_ID_ACCELEROMETER, MMA8653_DEFAULT_ADDR),
|
||||
compass(MICROBIT_ID_COMPASS, MAG3110_DEFAULT_ADDR),
|
||||
|
@ -92,6 +93,9 @@ MicroBit::MicroBit() :
|
|||
*/
|
||||
void MicroBit::init()
|
||||
{
|
||||
// Set the default baud rate for the serial port.`
|
||||
uBit.serial.baud(115200);
|
||||
|
||||
//add the display to the systemComponent array
|
||||
addSystemComponent(&uBit.display);
|
||||
|
||||
|
@ -254,25 +258,28 @@ void MicroBit::reset()
|
|||
* 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?
|
||||
* @note Values of below below the scheduling period (typical 6ms) tend to lose resolution.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.sleep(20); //sleep for 20ms
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBit::sleep(int milliseconds)
|
||||
int MicroBit::sleep(int milliseconds)
|
||||
{
|
||||
//sanity check, we can't time travel... (yet?)
|
||||
if(milliseconds < 0)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if (flags & MICROBIT_FLAG_SCHEDULER_RUNNING)
|
||||
fiber_sleep(milliseconds);
|
||||
else
|
||||
wait_ms(milliseconds);
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -298,7 +305,7 @@ int MicroBit::random(int max)
|
|||
{
|
||||
//return MICROBIT_INVALID_VALUE if max is <= 0...
|
||||
if(max <= 0)
|
||||
return MICROBIT_INVALID_VALUE;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// Cycle the LFSR (Linear Feedback Shift Register).
|
||||
// We use an optimal sequence with a period of 2^32-1, as defined by Bruce Schneider here (a true legend in the field!),
|
||||
|
@ -378,9 +385,11 @@ void MicroBit::systemTasks()
|
|||
|
||||
/**
|
||||
* add a component to the array of 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.
|
||||
* @note this will be converted into a dynamic list of components
|
||||
*/
|
||||
void MicroBit::addSystemComponent(MicroBitComponent *component)
|
||||
int MicroBit::addSystemComponent(MicroBitComponent *component)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
|
@ -388,16 +397,19 @@ void MicroBit::addSystemComponent(MicroBitComponent *component)
|
|||
i++;
|
||||
|
||||
if(i == MICROBIT_SYSTEM_COMPONENTS)
|
||||
return;
|
||||
return MICROBIT_NO_RESOURCES;
|
||||
|
||||
systemTickComponents[i] = component;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove a component from the array of components
|
||||
* @param component The component to remove.
|
||||
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMTER is returned if the given component has not been previous added.
|
||||
* @note this will be converted into a dynamic list of components
|
||||
*/
|
||||
void MicroBit::removeSystemComponent(MicroBitComponent *component)
|
||||
int MicroBit::removeSystemComponent(MicroBitComponent *component)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
|
@ -405,16 +417,20 @@ void MicroBit::removeSystemComponent(MicroBitComponent *component)
|
|||
i++;
|
||||
|
||||
if(i == MICROBIT_SYSTEM_COMPONENTS)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
systemTickComponents[i] = NULL;
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* add a component to the array of 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.
|
||||
* @note this will be converted into a dynamic list of components
|
||||
*/
|
||||
void MicroBit::addIdleComponent(MicroBitComponent *component)
|
||||
int MicroBit::addIdleComponent(MicroBitComponent *component)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
|
@ -422,16 +438,20 @@ void MicroBit::addIdleComponent(MicroBitComponent *component)
|
|||
i++;
|
||||
|
||||
if(i == MICROBIT_IDLE_COMPONENTS)
|
||||
return;
|
||||
return MICROBIT_NO_RESOURCES;
|
||||
|
||||
idleThreadComponents[i] = component;
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove a component from the array of components
|
||||
* @param component The component to remove.
|
||||
* @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMTER is returned if the given component has not been previous added.
|
||||
* @note this will be converted into a dynamic list of components
|
||||
*/
|
||||
void MicroBit::removeIdleComponent(MicroBitComponent *component)
|
||||
int MicroBit::removeIdleComponent(MicroBitComponent *component)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
|
@ -439,9 +459,11 @@ void MicroBit::removeIdleComponent(MicroBitComponent *component)
|
|||
i++;
|
||||
|
||||
if(i == MICROBIT_IDLE_COMPONENTS)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
idleThreadComponents[i] = NULL;
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -462,7 +484,7 @@ unsigned long MicroBit::systemTime()
|
|||
* @return A textual description of the currentlt executing micro:bit runtime.
|
||||
* TODO: handle overflow case.
|
||||
*/
|
||||
char *MicroBit::systemVersion()
|
||||
const char *MicroBit::systemVersion()
|
||||
{
|
||||
return MICROBIT_DAL_VERSION;
|
||||
}
|
||||
|
|
|
@ -12,11 +12,14 @@
|
|||
* in this object. The nearest values are chosen to those defined
|
||||
* that are supported by the hardware. The instance variables are then
|
||||
* updated to reflect reality.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if the accelerometer could not be configured.
|
||||
*/
|
||||
void MicroBitAccelerometer::configure()
|
||||
int MicroBitAccelerometer::configure()
|
||||
{
|
||||
const MMA8653SampleRangeConfig *actualSampleRange;
|
||||
const MMA8653SampleRateConfig *actualSampleRate;
|
||||
int result;
|
||||
|
||||
// First find the nearest sample rate to that specified.
|
||||
actualSampleRate = &MMA8653SampleRate[MMA8653_SAMPLE_RATES-1];
|
||||
|
@ -44,22 +47,36 @@ void MicroBitAccelerometer::configure()
|
|||
|
||||
// Now configure the accelerometer accordingly.
|
||||
// First place the device into standby mode, so it can be configured.
|
||||
writeCommand(MMA8653_CTRL_REG1, 0x00);
|
||||
result = writeCommand(MMA8653_CTRL_REG1, 0x00);
|
||||
if (result != 0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
// Enable high precisiosn mode. This consumes a bit more power, but still only 184 uA!
|
||||
writeCommand(MMA8653_CTRL_REG2, 0x10);
|
||||
result = writeCommand(MMA8653_CTRL_REG2, 0x10);
|
||||
if (result != 0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
// Enable the INT1 interrupt pin.
|
||||
writeCommand(MMA8653_CTRL_REG4, 0x01);
|
||||
result = writeCommand(MMA8653_CTRL_REG4, 0x01);
|
||||
if (result != 0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
// Select the DATA_READY event source to be routed to INT1
|
||||
writeCommand(MMA8653_CTRL_REG5, 0x01);
|
||||
result = writeCommand(MMA8653_CTRL_REG5, 0x01);
|
||||
if (result != 0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
// Configure for the selected g range.
|
||||
writeCommand(MMA8653_XYZ_DATA_CFG, actualSampleRange->xyz_data_cfg);
|
||||
result = writeCommand(MMA8653_XYZ_DATA_CFG, actualSampleRange->xyz_data_cfg);
|
||||
if (result != 0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
// Bring the device back online, with 10bit wide samples at the requested frequency.
|
||||
writeCommand(MMA8653_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01);
|
||||
result = writeCommand(MMA8653_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01);
|
||||
if (result != 0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,14 +85,15 @@ void MicroBitAccelerometer::configure()
|
|||
*
|
||||
* @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.
|
||||
*/
|
||||
void MicroBitAccelerometer::writeCommand(uint8_t reg, uint8_t value)
|
||||
int MicroBitAccelerometer::writeCommand(uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t command[2];
|
||||
command[0] = reg;
|
||||
command[1] = value;
|
||||
|
||||
uBit.i2c.write(address, (const char *)command, 2);
|
||||
return uBit.i2c.write(address, (const char *)command, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,11 +103,24 @@ void MicroBitAccelerometer::writeCommand(uint8_t reg, uint8_t value)
|
|||
* @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.
|
||||
*/
|
||||
void MicroBitAccelerometer::readCommand(uint8_t reg, uint8_t* buffer, int length)
|
||||
int MicroBitAccelerometer::readCommand(uint8_t reg, uint8_t* buffer, int length)
|
||||
{
|
||||
uBit.i2c.write(address, (const char *)®, 1, true);
|
||||
uBit.i2c.read(address, (char *)buffer, length);
|
||||
int result;
|
||||
|
||||
if (buffer == NULL || length <= 0 )
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
result = uBit.i2c.write(address, (const char *)®, 1, true);
|
||||
if (result !=0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
result = uBit.i2c.read(address, (char *)buffer, length);
|
||||
if (result !=0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,15 +145,13 @@ MicroBitAccelerometer::MicroBitAccelerometer(uint16_t id, uint16_t address) : sa
|
|||
this->sampleRange = 2;
|
||||
|
||||
// Configure and enable the accelerometer.
|
||||
this->configure();
|
||||
|
||||
// indicate that we're ready to receive tick callbacks.
|
||||
if (this->configure() == MICROBIT_OK)
|
||||
uBit.flags |= MICROBIT_FLAG_ACCELEROMETER_RUNNING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to determine the 8 bit ID from the accelerometer.
|
||||
* @return the 8 bit ID returned by the accelerometer
|
||||
* @return the 8 bit ID returned by the accelerometer, or MICROBIT_I2C_ERROR if the request fails.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -132,20 +161,29 @@ MicroBitAccelerometer::MicroBitAccelerometer(uint16_t id, uint16_t address) : sa
|
|||
int MicroBitAccelerometer::whoAmI()
|
||||
{
|
||||
uint8_t data;
|
||||
int result;
|
||||
|
||||
result = readCommand(MMA8653_WHOAMI, &data, 1);
|
||||
if (result !=0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
readCommand(MMA8653_WHOAMI, &data, 1);
|
||||
return (int)data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void MicroBitAccelerometer::update()
|
||||
int MicroBitAccelerometer::update()
|
||||
{
|
||||
int8_t data[6];
|
||||
int result;
|
||||
|
||||
readCommand(MMA8653_OUT_X_MSB, (uint8_t *)data, 6);
|
||||
result = readCommand(MMA8653_OUT_X_MSB, (uint8_t *)data, 6);
|
||||
if (result !=0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
// read MSB values...
|
||||
sample.x = data[0];
|
||||
|
@ -175,6 +213,8 @@ void MicroBitAccelerometer::update()
|
|||
|
||||
// Indicate that a new sample is available
|
||||
MicroBitEvent e(id, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE);
|
||||
|
||||
return MICROBIT_OK;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -182,11 +222,12 @@ void MicroBitAccelerometer::update()
|
|||
* 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.
|
||||
*/
|
||||
void MicroBitAccelerometer::setPeriod(int period)
|
||||
int MicroBitAccelerometer::setPeriod(int period)
|
||||
{
|
||||
this->samplePeriod = period;
|
||||
this->configure();
|
||||
return this->configure();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -203,11 +244,12 @@ int MicroBitAccelerometer::getPeriod()
|
|||
* n.b. the requested range may not be possible on the hardware. In this case, the
|
||||
* nearest lower rate is chosen.
|
||||
* @param range The requested sample range of samples, in g.
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR is the request fails.
|
||||
*/
|
||||
void MicroBitAccelerometer::setRange(int range)
|
||||
int MicroBitAccelerometer::setRange(int range)
|
||||
{
|
||||
this->sampleRange = range;
|
||||
this->configure();
|
||||
return this->configure();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,17 +18,16 @@
|
|||
* MICROBIT_BUTTON_EVT_UP
|
||||
* MICROBIT_BUTTON_EVT_CLICK
|
||||
* MICROBIT_BUTTON_EVT_LONG_CLICK
|
||||
* MICROBIT_BUTTON_EVT_DOUBLE_CLICK
|
||||
* MICROBIT_BUTTON_EVT_HOLD
|
||||
* @endcode
|
||||
*/
|
||||
MicroBitButton::MicroBitButton(uint16_t id, PinName name, PinMode mode) : pin(name, mode)
|
||||
MicroBitButton::MicroBitButton(uint16_t id, PinName name, MicroBitButtonEventConfiguration eventConfiguration, PinMode mode) : pin(name, mode)
|
||||
{
|
||||
this->id = id;
|
||||
this->name = name;
|
||||
this->eventConfiguration = eventConfiguration;
|
||||
this->downStartTime = 0;
|
||||
this->sigma = 0;
|
||||
this->doubleClickTimer = 0;
|
||||
uBit.addSystemComponent(this);
|
||||
}
|
||||
|
||||
|
@ -72,12 +71,15 @@ void MicroBitButton::systemTick()
|
|||
status = 0;
|
||||
MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_UP);
|
||||
|
||||
if (eventConfiguration == MICROBIT_BUTTON_ALL_EVENTS)
|
||||
{
|
||||
//determine if this is a long click or a normal click and send event
|
||||
if((ticks - downStartTime) >= MICROBIT_BUTTON_LONG_CLICK_TIME)
|
||||
MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_LONG_CLICK);
|
||||
else
|
||||
MicroBitEvent evt(id,MICROBIT_BUTTON_EVT_CLICK);
|
||||
}
|
||||
}
|
||||
|
||||
//if button is pressed and the hold triggered event state is not triggered AND we are greater than the button debounce value
|
||||
if((status & MICROBIT_BUTTON_STATE) && !(status & MICROBIT_BUTTON_STATE_HOLD_TRIGGERED) && (ticks - downStartTime) >= MICROBIT_BUTTON_HOLD_TIME)
|
||||
|
|
|
@ -33,12 +33,6 @@ MicroBitCompass::MicroBitCompass(uint16_t id, uint16_t address) : average(), sam
|
|||
this->samplePeriod = 100;
|
||||
this->configure();
|
||||
|
||||
//fetch our previous average values
|
||||
average.x = read16(MAG_OFF_X_MSB);
|
||||
average.y = read16(MAG_OFF_Y_MSB);
|
||||
average.z = read16(MAG_OFF_Z_MSB);
|
||||
|
||||
if(average.x == 0 && average.y == 0 && average.z == 0)
|
||||
status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED;
|
||||
|
||||
// Indicate that we're up and running.
|
||||
|
@ -51,14 +45,15 @@ MicroBitCompass::MicroBitCompass(uint16_t id, uint16_t address) : average(), sam
|
|||
*
|
||||
* @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 magnetometer could not be accessed.
|
||||
*/
|
||||
void MicroBitCompass::writeCommand(uint8_t reg, uint8_t value)
|
||||
int MicroBitCompass::writeCommand(uint8_t reg, uint8_t value)
|
||||
{
|
||||
uint8_t command[2];
|
||||
command[0] = reg;
|
||||
command[1] = value;
|
||||
|
||||
uBit.i2c.write(address, (const char *)command, 2);
|
||||
return uBit.i2c.write(address, (const char *)command, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,10 +64,22 @@ void MicroBitCompass::writeCommand(uint8_t reg, uint8_t value)
|
|||
* @param buffer Memory area to read the data into.
|
||||
* @param length The number of bytes to read.
|
||||
*/
|
||||
void MicroBitCompass::readCommand(uint8_t reg, uint8_t* buffer, int length)
|
||||
int MicroBitCompass::readCommand(uint8_t reg, uint8_t* buffer, int length)
|
||||
{
|
||||
uBit.i2c.write(address, (const char *)®, 1, true);
|
||||
uBit.i2c.read(address, (char *)buffer, length);
|
||||
int result;
|
||||
|
||||
if (buffer == NULL || length <= 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
result = uBit.i2c.write(address, (const char *)®, 1, true);
|
||||
if (result !=0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
result = uBit.i2c.read(address, (char *)buffer, length);
|
||||
if (result !=0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -81,19 +88,25 @@ void MicroBitCompass::readCommand(uint8_t reg, uint8_t* buffer, int length)
|
|||
* 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.
|
||||
* @return The register value, interpreted as a 16 but signed value, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed.
|
||||
*/
|
||||
int16_t MicroBitCompass::read16(uint8_t reg)
|
||||
int MicroBitCompass::read16(uint8_t reg)
|
||||
{
|
||||
uint8_t cmd[2];
|
||||
int result;
|
||||
|
||||
cmd[0] = reg;
|
||||
uBit.i2c.write(address, (const char *)cmd, 1);
|
||||
result = uBit.i2c.write(address, (const char *)cmd, 1);
|
||||
if (result !=0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
cmd[0] = 0x00;
|
||||
cmd[1] = 0x00;
|
||||
|
||||
uBit.i2c.read(address, (char *)cmd, 2);
|
||||
result = uBit.i2c.read(address, (char *)cmd, 2);
|
||||
if (result !=0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
return (int16_t) ((cmd[1] | (cmd[0] << 8))); //concatenate the MSB and LSB
|
||||
}
|
||||
|
||||
|
@ -102,14 +115,17 @@ int16_t MicroBitCompass::read16(uint8_t reg)
|
|||
* 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.
|
||||
* @return The register value, interpreted as a 8 bit unsigned value, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed.
|
||||
*/
|
||||
uint8_t MicroBitCompass::read8(uint8_t reg)
|
||||
int MicroBitCompass::read8(uint8_t reg)
|
||||
{
|
||||
uint8_t data;
|
||||
int result;
|
||||
|
||||
data = 0;
|
||||
readCommand(reg, (uint8_t*) &data, 1);
|
||||
result = readCommand(reg, (uint8_t*) &data, 1);
|
||||
if (result != MICROBIT_OK)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -128,12 +144,12 @@ uint8_t MicroBitCompass::read8(uint8_t reg)
|
|||
int MicroBitCompass::heading()
|
||||
{
|
||||
if(status & MICROBIT_COMPASS_STATUS_CALIBRATING)
|
||||
return MICROBIT_COMPASS_IS_CALIBRATING;
|
||||
return MICROBIT_CALIBRATION_IN_PROGRESS;
|
||||
|
||||
else if(!(status & MICROBIT_COMPASS_STATUS_CALIBRATED))
|
||||
{
|
||||
MicroBitEvent(id, MICROBIT_COMPASS_EVT_CAL_REQUIRED);
|
||||
return MICROBIT_COMPASS_CALIBRATE_REQUIRED;
|
||||
return MICROBIT_CALIBRATION_REQUIRED;
|
||||
}
|
||||
|
||||
float bearing = (atan2((double)(sample.y - average.y),(double)(sample.x - average.x)))*180/PI;
|
||||
|
@ -154,9 +170,9 @@ void MicroBitCompass::idleTick()
|
|||
// Active HI. Interrupt is cleared in data read of MAG_OUT_X_MSB.
|
||||
if(int1)
|
||||
{
|
||||
sample.x = read16(MAG_OUT_X_MSB);
|
||||
sample.y = read16(MAG_OUT_Y_MSB);
|
||||
sample.z = read16(MAG_OUT_Z_MSB);
|
||||
sample.x = (int16_t) read16(MAG_OUT_X_MSB);
|
||||
sample.y = (int16_t) read16(MAG_OUT_Y_MSB);
|
||||
sample.z = (int16_t) read16(MAG_OUT_Z_MSB);
|
||||
|
||||
if (status & MICROBIT_COMPASS_STATUS_CALIBRATING)
|
||||
{
|
||||
|
@ -230,17 +246,34 @@ int MicroBitCompass::getZ()
|
|||
* in this object. The nearest values are chosen to those defined
|
||||
* that are supported by the hardware. The instance variables are then
|
||||
* updated to reflect reality.
|
||||
* @return MICROBIT_OK or MICROBIT_I2C_ERROR if the magnetometer could not be configured.
|
||||
*/
|
||||
void MicroBitCompass::configure()
|
||||
int MicroBitCompass::configure()
|
||||
{
|
||||
const MAG3110SampleRateConfig *actualSampleRate;
|
||||
int result;
|
||||
|
||||
// First, take the device offline, so it can be configured.
|
||||
writeCommand(MAG_CTRL_REG1, 0x00);
|
||||
result = writeCommand(MAG_CTRL_REG1, 0x00);
|
||||
if (result != MICROBIT_OK)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
// Wait for the part to enter standby mode...
|
||||
while(this->read8(MAG_SYSMOD) & 0x03)
|
||||
while(1)
|
||||
{
|
||||
// Read the status of the part...
|
||||
// If we can't communicate with it over I2C, pass on the error.
|
||||
result = this->read8(MAG_SYSMOD);
|
||||
if (result == MICROBIT_I2C_ERROR)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
// if the part in in standby, we're good to carry on.
|
||||
if((result & 0x03) == 0)
|
||||
break;
|
||||
|
||||
// Perform a power efficient sleep...
|
||||
uBit.sleep(100);
|
||||
}
|
||||
|
||||
// Find the nearest sample rate to that specified.
|
||||
actualSampleRate = &MAG3110SampleRate[MAG3110_SAMPLE_RATES-1];
|
||||
|
@ -256,10 +289,17 @@ void MicroBitCompass::configure()
|
|||
this->samplePeriod = actualSampleRate->sample_period / 1000;
|
||||
|
||||
// Enable automatic reset after each sample;
|
||||
writeCommand(MAG_CTRL_REG2, 0xA0);
|
||||
result = writeCommand(MAG_CTRL_REG2, 0xA0);
|
||||
if (result != MICROBIT_OK)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
|
||||
// Bring the device online, with the requested sample frequency.
|
||||
writeCommand(MAG_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01);
|
||||
result = writeCommand(MAG_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01);
|
||||
if (result != MICROBIT_OK)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -267,11 +307,12 @@ void MicroBitCompass::configure()
|
|||
* 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 or MICROBIT_I2C_ERROR if the magnetometer could not be updated.
|
||||
*/
|
||||
void MicroBitCompass::setPeriod(int period)
|
||||
int MicroBitCompass::setPeriod(int period)
|
||||
{
|
||||
this->samplePeriod = period;
|
||||
this->configure();
|
||||
return this->configure();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -286,7 +327,7 @@ int MicroBitCompass::getPeriod()
|
|||
|
||||
/**
|
||||
* Attempts to determine the 8 bit ID from the magnetometer.
|
||||
* @return the id of the compass (magnetometer)
|
||||
* @return the id of the compass (magnetometer), or MICROBIT_I2C_ERROR if the magnetometer could not be updated.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -296,19 +337,27 @@ int MicroBitCompass::getPeriod()
|
|||
int MicroBitCompass::whoAmI()
|
||||
{
|
||||
uint8_t data;
|
||||
int result;
|
||||
|
||||
result = readCommand(MAG_WHOAMI, &data, 1);
|
||||
if (result != MICROBIT_OK)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
readCommand(MAG_WHOAMI, &data, 1);
|
||||
return (int)data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the currently die temperature of the compass.
|
||||
* @return The temperature, in degrees celsius.
|
||||
* @return the temperature in degrees celsius, or MICROBIT_I2C_ERROR if the magnetometer could not be updated.
|
||||
*/
|
||||
int MicroBitCompass::readTemperature()
|
||||
{
|
||||
int8_t temperature;
|
||||
readCommand(MAG_DIE_TEMP, (uint8_t *)&temperature, 1);
|
||||
int result;
|
||||
|
||||
result = readCommand(MAG_DIE_TEMP, (uint8_t *)&temperature, 1);
|
||||
if (result != MICROBIT_OK)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
return temperature;
|
||||
}
|
||||
|
@ -316,12 +365,13 @@ int MicroBitCompass::readTemperature()
|
|||
/**
|
||||
* Perform a calibration of the compass.
|
||||
* This will fire MICROBIT_COMPASS_EVT_CAL_START.
|
||||
* @return MICROBIT_OK, or MICROBIT_I2C_ERROR if the magnetometer could not be accessed.
|
||||
* @note THIS MUST BE CALLED TO GAIN RELIABLE VALUES FROM THE COMPASS
|
||||
*/
|
||||
void MicroBitCompass::calibrateStart()
|
||||
int MicroBitCompass::calibrateStart()
|
||||
{
|
||||
if(this->isCalibrating())
|
||||
return;
|
||||
return MICROBIT_CALIBRATION_IN_PROGRESS;
|
||||
|
||||
status |= MICROBIT_COMPASS_STATUS_CALIBRATING;
|
||||
|
||||
|
@ -330,6 +380,8 @@ void MicroBitCompass::calibrateStart()
|
|||
maxSample = sample;
|
||||
|
||||
MicroBitEvent(id, MICROBIT_COMPASS_EVT_CAL_START);
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -358,16 +410,6 @@ void MicroBitCompass::calibrateEnd()
|
|||
status &= ~MICROBIT_COMPASS_STATUS_CALIBRATING;
|
||||
status |= MICROBIT_COMPASS_STATUS_CALIBRATED;
|
||||
|
||||
//Store x, y and z values in persistent storage on the MAG3110
|
||||
writeCommand(MAG_OFF_X_LSB, (uint8_t)average.x);
|
||||
writeCommand(MAG_OFF_X_MSB, (uint8_t)(average.x >> 8));
|
||||
|
||||
writeCommand(MAG_OFF_Y_LSB, (uint8_t)average.y);
|
||||
writeCommand(MAG_OFF_Y_MSB, (uint8_t)(average.y >> 8));
|
||||
|
||||
writeCommand(MAG_OFF_Z_LSB, (uint8_t)average.z);
|
||||
writeCommand(MAG_OFF_Z_MSB, (uint8_t)(average.z >> 8));
|
||||
|
||||
MicroBitEvent(id, MICROBIT_COMPASS_EVT_CAL_END);
|
||||
}
|
||||
|
||||
|
@ -392,15 +434,6 @@ int MicroBitCompass::isCalibrating()
|
|||
*/
|
||||
void MicroBitCompass::clearCalibration()
|
||||
{
|
||||
writeCommand(MAG_OFF_X_LSB, 0);
|
||||
writeCommand(MAG_OFF_X_MSB, 0);
|
||||
|
||||
writeCommand(MAG_OFF_Y_LSB, 0);
|
||||
writeCommand(MAG_OFF_Y_MSB, 0);
|
||||
|
||||
writeCommand(MAG_OFF_Z_LSB, 0);
|
||||
writeCommand(MAG_OFF_Z_MSB, 0);
|
||||
|
||||
status &= ~MICROBIT_COMPASS_STATUS_CALIBRATED;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,18 +2,19 @@
|
|||
* Compatibility / portability funcitons and constants for the MicroBit DAL.
|
||||
*/
|
||||
#include "mbed.h"
|
||||
#include "ErrorNo.h"
|
||||
|
||||
|
||||
/**
|
||||
* Performs an in buffer reverse of a given char array
|
||||
* @param s the char* to reverse.
|
||||
* @return the reversed char*
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
|
||||
*/
|
||||
void string_reverse(char *s)
|
||||
int string_reverse(char *s)
|
||||
{
|
||||
//sanity check...
|
||||
if(s == NULL)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
char *j;
|
||||
int c;
|
||||
|
@ -26,6 +27,8 @@ void string_reverse(char *s)
|
|||
*s++ = *j;
|
||||
*j-- = c;
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,12 +36,16 @@ void string_reverse(char *s)
|
|||
*
|
||||
* @param n The number to convert.
|
||||
* @param s Pointer to a buffer in which to store the resulting string.
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
|
||||
*/
|
||||
void itoa(int n, char *s)
|
||||
int itoa(int n, char *s)
|
||||
{
|
||||
int i = 0;
|
||||
int positive = (n >= 0);
|
||||
|
||||
if (s == NULL)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// Record the sign of the number,
|
||||
// Ensure our working value is positive.
|
||||
if (positive)
|
||||
|
@ -58,5 +65,7 @@ void itoa(int n, char *s)
|
|||
|
||||
// Flip the order.
|
||||
string_reverse(s);
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ void MicroBitDisplay::renderFinish()
|
|||
//kept inline to reduce overhead
|
||||
//clear the old bit pattern for this row.
|
||||
//clear port 0 4-7 and retain lower 4 bits
|
||||
nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT0, 0xF0 | nrf_gpio_port_read(NRF_GPIO_PORT_SELECT_PORT0) & 0x0F);
|
||||
nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT0, 0xF0 | (nrf_gpio_port_read(NRF_GPIO_PORT_SELECT_PORT0) & 0x0F));
|
||||
|
||||
// clear port 1 8-12 for the current row
|
||||
nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, strobeBitMsk | 0x1F);
|
||||
|
@ -95,6 +95,7 @@ void MicroBitDisplay::renderFinish()
|
|||
|
||||
void MicroBitDisplay::render()
|
||||
{
|
||||
// Simple optimisation. If display is at zero brightness, there's nothign to do.
|
||||
if(brightness == 0)
|
||||
return;
|
||||
|
||||
|
@ -131,7 +132,7 @@ void MicroBitDisplay::render()
|
|||
|
||||
//write the new bit pattern
|
||||
//set port 0 4-7 and retain lower 4 bits
|
||||
nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT0, ~coldata<<4 & 0xF0 | nrf_gpio_port_read(NRF_GPIO_PORT_SELECT_PORT0) & 0x0F);
|
||||
nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT0, (~coldata<<4 & 0xF0) | (nrf_gpio_port_read(NRF_GPIO_PORT_SELECT_PORT0) & 0x0F));
|
||||
|
||||
//set port 1 8-12 for the current row
|
||||
nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, strobeBitMsk | (~coldata>>4 & 0x1F));
|
||||
|
@ -179,7 +180,7 @@ void MicroBitDisplay::renderGreyscale()
|
|||
}
|
||||
//write the new bit pattern
|
||||
//set port 0 4-7 and retain lower 4 bits
|
||||
nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT0, ~coldata<<4 & 0xF0 | nrf_gpio_port_read(NRF_GPIO_PORT_SELECT_PORT0) & 0x0F);
|
||||
nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT0, (~coldata<<4 & 0xF0) | (nrf_gpio_port_read(NRF_GPIO_PORT_SELECT_PORT0) & 0x0F));
|
||||
|
||||
//set port 1 8-12 for the current row
|
||||
nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, strobeBitMsk | (~coldata>>4 & 0x1F));
|
||||
|
@ -198,6 +199,7 @@ void MicroBitDisplay::renderGreyscale()
|
|||
void
|
||||
MicroBitDisplay::animationUpdate()
|
||||
{
|
||||
// If there's no ongoing animation, then nothing to do.
|
||||
if (animationMode == ANIMATION_MODE_NONE)
|
||||
return;
|
||||
|
||||
|
@ -234,10 +236,10 @@ MicroBitDisplay::animationUpdate()
|
|||
void MicroBitDisplay::sendAnimationCompleteEvent()
|
||||
{
|
||||
// Signal that we've completed an animation.
|
||||
MicroBitEvent evt1(id,MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
|
||||
MicroBitEvent(id,MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
|
||||
|
||||
// Wake up any fibers that were blocked on the animation (if any).
|
||||
MicroBitEvent evt2(MICROBIT_ID_ALERT, nonce);
|
||||
// Wake up a fiber that was blocked on the animation (if any).
|
||||
MicroBitEvent(MICROBIT_ID_NOTIFY_ONE, MICROBIT_DISPLAY_EVT_FREE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -304,7 +306,6 @@ void MicroBitDisplay::updateScrollImage()
|
|||
scrollingImageRendered = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal animateImage update method.
|
||||
* Paste the stored bitmap at the appropriate point and stop on the last frame.
|
||||
|
@ -315,6 +316,7 @@ void MicroBitDisplay::updateAnimateImage()
|
|||
if (scrollingImagePosition <= -scrollingImage.getWidth() + (MICROBIT_DISPLAY_WIDTH + scrollingImageStride) && scrollingImageRendered)
|
||||
{
|
||||
animationMode = ANIMATION_MODE_NONE;
|
||||
this->clear();
|
||||
this->sendAnimationCompleteEvent();
|
||||
return;
|
||||
}
|
||||
|
@ -331,112 +333,123 @@ void MicroBitDisplay::updateAnimateImage()
|
|||
|
||||
/**
|
||||
* Resets the current given animation.
|
||||
* @param delay the delay after which the animation is reset.
|
||||
*/
|
||||
void MicroBitDisplay::resetAnimation(uint16_t delay)
|
||||
void MicroBitDisplay::stopAnimation()
|
||||
{
|
||||
//sanitise this value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
|
||||
// Reset any ongoing animation.
|
||||
if (animationMode != ANIMATION_MODE_NONE)
|
||||
{
|
||||
animationMode = ANIMATION_MODE_NONE;
|
||||
this->sendAnimationCompleteEvent();
|
||||
|
||||
// Indicate that we've completed an animation.
|
||||
MicroBitEvent(id,MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
|
||||
|
||||
// Wake up aall fibers that may blocked on the animation (if any).
|
||||
MicroBitEvent(MICROBIT_ID_NOTIFY, MICROBIT_DISPLAY_EVT_FREE);
|
||||
}
|
||||
|
||||
// Clear the display and setup the animation timers.
|
||||
this->image.clear();
|
||||
this->animationDelay = delay;
|
||||
this->animationTick = delay-1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given string to the display, one character at a time.
|
||||
* Uses the given delay between characters.
|
||||
* Blocks the current fiber until the display is available (i.e. not effect is being displayed).
|
||||
* Animations are queued until their time to display.
|
||||
*
|
||||
*/
|
||||
void MicroBitDisplay::waitForFreeDisplay()
|
||||
{
|
||||
// If there's an ongoing animation, wait for our turn to display.
|
||||
if (animationMode != ANIMATION_MODE_NONE && animationMode != ANIMATION_MODE_STOPPED)
|
||||
fiber_wait_for_event(MICROBIT_ID_NOTIFY, MICROBIT_DISPLAY_EVT_FREE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints the given character to the display, if it is not in use.
|
||||
*
|
||||
* @param c The character to display.
|
||||
* @param delay Optional parameter - the time for which to show the character. Zero displays the character forever.
|
||||
* @return MICROBIT_OK, MICROBIT_BUSY is the screen is in use, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.printAsync('p');
|
||||
* uBit.display.printAsync('p',100);
|
||||
* @endcode
|
||||
*/
|
||||
int MicroBitDisplay::printAsync(char c, int delay)
|
||||
{
|
||||
//sanitise this value
|
||||
if(delay < 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// If the display is free, it's our turn to display.
|
||||
if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
|
||||
{
|
||||
image.print(c, 0, 0);
|
||||
|
||||
if (delay > 0)
|
||||
{
|
||||
animationDelay = delay;
|
||||
animationTick = 0;
|
||||
animationMode = ANIMATION_MODE_PRINT_CHARACTER;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return MICROBIT_BUSY;
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given string to the display, one character at a time, if the display is not in use.
|
||||
* Returns immediately, and executes the animation asynchronously.
|
||||
*
|
||||
* @param s The string to display.
|
||||
* @param delay The time to delay between characters, in timer ticks.
|
||||
* @param delay The time to delay between characters, in milliseconds. Must be > 0.
|
||||
* @return MICROBIT_OK, MICROBIT_BUSY if the display is already in use, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.printAsync("abc123",400);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitDisplay::printAsync(ManagedString s, int delay)
|
||||
int MicroBitDisplay::printAsync(ManagedString s, int delay)
|
||||
{
|
||||
//sanitise this value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
this->resetAnimation(delay);
|
||||
|
||||
this->printingChar = 0;
|
||||
this->printingText = s;
|
||||
if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
|
||||
{
|
||||
printingChar = 0;
|
||||
printingText = s;
|
||||
animationDelay = delay;
|
||||
animationTick = 0;
|
||||
|
||||
animationMode = ANIMATION_MODE_PRINT_TEXT;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MICROBIT_BUSY;
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given character to the display.
|
||||
*
|
||||
* @param c The character to display.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.print('p');
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitDisplay::print(char c, int delay)
|
||||
{
|
||||
image.print(c, 0, 0);
|
||||
|
||||
if(delay <= 0)
|
||||
return;
|
||||
|
||||
this->animationDelay = delay;
|
||||
animationMode = ANIMATION_MODE_PRINT_CHARACTER;
|
||||
|
||||
// Wait for completion.
|
||||
nonce = uBit.MessageBus.nonce();
|
||||
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given string to the display, one character at a time.
|
||||
* Uses the given delay between characters.
|
||||
* Blocks the calling thread until all the text has been displayed.
|
||||
*
|
||||
* @param s The string to display.
|
||||
* @param delay The time to delay between characters, in timer ticks.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.print("abc123",400);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitDisplay::print(ManagedString s, int delay)
|
||||
{
|
||||
//sanitise this value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
|
||||
// Start the effect.
|
||||
this->printAsync(s, delay);
|
||||
|
||||
// Wait for completion.
|
||||
nonce = uBit.MessageBus.nonce();
|
||||
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given image to the display.
|
||||
* Blocks the calling thread until all the text has been displayed.
|
||||
* Prints the given image to the display, if the display is not in use.
|
||||
* Returns immediately, and executes the animation asynchronously.
|
||||
*
|
||||
* @param i The image to display.
|
||||
* @param delay The time to delay between characters, in timer ticks.
|
||||
* @param x The horizontal position on the screen to display the image (default 0)
|
||||
* @param y The vertical position on the screen to display the image (default 0)
|
||||
* @param alpha Treats the brightness level '0' as transparent (default 0)
|
||||
* @param delay The time to delay between characters, in milliseconds. set to 0 to display forever. (default 0).
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -444,19 +457,141 @@ void MicroBitDisplay::print(ManagedString s, int delay)
|
|||
* uBit.display.print(i,400);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitDisplay::print(MicroBitImage i, int x, int y, int alpha, int delay)
|
||||
int MicroBitDisplay::printAsync(MicroBitImage i, int x, int y, int alpha, int delay)
|
||||
{
|
||||
if(delay < 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
|
||||
{
|
||||
image.paste(i, x, y, alpha);
|
||||
|
||||
if(delay <= 0)
|
||||
return;
|
||||
|
||||
this->animationDelay = delay;
|
||||
if(delay > 0)
|
||||
{
|
||||
animationDelay = delay;
|
||||
animationTick = 0;
|
||||
animationMode = ANIMATION_MODE_PRINT_CHARACTER;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return MICROBIT_BUSY;
|
||||
}
|
||||
|
||||
// Wait for completion.
|
||||
nonce = uBit.MessageBus.nonce();
|
||||
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given character to the display, and wait for it to complete.
|
||||
*
|
||||
* @param c The character to display.
|
||||
* @param delay The time to delay between characters, in milliseconds. Must be > 0.
|
||||
* @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.print('p');
|
||||
* uBit.display.print('p',100);
|
||||
* @endcode
|
||||
*/
|
||||
int MicroBitDisplay::print(char c, int delay)
|
||||
{
|
||||
if (delay < 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// If there's an ongoing animation, wait for our turn to display.
|
||||
this->waitForFreeDisplay();
|
||||
|
||||
// If the display is free, it's our turn to display.
|
||||
// If someone called stopAnimation(), then we simply skip...
|
||||
if (animationMode == ANIMATION_MODE_NONE)
|
||||
{
|
||||
this->printAsync(c, delay);
|
||||
if (delay > 0)
|
||||
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MICROBIT_CANCELLED;
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given string to the display, one character at a time.
|
||||
* Uses the given delay between characters.
|
||||
* Blocks the calling thread until all the text has been displayed.
|
||||
*
|
||||
* @param s The string to display.
|
||||
* @param delay The time to delay between characters, in milliseconds. Must be > 0.
|
||||
* @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.print("abc123",400);
|
||||
* @endcode
|
||||
*/
|
||||
int MicroBitDisplay::print(ManagedString s, int delay)
|
||||
{
|
||||
//sanitise this value
|
||||
if(delay <= 0 )
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// If there's an ongoing animation, wait for our turn to display.
|
||||
this->waitForFreeDisplay();
|
||||
|
||||
// If the display is free, it's our turn to display.
|
||||
// If someone called stopAnimation(), then we simply skip...
|
||||
if (animationMode == ANIMATION_MODE_NONE)
|
||||
{
|
||||
this->printAsync(s, delay);
|
||||
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MICROBIT_CANCELLED;
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the given image to the display.
|
||||
* Blocks the calling thread until all the text has been displayed.
|
||||
*
|
||||
* @param i The image to display.
|
||||
* @param delay The time to display the image for, or zero to show the image forever. Must be >= 0.
|
||||
* @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* MicrobitImage i("1,1,1,1,1\n1,1,1,1,1\n");
|
||||
* uBit.display.print(i,400);
|
||||
* @endcode
|
||||
*/
|
||||
int MicroBitDisplay::print(MicroBitImage i, int x, int y, int alpha, int delay)
|
||||
{
|
||||
if(delay < 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// If there's an ongoing animation, wait for our turn to display.
|
||||
this->waitForFreeDisplay();
|
||||
|
||||
// If the display is free, it's our turn to display.
|
||||
// If someone called stopAnimation(), then we simply skip...
|
||||
if (animationMode == ANIMATION_MODE_NONE)
|
||||
{
|
||||
this->printAsync(i, x, y, alpha, delay);
|
||||
if (delay > 0)
|
||||
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MICROBIT_CANCELLED;
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -465,34 +600,47 @@ void MicroBitDisplay::print(MicroBitImage i, int x, int y, int alpha, int delay)
|
|||
* Returns immediately, and executes the animation asynchronously.
|
||||
*
|
||||
* @param s The string to display.
|
||||
* @param delay The time to delay between characters, in timer ticks.
|
||||
* @param delay The time to delay between each update to the display, in milliseconds. Must be > 0.
|
||||
* @return MICROBIT_OK, MICROBIT_BUSY if the display is already in use, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.scrollAsync("abc123",100);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitDisplay::scrollAsync(ManagedString s, int delay)
|
||||
int MicroBitDisplay::scrollAsync(ManagedString s, int delay)
|
||||
{
|
||||
//sanitise this value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
if(delay <= 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
this->resetAnimation(delay);
|
||||
|
||||
this->scrollingPosition = width-1;
|
||||
this->scrollingChar = 0;
|
||||
this->scrollingText = s;
|
||||
// If the display is free, it's our turn to display.
|
||||
if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
|
||||
{
|
||||
scrollingPosition = width-1;
|
||||
scrollingChar = 0;
|
||||
scrollingText = s;
|
||||
|
||||
animationDelay = delay;
|
||||
animationTick = 0;
|
||||
animationMode = ANIMATION_MODE_SCROLL_TEXT;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MICROBIT_BUSY;
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolls the given image across the display, from right to left.
|
||||
* Returns immediately, and executes the animation asynchronously.
|
||||
*
|
||||
* @param image The image to display.
|
||||
* @param delay The time to delay between each scroll update, in timer ticks. Has a default.
|
||||
* @param stride The number of pixels to move in each quantum. Has a default.
|
||||
* @param delay The time to delay between each update to the display, in milliseconds. Must be > 0.
|
||||
* @param stride The number of pixels to move in each update. Default value is the screen width.
|
||||
* @return MICROBIT_OK, MICROBIT_BUSY if the display is already in use, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -500,20 +648,30 @@ void MicroBitDisplay::scrollAsync(ManagedString s, int delay)
|
|||
* uBit.display.scrollAsync(i,100,1);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitDisplay::scrollAsync(MicroBitImage image, int delay, int stride)
|
||||
int MicroBitDisplay::scrollAsync(MicroBitImage image, int delay, int stride)
|
||||
{
|
||||
//sanitise the delay value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
if(delay <= 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
this->resetAnimation(delay);
|
||||
|
||||
this->scrollingImagePosition = stride < 0 ? width : -image.getWidth();
|
||||
this->scrollingImageStride = stride;
|
||||
this->scrollingImage = image;
|
||||
this->scrollingImageRendered = false;
|
||||
// If the display is free, it's our turn to display.
|
||||
if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
|
||||
{
|
||||
scrollingImagePosition = stride < 0 ? width : -image.getWidth();
|
||||
scrollingImageStride = stride;
|
||||
scrollingImage = image;
|
||||
scrollingImageRendered = false;
|
||||
|
||||
animationDelay = delay;
|
||||
animationTick = 0;
|
||||
animationMode = ANIMATION_MODE_SCROLL_IMAGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MICROBIT_BUSY;
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -522,25 +680,39 @@ void MicroBitDisplay::scrollAsync(MicroBitImage image, int delay, int stride)
|
|||
* Blocks the calling thread until all the text has been displayed.
|
||||
*
|
||||
* @param s The string to display.
|
||||
* @param delay The time to delay between characters, in timer ticks.
|
||||
* @param delay The time to delay between each update to the display, in milliseconds. Must be > 0.
|
||||
* @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.scrollString("abc123",100);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitDisplay::scroll(ManagedString s, int delay)
|
||||
int MicroBitDisplay::scroll(ManagedString s, int delay)
|
||||
{
|
||||
//sanitise this value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
if(delay <= 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// If there's an ongoing animation, wait for our turn to display.
|
||||
this->waitForFreeDisplay();
|
||||
|
||||
// If the display is free, it's our turn to display.
|
||||
// If someone called stopAnimation(), then we simply skip...
|
||||
if (animationMode == ANIMATION_MODE_NONE)
|
||||
{
|
||||
// Start the effect.
|
||||
this->scrollAsync(s, delay);
|
||||
|
||||
// Wait for completion.
|
||||
nonce = uBit.MessageBus.nonce();
|
||||
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
|
||||
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MICROBIT_CANCELLED;
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -548,8 +720,9 @@ void MicroBitDisplay::scroll(ManagedString s, int delay)
|
|||
* Blocks the calling thread until all the text has been displayed.
|
||||
*
|
||||
* @param image The image to display.
|
||||
* @param delay The time to delay between each scroll update, in timer ticks. Has a default.
|
||||
* @param stride The number of pixels to move in each quantum. Has a default.
|
||||
* @param delay The time to delay between each update to the display, in milliseconds. Must be > 0.
|
||||
* @param stride The number of pixels to move in each update. Default value is the screen width.
|
||||
* @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -557,18 +730,31 @@ void MicroBitDisplay::scroll(ManagedString s, int delay)
|
|||
* uBit.display.scroll(i,100,1);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitDisplay::scroll(MicroBitImage image, int delay, int stride)
|
||||
int MicroBitDisplay::scroll(MicroBitImage image, int delay, int stride)
|
||||
{
|
||||
//sanitise the delay value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
if(delay <= 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// If there's an ongoing animation, wait for our turn to display.
|
||||
this->waitForFreeDisplay();
|
||||
|
||||
// If the display is free, it's our turn to display.
|
||||
// If someone called stopAnimation(), then we simply skip...
|
||||
if (animationMode == ANIMATION_MODE_NONE)
|
||||
{
|
||||
// Start the effect.
|
||||
this->scrollAsync(image, delay, stride);
|
||||
|
||||
// Wait for completion.
|
||||
nonce = uBit.MessageBus.nonce();
|
||||
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
|
||||
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MICROBIT_CANCELLED;
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -576,8 +762,9 @@ void MicroBitDisplay::scroll(MicroBitImage image, int delay, int stride)
|
|||
* Returns immediately.
|
||||
*
|
||||
* @param image The image to display.
|
||||
* @param delay The time to delay between each animation update, in timer ticks. Has a default.
|
||||
* @param stride The number of pixels to move in each quantum. Has a default.
|
||||
* @param delay The time to delay between each update to the display, in milliseconds. Must be > 0.
|
||||
* @param stride The number of pixels to move in each update. Default value is the screen width.
|
||||
* @return MICROBIT_OK, MICROBIT_BUSY if the screen is in use, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -589,32 +776,34 @@ void MicroBitDisplay::scroll(MicroBitImage image, int delay, int stride)
|
|||
* uBit.display.animateAsync(i,100,5);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitDisplay::animateAsync(MicroBitImage image, int delay, int stride, int startingPosition)
|
||||
int MicroBitDisplay::animateAsync(MicroBitImage image, int delay, int stride, int startingPosition)
|
||||
{
|
||||
//sanitise the delay value
|
||||
if(delay <= 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// If the display is free, we can display.
|
||||
if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
|
||||
{
|
||||
// Assume right to left functionality, to align with scrollString()
|
||||
stride = -stride;
|
||||
|
||||
//sanitise the delay value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
//calculate starting position which is offset by the stride
|
||||
scrollingImagePosition = (startingPosition == MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS) ? MICROBIT_DISPLAY_WIDTH + stride : startingPosition;
|
||||
scrollingImageStride = stride;
|
||||
scrollingImage = image;
|
||||
scrollingImageRendered = false;
|
||||
|
||||
// Reset any ongoing animation.
|
||||
if (animationMode != ANIMATION_MODE_NONE)
|
||||
animationDelay = delay;
|
||||
animationTick = delay-1;
|
||||
animationMode = ANIMATION_MODE_ANIMATE_IMAGE;
|
||||
}
|
||||
else
|
||||
{
|
||||
animationMode = ANIMATION_MODE_NONE;
|
||||
this->sendAnimationCompleteEvent();
|
||||
return MICROBIT_BUSY;
|
||||
}
|
||||
|
||||
this->animationDelay = delay;
|
||||
this->animationTick = delay-1;
|
||||
|
||||
//calculate starting position which is offset by the stride
|
||||
this->scrollingImagePosition = (startingPosition == MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS)?MICROBIT_DISPLAY_WIDTH + stride:startingPosition;
|
||||
this->scrollingImageStride = stride;
|
||||
this->scrollingImage = image;
|
||||
this->scrollingImageRendered = false;
|
||||
|
||||
animationMode = ANIMATION_MODE_ANIMATE_IMAGE;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -622,8 +811,9 @@ void MicroBitDisplay::animateAsync(MicroBitImage image, int delay, int stride, i
|
|||
* Blocks the calling thread until the animation is complete.
|
||||
*
|
||||
* @param image The image to display.
|
||||
* @param delay The time to delay between each animation update, in timer ticks. Has a default.
|
||||
* @param stride The number of pixels to move in each quantum. Has a default.
|
||||
* @param delay The time to delay between each update to the display, in milliseconds. Must be > 0.
|
||||
* @param stride The number of pixels to move in each update. Default value is the screen width.
|
||||
* @return MICROBIT_OK, MICROBIT_BUSY if the screen is in use, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -635,41 +825,56 @@ void MicroBitDisplay::animateAsync(MicroBitImage image, int delay, int stride, i
|
|||
* uBit.display.animate(i,100,5);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitDisplay::animate(MicroBitImage image, int delay, int stride, int startingPosition)
|
||||
int MicroBitDisplay::animate(MicroBitImage image, int delay, int stride, int startingPosition)
|
||||
{
|
||||
//sanitise the delay value
|
||||
if(delay <= 0 )
|
||||
delay = MICROBIT_DEFAULT_SCROLL_SPEED;
|
||||
if(delay <= 0)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// If there's an ongoing animation, wait for our turn to display.
|
||||
this->waitForFreeDisplay();
|
||||
|
||||
// If the display is free, it's our turn to display.
|
||||
// If someone called stopAnimation(), then we simply skip...
|
||||
if (animationMode == ANIMATION_MODE_NONE)
|
||||
{
|
||||
// Start the effect.
|
||||
this->animateAsync(image, delay, stride, startingPosition);
|
||||
|
||||
// Wait for completion.
|
||||
nonce = uBit.MessageBus.nonce();
|
||||
fiber_wait_for_event(MICROBIT_ID_ALERT, nonce);
|
||||
//TODO: Put this in when we merge tight-validation
|
||||
//if (delay > 0)
|
||||
fiber_wait_for_event(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_ANIMATION_COMPLETE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return MICROBIT_CANCELLED;
|
||||
}
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the display brightness to the specified level.
|
||||
* @param b The brightness to set the brightness to, in the range 0..255.
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* uBit.display.setBrightness(255); //max brightness
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitDisplay::setBrightness(int b)
|
||||
int MicroBitDisplay::setBrightness(int b)
|
||||
{
|
||||
//sanitise the brightness level
|
||||
if(b < 0 || b > 255)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
this->brightness = b;
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sets the mode of the display.
|
||||
* @param mode The mode to swap the display into. (can be either DISPLAY_MODE_GREYSCALE, or DISPLAY_MODE_NORMAL)
|
||||
|
@ -707,23 +912,9 @@ int MicroBitDisplay::getBrightness()
|
|||
* uBit.display.rotateTo(MICROBIT_DISPLAY_ROTATION_180); //rotates 180 degrees from original orientation
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitDisplay::rotateTo(uint8_t position)
|
||||
void MicroBitDisplay::rotateTo(DisplayRotation rotation)
|
||||
{
|
||||
//perform a switch on position to restrict range to distinct values
|
||||
switch(position){
|
||||
case MICROBIT_DISPLAY_ROTATION_0:
|
||||
this->rotation = MICROBIT_DISPLAY_ROTATION_0;
|
||||
break;
|
||||
case MICROBIT_DISPLAY_ROTATION_90:
|
||||
this->rotation = MICROBIT_DISPLAY_ROTATION_90;
|
||||
break;
|
||||
case MICROBIT_DISPLAY_ROTATION_180:
|
||||
this->rotation = MICROBIT_DISPLAY_ROTATION_180;
|
||||
break;
|
||||
case MICROBIT_DISPLAY_ROTATION_270:
|
||||
this->rotation = MICROBIT_DISPLAY_ROTATION_270;
|
||||
break;
|
||||
}
|
||||
this->rotation = rotation;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -785,6 +976,8 @@ void MicroBitDisplay::clear()
|
|||
*/
|
||||
void MicroBitDisplay::error(int statusCode)
|
||||
{
|
||||
extern InterruptIn resetButton;
|
||||
|
||||
__disable_irq(); //stop ALL interrupts
|
||||
|
||||
if(statusCode < 0 || statusCode > 255)
|
||||
|
@ -810,7 +1003,7 @@ void MicroBitDisplay::error(int statusCode)
|
|||
int outerCount = 0;
|
||||
|
||||
//display the current character
|
||||
while( outerCount < 50000)
|
||||
while(outerCount < 500)
|
||||
{
|
||||
int coldata = 0;
|
||||
|
||||
|
@ -842,11 +1035,17 @@ void MicroBitDisplay::error(int statusCode)
|
|||
nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT1, strobeBitMsk | (~coldata>>4 & 0x1F)); //set port 1 8-12
|
||||
|
||||
//set i to an obscene number.
|
||||
i = 100000;
|
||||
i = 1000;
|
||||
|
||||
//burn cycles
|
||||
while(i>0)
|
||||
{
|
||||
// Check if the reset button has been pressed. Interrupts are disabled, so the normal method can't be relied upon...
|
||||
if (resetButton == 0)
|
||||
microbit_reset();
|
||||
|
||||
i--;
|
||||
}
|
||||
|
||||
//update the bit mask and row count
|
||||
strobeBitMsk <<= 1;
|
||||
|
|
|
@ -83,7 +83,6 @@ void queue_fiber(Fiber *f, Fiber **queue)
|
|||
*/
|
||||
void dequeue_fiber(Fiber *f)
|
||||
{
|
||||
|
||||
// If this fiber is already dequeued, nothing the there's nothing to do.
|
||||
if (f->queue == NULL)
|
||||
return;
|
||||
|
@ -131,8 +130,8 @@ Fiber *getFiberContext()
|
|||
if (f == NULL)
|
||||
return NULL;
|
||||
|
||||
f->stack_bottom = NULL;
|
||||
f->stack_top = NULL;
|
||||
f->stack_bottom = 0;
|
||||
f->stack_top = 0;
|
||||
}
|
||||
|
||||
// Ensure this fiber is in suitable state for reuse.
|
||||
|
@ -163,6 +162,10 @@ void scheduler_init()
|
|||
idleFiber->tcb.SP = CORTEX_M0_STACK_BASE - 0x04;
|
||||
idleFiber->tcb.LR = (uint32_t) &idle_task;
|
||||
|
||||
// Register to receive events in the NOTIFY channel - this is used to implement wait-notify semantics
|
||||
uBit.MessageBus.listen(MICROBIT_ID_NOTIFY, MICROBIT_EVT_ANY, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE);
|
||||
uBit.MessageBus.listen(MICROBIT_ID_NOTIFY_ONE, MICROBIT_EVT_ANY, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE);
|
||||
|
||||
// Flag that we now have a scheduler running
|
||||
uBit.flags |= MICROBIT_FLAG_SCHEDULER_RUNNING;
|
||||
}
|
||||
|
@ -205,6 +208,7 @@ void scheduler_event(MicroBitEvent evt)
|
|||
{
|
||||
Fiber *f = waitQueue;
|
||||
Fiber *t;
|
||||
int notifyOneComplete = 0;
|
||||
|
||||
// Check the wait queue, and wake up any fibers as necessary.
|
||||
while (f != NULL)
|
||||
|
@ -215,7 +219,20 @@ void scheduler_event(MicroBitEvent evt)
|
|||
uint16_t id = f->context & 0xFFFF;
|
||||
uint16_t value = (f->context & 0xFFFF0000) >> 16;
|
||||
|
||||
if ((id == MICROBIT_ID_ANY || id == evt.source) && (value == MICROBIT_EVT_ANY || value == evt.value))
|
||||
// Special case for the NOTIFY_ONE channel...
|
||||
if ((evt.source == MICROBIT_ID_NOTIFY_ONE && id == MICROBIT_ID_NOTIFY) && (value == MICROBIT_EVT_ANY || value == evt.value))
|
||||
{
|
||||
if (!notifyOneComplete)
|
||||
{
|
||||
// Wakey wakey!
|
||||
dequeue_fiber(f);
|
||||
queue_fiber(f,&runQueue);
|
||||
notifyOneComplete = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Normal case.
|
||||
else if ((id == MICROBIT_ID_ANY || id == evt.source) && (value == MICROBIT_EVT_ANY || value == evt.value))
|
||||
{
|
||||
// Wakey wakey!
|
||||
dequeue_fiber(f);
|
||||
|
@ -226,6 +243,7 @@ void scheduler_event(MicroBitEvent evt)
|
|||
}
|
||||
|
||||
// Unregister this event, as we've woken up all the fibers with this match.
|
||||
if (evt.source != MICROBIT_ID_NOTIFY && evt.source != MICROBIT_ID_NOTIFY_ONE)
|
||||
uBit.MessageBus.ignore(evt.source, evt.value, scheduler_event);
|
||||
}
|
||||
|
||||
|
@ -248,7 +266,7 @@ void fiber_sleep(unsigned long t)
|
|||
// it's time to spawn a new fiber...
|
||||
if (currentFiber->flags & MICROBIT_FIBER_FLAG_FOB)
|
||||
{
|
||||
// Allocate a TCB from the new fiber. This will come from the tread pool if availiable,
|
||||
// Allocate a new fiber. This will come from the fiber pool if availiable,
|
||||
// else a new one will be allocated on the heap.
|
||||
forkedFiber = getFiberContext();
|
||||
|
||||
|
@ -310,6 +328,8 @@ void fiber_wait_for_event(uint16_t id, uint16_t value)
|
|||
queue_fiber(f, &waitQueue);
|
||||
|
||||
// Register to receive this event, so we can wake up the fiber when it happens.
|
||||
// Special case for teh notify channel, as we always stay registered for that.
|
||||
if (id != MICROBIT_ID_NOTIFY && id != MICROBIT_ID_NOTIFY_ONE)
|
||||
uBit.MessageBus.listen(id, value, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE);
|
||||
|
||||
// Finally, enter the scheduler.
|
||||
|
@ -326,19 +346,20 @@ void fiber_wait_for_event(uint16_t id, uint16_t value)
|
|||
* We only create an additional fiber if that function performs a block operation.
|
||||
*
|
||||
* @param entry_fn The function to execute.
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
|
||||
*/
|
||||
void invoke(void (*entry_fn)(void))
|
||||
int invoke(void (*entry_fn)(void))
|
||||
{
|
||||
// Validate our parameters.
|
||||
if (entry_fn == NULL)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if (currentFiber->flags & MICROBIT_FIBER_FLAG_FOB)
|
||||
{
|
||||
// If we attempt a fork on block whilst already in fork n block context,
|
||||
// simply launch a fiber to deal with the request and we're done.
|
||||
create_fiber(entry_fn);
|
||||
return;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
// Snapshot current context, but also update the Link Register to
|
||||
|
@ -354,7 +375,7 @@ void invoke(void (*entry_fn)(void))
|
|||
{
|
||||
currentFiber->flags &= ~MICROBIT_FIBER_FLAG_FOB;
|
||||
currentFiber->flags &= ~MICROBIT_FIBER_FLAG_PARENT;
|
||||
return;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
// Otherwise, we're here for the first time. Enter FORK ON BLOCK mode, and
|
||||
|
@ -368,6 +389,8 @@ void invoke(void (*entry_fn)(void))
|
|||
// The fiber will then re-enter the scheduler, so no need for further cleanup.
|
||||
if (currentFiber->flags & MICROBIT_FIBER_FLAG_CHILD)
|
||||
release_fiber();
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -381,19 +404,20 @@ void invoke(void (*entry_fn)(void))
|
|||
*
|
||||
* @param entry_fn The function to execute.
|
||||
* @param param an untyped parameter passed into the entry_fn.
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
|
||||
*/
|
||||
void invoke(void (*entry_fn)(void *), void *param)
|
||||
int invoke(void (*entry_fn)(void *), void *param)
|
||||
{
|
||||
// Validate our parameters.
|
||||
if (entry_fn == NULL)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if (currentFiber->flags & (MICROBIT_FIBER_FLAG_FOB | MICROBIT_FIBER_FLAG_PARENT | MICROBIT_FIBER_FLAG_CHILD))
|
||||
{
|
||||
// If we attempt a fork on block whilst already in a fork on block context,
|
||||
// simply launch a fiber to deal with the request and we're done.
|
||||
create_fiber(entry_fn, param);
|
||||
return;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
// Snapshot current context, but also update the Link Register to
|
||||
|
@ -409,7 +433,7 @@ void invoke(void (*entry_fn)(void *), void *param)
|
|||
{
|
||||
currentFiber->flags &= ~MICROBIT_FIBER_FLAG_FOB;
|
||||
currentFiber->flags &= ~MICROBIT_FIBER_FLAG_PARENT;
|
||||
return;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
// Otherwise, we're here for the first time. Enter FORK ON BLOCK mode, and
|
||||
|
@ -423,6 +447,8 @@ void invoke(void (*entry_fn)(void *), void *param)
|
|||
// The fiber will then re-enter the scheduler, so no need for further cleanup.
|
||||
if (currentFiber->flags & MICROBIT_FIBER_FLAG_CHILD)
|
||||
release_fiber(param);
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
void launch_new_fiber(void (*ep)(void), void (*cp)(void))
|
||||
|
@ -486,7 +512,7 @@ Fiber *__create_fiber(uint32_t ep, uint32_t cp, uint32_t pm, int parameterised)
|
|||
*/
|
||||
Fiber *create_fiber(void (*entry_fn)(void), void (*completion_fn)(void))
|
||||
{
|
||||
return __create_fiber((uint32_t) entry_fn, (uint32_t)completion_fn, NULL, 0);
|
||||
return __create_fiber((uint32_t) entry_fn, (uint32_t)completion_fn, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -509,6 +535,8 @@ Fiber *create_fiber(void (*entry_fn)(void *), void *param, void (*completion_fn)
|
|||
*/
|
||||
void release_fiber(void * param)
|
||||
{
|
||||
(void)param; /* -Wunused-parameter */
|
||||
|
||||
release_fiber();
|
||||
}
|
||||
|
||||
|
@ -662,7 +690,7 @@ void schedule()
|
|||
if (oldFiber == idleFiber)
|
||||
{
|
||||
// Just swap in the new fiber, and discard changes to stack and register context.
|
||||
swap_context(NULL, ¤tFiber->tcb, NULL, currentFiber->stack_top);
|
||||
swap_context(NULL, ¤tFiber->tcb, 0, currentFiber->stack_top);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -32,7 +32,7 @@ struct HeapDefinition
|
|||
|
||||
// Create the necessary heap definitions.
|
||||
// We use two heaps by default: one for SoftDevice reuse, and one to run inside the mbed heap.
|
||||
HeapDefinition heap[MICROBIT_HEAP_COUNT] = { NULL };
|
||||
HeapDefinition heap[MICROBIT_HEAP_COUNT] = { };
|
||||
|
||||
// Scans the status of the heap definition table, and returns the number of INITIALISED heaps.
|
||||
int microbit_active_heaps()
|
||||
|
@ -62,13 +62,13 @@ void microbit_heap_print(HeapDefinition &heap)
|
|||
|
||||
if (heap.heap_start == NULL)
|
||||
{
|
||||
pc.printf("--- HEAP NOT INITIALISED ---\n");
|
||||
uBit.serial.printf("--- HEAP NOT INITIALISED ---\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pc.printf("heap_start : %p\n", heap.heap_start);
|
||||
pc.printf("heap_end : %p\n", heap.heap_end);
|
||||
pc.printf("heap_size : %d\n", (int)heap.heap_end - (int)heap.heap_start);
|
||||
uBit.serial.printf("heap_start : %p\n", heap.heap_start);
|
||||
uBit.serial.printf("heap_end : %p\n", heap.heap_end);
|
||||
uBit.serial.printf("heap_size : %d\n", (int)heap.heap_end - (int)heap.heap_start);
|
||||
|
||||
// Disable IRQ temporarily to ensure no race conditions!
|
||||
__disable_irq();
|
||||
|
@ -77,10 +77,10 @@ void microbit_heap_print(HeapDefinition &heap)
|
|||
while (block < heap.heap_end)
|
||||
{
|
||||
blockSize = *block & ~MICROBIT_HEAP_BLOCK_FREE;
|
||||
pc.printf("[%C:%d] ", *block & MICROBIT_HEAP_BLOCK_FREE ? 'F' : 'U', blockSize*4);
|
||||
uBit.serialpc.printf("[%C:%d] ", *block & MICROBIT_HEAP_BLOCK_FREE ? 'F' : 'U', blockSize*4);
|
||||
if (cols++ == 20)
|
||||
{
|
||||
pc.printf("\n");
|
||||
uBit.serial.printf("\n");
|
||||
cols = 0;
|
||||
}
|
||||
|
||||
|
@ -95,10 +95,10 @@ void microbit_heap_print(HeapDefinition &heap)
|
|||
// Enable Interrupts
|
||||
__enable_irq();
|
||||
|
||||
pc.printf("\n");
|
||||
uBit.serial.printf("\n");
|
||||
|
||||
pc.printf("mb_total_free : %d\n", totalFreeBlock*4);
|
||||
pc.printf("mb_total_used : %d\n", totalUsedBlock*4);
|
||||
uBit.serial.printf("mb_total_free : %d\n", totalFreeBlock*4);
|
||||
uBit.serial.printf("mb_total_used : %d\n", totalUsedBlock*4);
|
||||
}
|
||||
|
||||
|
||||
|
@ -108,7 +108,7 @@ void microbit_heap_print()
|
|||
{
|
||||
for (int i=0; i < MICROBIT_HEAP_COUNT; i++)
|
||||
{
|
||||
pc.printf("\nHEAP %d: \n", i);
|
||||
uBit.serial.printf("\nHEAP %d: \n", i);
|
||||
microbit_heap_print(heap[i]);
|
||||
}
|
||||
}
|
||||
|
@ -137,9 +137,9 @@ microbit_create_sd_heap(HeapDefinition &heap)
|
|||
#endif
|
||||
|
||||
microbit_initialise_heap(heap);
|
||||
return 1;
|
||||
return MICROBIT_OK;
|
||||
#else
|
||||
return 0;
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -151,7 +151,7 @@ microbit_create_nested_heap(HeapDefinition &heap)
|
|||
|
||||
// Ensure we're configured to use this heap at all. If not, we can safely return.
|
||||
if (MICROBIT_HEAP_SIZE <= 0)
|
||||
return 0;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// Snapshot something at the top of the main heap.
|
||||
p = native_malloc(sizeof(uint32_t));
|
||||
|
@ -173,14 +173,14 @@ microbit_create_nested_heap(HeapDefinition &heap)
|
|||
{
|
||||
mb_heap_max -= 32;
|
||||
if (mb_heap_max <= 0)
|
||||
return 0;
|
||||
return MICROBIT_NO_RESOURCES;
|
||||
}
|
||||
}
|
||||
|
||||
heap.heap_end = heap.heap_start + mb_heap_max / MICROBIT_HEAP_BLOCK_SIZE;
|
||||
microbit_initialise_heap(heap);
|
||||
|
||||
return 1;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -188,18 +188,29 @@ microbit_create_nested_heap(HeapDefinition &heap)
|
|||
* After this is called, any future calls to malloc, new, free or delete will use the new heap.
|
||||
* n.b. only code that #includes MicroBitHeapAllocator.h will use this heap. This includes all micro:bit runtime
|
||||
* code, and user code targetting the runtime. External code can choose to include this file, or
|
||||
* simply use the strandard mbed heap.
|
||||
* simply use the standard mbed heap.
|
||||
*/
|
||||
int
|
||||
microbit_heap_init()
|
||||
{
|
||||
int r = 0;
|
||||
int result;
|
||||
|
||||
// Disable IRQ temporarily to ensure no race conditions!
|
||||
__disable_irq();
|
||||
|
||||
r += microbit_create_nested_heap(heap[0]);
|
||||
r += microbit_create_sd_heap(heap[1]);
|
||||
result = microbit_create_nested_heap(heap[0]);
|
||||
if (result != MICROBIT_OK)
|
||||
{
|
||||
__enable_irq();
|
||||
return MICROBIT_NO_RESOURCES;
|
||||
}
|
||||
|
||||
result = microbit_create_sd_heap(heap[1]);
|
||||
if (result != MICROBIT_OK)
|
||||
{
|
||||
__enable_irq();
|
||||
return MICROBIT_NO_RESOURCES;
|
||||
}
|
||||
|
||||
// Enable Interrupts
|
||||
__enable_irq();
|
||||
|
@ -207,7 +218,8 @@ microbit_heap_init()
|
|||
#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
|
||||
microbit_heap_print();
|
||||
#endif
|
||||
return r;
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -317,7 +329,7 @@ void *microbit_malloc(size_t size)
|
|||
if (p != NULL)
|
||||
{
|
||||
#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
|
||||
pc.printf("microbit_malloc: ALLOCATED: %d [%p]\n", size, p);
|
||||
pc.uBit.serial("microbit_malloc: ALLOCATED: %d [%p]\n", size, p);
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
@ -333,7 +345,7 @@ void *microbit_malloc(size_t size)
|
|||
#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
|
||||
// Keep everything trasparent if we've not been initialised yet
|
||||
if (microbit_active_heaps())
|
||||
pc.printf("microbit_malloc: NATIVE ALLOCATED: %d [%p]\n", size, p);
|
||||
pc.uBit.serial("microbit_malloc: NATIVE ALLOCATED: %d [%p]\n", size, p);
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
@ -342,7 +354,7 @@ void *microbit_malloc(size_t size)
|
|||
#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
|
||||
// Keep everything trasparent if we've not been initialised yet
|
||||
if (microbit_active_heaps())
|
||||
pc.printf("microbit_malloc: OUT OF MEMORY\n");
|
||||
pc.uBit.serial("microbit_malloc: OUT OF MEMORY\n");
|
||||
#endif
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_PANIC_HEAP_FULL)
|
||||
|
@ -363,7 +375,7 @@ void microbit_free(void *mem)
|
|||
|
||||
#if CONFIG_ENABLED(MICROBIT_DBG) && CONFIG_ENABLED(MICROBIT_HEAP_DBG)
|
||||
if (microbit_active_heaps())
|
||||
pc.printf("microbit_free: %p\n", mem);
|
||||
pc.uBit.serial("microbit_free: %p\n", mem);
|
||||
#endif
|
||||
// Sanity check.
|
||||
if (memory == NULL)
|
||||
|
|
|
@ -19,7 +19,16 @@ MicroBitI2C::MicroBitI2C(PinName sda, PinName scl) : I2C(sda,scl)
|
|||
this->retries = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs a complete read transaction. The bottom bit of the address is forced to 1 to indicate a read.
|
||||
*
|
||||
* @address 8-bit I2C slave address [ addr | 1 ]
|
||||
* @data Pointer to the byte-array to read data in to
|
||||
* @length Number of bytes to read
|
||||
* @repeated Repeated start, true - don't send stop at end.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if an unresolved read failure is detected.
|
||||
*/
|
||||
int MicroBitI2C::read(int address, char *data, int length, bool repeated)
|
||||
{
|
||||
int result = I2C::read(address,data,length,repeated);
|
||||
|
@ -38,18 +47,25 @@ int MicroBitI2C::read(int address, char *data, int length, bool repeated)
|
|||
retries++;
|
||||
}
|
||||
|
||||
if(retries == MICROBIT_I2C_MAX_RETRIES - 1)
|
||||
uBit.panic(MICROBIT_I2C_LOCKUP);
|
||||
if(result != 0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
retries = 0;
|
||||
|
||||
return result;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a complete write transaction. The bottom bit of the address is forced to 0 to indicate a write.
|
||||
*
|
||||
* @address 8-bit I2C slave address [ addr | 0 ]
|
||||
* @data Pointer to the byte-arraycontaining the data to write
|
||||
* @length Number of bytes to write
|
||||
* @repeated Repeated start, true - don't send stop at end.
|
||||
*
|
||||
* @return MICROBIT_OK on success, MICROBIT_I2C_ERROR if an unresolved write failure is detected.
|
||||
*/
|
||||
int MicroBitI2C::write(int address, const char *data, int length, bool repeated)
|
||||
{
|
||||
|
||||
|
||||
int result = I2C::write(address,data,length,repeated);
|
||||
|
||||
//0 indicates a success, presume failure
|
||||
|
@ -67,10 +83,9 @@ int MicroBitI2C::write(int address, const char *data, int length, bool repeated)
|
|||
retries++;
|
||||
}
|
||||
|
||||
if(retries == MICROBIT_I2C_MAX_RETRIES - 1)
|
||||
uBit.panic(MICROBIT_I2C_LOCKUP);
|
||||
if(result != 0)
|
||||
return MICROBIT_I2C_ERROR;
|
||||
|
||||
retries = 0;
|
||||
|
||||
return result;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
|
|
@ -338,6 +338,7 @@ void MicroBitImage::clear()
|
|||
* @param x The co-ordinate of the pixel to change w.r.t. top left origin.
|
||||
* @param y The co-ordinate of the pixel to change w.r.t. top left origin.
|
||||
* @param value The new value of the pixel (the brightness level 0-255)
|
||||
* @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -345,18 +346,22 @@ void MicroBitImage::clear()
|
|||
* i.setPixelValue(0,0,255);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitImage::setPixelValue(int16_t x , int16_t y, uint8_t value)
|
||||
int MicroBitImage::setPixelValue(int16_t x , int16_t y, uint8_t value)
|
||||
{
|
||||
//sanity check
|
||||
if(x >= getWidth() || y >= getHeight() || x < 0 || y < 0)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
this->getBitmap()[y*getWidth()+x] = value;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the value of a given pixel.
|
||||
* @return The value assigned to the given pixel location (the brightness level 0-255)
|
||||
*
|
||||
* @param x The x co-ordinate of the pixel to read. Must be within the dimensions of the image.
|
||||
* @param y The y co-ordinate of the pixel to read. Must be within the dimensions of the image.
|
||||
* @return The value assigned to the given pixel location (the brightness level 0-255), or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -368,7 +373,7 @@ int MicroBitImage::getPixelValue(int16_t x , int16_t y)
|
|||
{
|
||||
//sanity check
|
||||
if(x >= getWidth() || y >= getHeight() || x < 0 || y < 0)
|
||||
return MICROBIT_INVALID_VALUE;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
return this->getBitmap()[y*getWidth()+x];
|
||||
}
|
||||
|
@ -378,9 +383,10 @@ int MicroBitImage::getPixelValue(int16_t x , int16_t y)
|
|||
* 2D array representing the image.
|
||||
* Origin is in the top left corner of the image.
|
||||
*
|
||||
* @param x the width of the image.
|
||||
* @param y the height of the image.
|
||||
* @param x the width of the image. Must be within the dimensions of the image.
|
||||
* @param y the width of the image. Must be within the dimensions of the image.
|
||||
* @param bitmap a 2D array representing the image.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -389,7 +395,7 @@ int MicroBitImage::getPixelValue(int16_t x , int16_t y)
|
|||
* i.printImage(0,0,heart);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitImage::printImage(int16_t width, int16_t height, const uint8_t *bitmap)
|
||||
int MicroBitImage::printImage(int16_t width, int16_t height, const uint8_t *bitmap)
|
||||
{
|
||||
const uint8_t *pIn;
|
||||
uint8_t *pOut;
|
||||
|
@ -397,7 +403,7 @@ void MicroBitImage::printImage(int16_t width, int16_t height, const uint8_t *bit
|
|||
|
||||
// Sanity check.
|
||||
if (width <= 0 || width <= 0 || bitmap == NULL)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// Calcualte sane start pointer.
|
||||
pixelsToCopyX = min(width,this->getWidth());
|
||||
|
@ -413,6 +419,8 @@ void MicroBitImage::printImage(int16_t width, int16_t height, const uint8_t *bit
|
|||
pIn += width;
|
||||
pOut += this->getWidth();
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -447,7 +455,7 @@ int MicroBitImage::paste(const MicroBitImage &image, int16_t x, int16_t y, uint8
|
|||
cx = x < 0 ? min(image.getWidth() + x, getWidth()) : min(image.getWidth(), getWidth() - x);
|
||||
cy = y < 0 ? min(image.getHeight() + y, getHeight()) : min(image.getHeight(), getHeight() - y);
|
||||
|
||||
// Calcualte sane start pointer.
|
||||
// Calculate sane start pointer.
|
||||
pIn = image.ptr->data;
|
||||
pIn += (x < 0) ? -x : 0;
|
||||
pIn += (y < 0) ? -image.getWidth()*y : 0;
|
||||
|
@ -498,6 +506,7 @@ int MicroBitImage::paste(const MicroBitImage &image, int16_t x, int16_t y, uint8
|
|||
* @param c The character to display.
|
||||
* @param x The x co-ordinate of on the image to place the top left of the character
|
||||
* @param y The y co-ordinate of on the image to place the top left of the character
|
||||
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -505,7 +514,7 @@ int MicroBitImage::paste(const MicroBitImage &image, int16_t x, int16_t y, uint8
|
|||
* i.print('a',0,0);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitImage::print(char c, int16_t x, int16_t y)
|
||||
int MicroBitImage::print(char c, int16_t x, int16_t y)
|
||||
{
|
||||
unsigned char v;
|
||||
int x1, y1;
|
||||
|
@ -514,7 +523,7 @@ void MicroBitImage::print(char c, int16_t x, int16_t y)
|
|||
|
||||
// Sanity check. Silently ignore anything out of bounds.
|
||||
if (x >= getWidth() || y >= getHeight() || c < MICROBIT_FONT_ASCII_START || c > font.asciiEnd)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// Paste.
|
||||
int offset = (c-MICROBIT_FONT_ASCII_START) * 5;
|
||||
|
@ -537,6 +546,8 @@ void MicroBitImage::print(char c, int16_t x, int16_t y)
|
|||
this->getBitmap()[y1*getWidth()+x1] = (v & (0x10 >> col)) ? 255 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -544,6 +555,7 @@ void MicroBitImage::print(char c, int16_t x, int16_t y)
|
|||
* Shifts the pixels in this Image a given number of pixels to the Left.
|
||||
*
|
||||
* @param n The number of pixels to shift.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -552,18 +564,18 @@ void MicroBitImage::print(char c, int16_t x, int16_t y)
|
|||
* i.shiftLeft(5); //displays a small heart :)
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitImage::shiftLeft(int16_t n)
|
||||
int MicroBitImage::shiftLeft(int16_t n)
|
||||
{
|
||||
uint8_t *p = getBitmap();
|
||||
int pixels = getWidth()-n;
|
||||
|
||||
if (n <= 0 )
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if(n >= getWidth())
|
||||
{
|
||||
clear();
|
||||
return;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
for (int y = 0; y < getHeight(); y++)
|
||||
|
@ -573,12 +585,15 @@ void MicroBitImage::shiftLeft(int16_t n)
|
|||
memclr(p+pixels, n);
|
||||
p += getWidth();
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shifts the pixels in this Image a given number of pixels to the Right.
|
||||
*
|
||||
* @param n The number of pixels to shift.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -588,18 +603,18 @@ void MicroBitImage::shiftLeft(int16_t n)
|
|||
* i.shiftRight(5); //displays a big heart :)
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitImage::shiftRight(int16_t n)
|
||||
int MicroBitImage::shiftRight(int16_t n)
|
||||
{
|
||||
uint8_t *p = getBitmap();
|
||||
int pixels = getWidth()-n;
|
||||
|
||||
if (n <= 0)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if(n >= getWidth())
|
||||
{
|
||||
clear();
|
||||
return;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
for (int y = 0; y < getHeight(); y++)
|
||||
|
@ -609,6 +624,8 @@ void MicroBitImage::shiftRight(int16_t n)
|
|||
memclr(p, n);
|
||||
p += getWidth();
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -616,6 +633,7 @@ void MicroBitImage::shiftRight(int16_t n)
|
|||
* Shifts the pixels in this Image a given number of pixels to Upward.
|
||||
*
|
||||
* @param n The number of pixels to shift.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -624,17 +642,17 @@ void MicroBitImage::shiftRight(int16_t n)
|
|||
* i.shiftUp(1);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitImage::shiftUp(int16_t n)
|
||||
int MicroBitImage::shiftUp(int16_t n)
|
||||
{
|
||||
uint8_t *pOut, *pIn;
|
||||
|
||||
if (n <= 0 )
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if(n >= getHeight())
|
||||
{
|
||||
clear();
|
||||
return;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
pOut = getBitmap();
|
||||
|
@ -651,6 +669,8 @@ void MicroBitImage::shiftUp(int16_t n)
|
|||
pIn += getWidth();
|
||||
pOut += getWidth();
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -658,6 +678,7 @@ void MicroBitImage::shiftUp(int16_t n)
|
|||
* Shifts the pixels in this Image a given number of pixels to Downward.
|
||||
*
|
||||
* @param n The number of pixels to shift.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -666,17 +687,17 @@ void MicroBitImage::shiftUp(int16_t n)
|
|||
* i.shiftDown(1);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitImage::shiftDown(int16_t n)
|
||||
int MicroBitImage::shiftDown(int16_t n)
|
||||
{
|
||||
uint8_t *pOut, *pIn;
|
||||
|
||||
if (n <= 0 )
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
if(n >= getHeight())
|
||||
{
|
||||
clear();
|
||||
return;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
pOut = getBitmap() + getWidth()*(getHeight()-1);
|
||||
|
@ -693,6 +714,8 @@ void MicroBitImage::shiftDown(int16_t n)
|
|||
pIn -= getWidth();
|
||||
pOut -= getWidth();
|
||||
}
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ MicroBitListener::MicroBitListener(uint16_t id, uint16_t value, void (*handler)(
|
|||
this->cb_arg = NULL;
|
||||
this->flags = flags;
|
||||
this->next = NULL;
|
||||
this->evt_queue = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,6 +42,7 @@ MicroBitListener::MicroBitListener(uint16_t id, uint16_t value, void (*handler)(
|
|||
this->cb_arg = arg;
|
||||
this->flags = flags | MESSAGE_BUS_LISTENER_PARAMETERISED;
|
||||
this->next = NULL;
|
||||
this->evt_queue = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,16 +60,23 @@ MicroBitListener::~MicroBitListener()
|
|||
*/
|
||||
void MicroBitListener::queue(MicroBitEvent e)
|
||||
{
|
||||
MicroBitEventQueueItem *q = new MicroBitEventQueueItem(e);
|
||||
int queueDepth;
|
||||
|
||||
MicroBitEventQueueItem *p = evt_queue;
|
||||
|
||||
if (evt_queue == NULL)
|
||||
evt_queue = q;
|
||||
evt_queue = new MicroBitEventQueueItem(e);
|
||||
else
|
||||
{
|
||||
while (p->next != NULL)
|
||||
p = p->next;
|
||||
queueDepth = 1;
|
||||
|
||||
p->next = q;
|
||||
while (p->next != NULL)
|
||||
{
|
||||
p = p->next;
|
||||
queueDepth++;
|
||||
}
|
||||
|
||||
if (queueDepth < MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH)
|
||||
p->next = new MicroBitEventQueueItem(e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,18 +15,7 @@ MicroBitMessageBus::MicroBitMessageBus()
|
|||
this->listeners = NULL;
|
||||
this->evt_queue_head = NULL;
|
||||
this->evt_queue_tail = NULL;
|
||||
this->nonce_val = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a 'nonce' for use with the NONCE_ID channel of the message bus.
|
||||
*/
|
||||
uint16_t MicroBitMessageBus::nonce()
|
||||
{
|
||||
// In the global scheme of things, a terrible nonce generator.
|
||||
// However, for our purposes, this is simple and adequate for local use.
|
||||
// This would be a bad idea if our events were networked though - can you think why?
|
||||
return nonce_val++;
|
||||
this->queueLength = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,7 +67,7 @@ void async_callback(void *param)
|
|||
else
|
||||
listener->cb(listener->evt);
|
||||
|
||||
// If there are more events to process, dequeue te next one and process it.
|
||||
// If there are more events to process, dequeue the next one and process it.
|
||||
if ((listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY) && listener->evt_queue)
|
||||
{
|
||||
MicroBitEventQueueItem *item = listener->evt_queue;
|
||||
|
@ -86,6 +75,9 @@ void async_callback(void *param)
|
|||
listener->evt = item->evt;
|
||||
listener->evt_queue = listener->evt_queue->next;
|
||||
delete item;
|
||||
|
||||
// We spin the scheduler here, to preven any particular event handler from continuously holding onto resources.
|
||||
schedule();
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
@ -95,7 +87,6 @@ void async_callback(void *param)
|
|||
listener->flags &= ~MESSAGE_BUS_LISTENER_BUSY;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Queue the given event for processing at a later time.
|
||||
* Add the given event at the tail of our queue.
|
||||
|
@ -106,23 +97,47 @@ void MicroBitMessageBus::queueEvent(MicroBitEvent &evt)
|
|||
{
|
||||
int processingComplete;
|
||||
|
||||
// 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);
|
||||
MicroBitEventQueueItem *prev = evt_queue_tail;
|
||||
|
||||
if (!processingComplete)
|
||||
{
|
||||
// We need to queue this event for later processing...
|
||||
// Now process all handler regsitered as URGENT.
|
||||
// These pre-empt the queue, and are useful for fast, high priority services.
|
||||
processingComplete = this->process(evt, true);
|
||||
|
||||
// If we've already processed all event handlers, we're all done.
|
||||
// No need to queue the event.
|
||||
if (processingComplete)
|
||||
return;
|
||||
|
||||
// If we need to queue, but there is no space, then there's nothg we can do.
|
||||
if (queueLength >= MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH)
|
||||
return;
|
||||
|
||||
// Otherwise, we need to queue this event for later processing...
|
||||
// We queue this event at the tail of the queue at the point where we entered queueEvent()
|
||||
// This is important as the processing above *may* have generated further events, and
|
||||
// we want to maintain ordering of events.
|
||||
MicroBitEventQueueItem *item = new MicroBitEventQueueItem(evt);
|
||||
|
||||
// The queue was empty when we entered this function, so queue our event at the start of the queue.
|
||||
__disable_irq();
|
||||
|
||||
if (evt_queue_tail == NULL)
|
||||
evt_queue_head = evt_queue_tail = item;
|
||||
if (prev == NULL)
|
||||
{
|
||||
item->next = evt_queue_head;
|
||||
evt_queue_head = item;
|
||||
}
|
||||
else
|
||||
evt_queue_tail->next = item;
|
||||
{
|
||||
item->next = prev->next;
|
||||
prev->next = item;
|
||||
}
|
||||
|
||||
if (item->next == NULL)
|
||||
evt_queue_tail = item;
|
||||
|
||||
queueLength++;
|
||||
|
||||
__enable_irq();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,13 +159,55 @@ MicroBitEventQueueItem* MicroBitMessageBus::dequeueEvent()
|
|||
|
||||
if (evt_queue_head == NULL)
|
||||
evt_queue_tail = NULL;
|
||||
|
||||
queueLength--;
|
||||
}
|
||||
|
||||
__enable_irq();
|
||||
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup any MicroBitListeners marked for deletion from the list.
|
||||
* @return The number of listeners removed from the list.
|
||||
*/
|
||||
int MicroBitMessageBus::deleteMarkedListeners()
|
||||
{
|
||||
MicroBitListener *l, *p;
|
||||
int removed = 0;
|
||||
|
||||
l = listeners;
|
||||
p = NULL;
|
||||
|
||||
// Walk this list of event handlers. Delete any that match the given listener.
|
||||
while (l != NULL)
|
||||
{
|
||||
if (l->flags & MESSAGE_BUS_LISTENER_DELETING && !l->flags & MESSAGE_BUS_LISTENER_BUSY)
|
||||
{
|
||||
if (p == NULL)
|
||||
listeners = l->next;
|
||||
else
|
||||
p->next = l->next;
|
||||
|
||||
// delete the listener.
|
||||
MicroBitListener *t = l;
|
||||
l = l->next;
|
||||
|
||||
delete t;
|
||||
removed++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
p = l;
|
||||
l = l->next;
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Periodic callback from MicroBit.
|
||||
* Process at least one event from the event queue, if it is not empty.
|
||||
|
@ -158,6 +215,9 @@ MicroBitEventQueueItem* MicroBitMessageBus::dequeueEvent()
|
|||
*/
|
||||
void MicroBitMessageBus::idleTick()
|
||||
{
|
||||
// Clear out any listeners marked for deletion
|
||||
this->deleteMarkedListeners();
|
||||
|
||||
MicroBitEventQueueItem *item = this->dequeueEvent();
|
||||
|
||||
// Whilst there are events to process and we have no useful other work to do, pull them off the queue and process them.
|
||||
|
@ -210,9 +270,7 @@ void MicroBitMessageBus::send(MicroBitEvent evt)
|
|||
// We simply queue processing of the event until we're scheduled in normal thread context.
|
||||
// We do this to avoid the possibility of executing event handler code in IRQ context, which may bring
|
||||
// hidden race conditions to kids code. Queuing all events ensures causal ordering (total ordering in fact).
|
||||
|
||||
this->queueEvent(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -221,20 +279,23 @@ void MicroBitMessageBus::send(MicroBitEvent evt)
|
|||
* This will attempt to call the event handler directly, but spawn a fiber should that
|
||||
* event handler attempt a blocking operation.
|
||||
* @param evt The event to be delivered.
|
||||
* @param mask The type of listeners to process (optional). Matches MicroBitListener flags. If not defined, all standard listeners will be processed.
|
||||
* @return The 1 if all matching listeners were processed, 0 if further processing is required.
|
||||
* @param urgent The type of listeners to process (optional). If set to true, only listeners defined as urgent and non-blocking will be processed
|
||||
* otherwise, all other (standard) listeners will be processed.
|
||||
* @return 1 if all matching listeners were processed, 0 if further processing is required.
|
||||
*/
|
||||
int MicroBitMessageBus::process(MicroBitEvent &evt, uint32_t mask)
|
||||
int MicroBitMessageBus::process(MicroBitEvent &evt, bool urgent)
|
||||
{
|
||||
MicroBitListener *l;
|
||||
int complete = 1;
|
||||
bool listenerUrgent;
|
||||
|
||||
l = listeners;
|
||||
while (l != NULL)
|
||||
{
|
||||
if((l->id == evt.source || l->id == MICROBIT_ID_ANY) && (l->value == evt.value || l->value == MICROBIT_EVT_ANY))
|
||||
{
|
||||
if(l->flags & mask)
|
||||
listenerUrgent = (l->flags & MESSAGE_BUS_LISTENER_IMMEDIATE) == MESSAGE_BUS_LISTENER_IMMEDIATE;
|
||||
if(listenerUrgent == urgent && !(l->flags & MESSAGE_BUS_LISTENER_DELETING))
|
||||
{
|
||||
l->evt = evt;
|
||||
|
||||
|
@ -269,7 +330,9 @@ int MicroBitMessageBus::process(MicroBitEvent &evt, uint32_t mask)
|
|||
* @param value The value of messages to listen for. Events with any other values will be filtered.
|
||||
* Use MICROBIT_VALUE_ANY to receive events of any value.
|
||||
*
|
||||
* @param hander The function to call when an event is received.
|
||||
* @param handler The function to call when an event is received.
|
||||
*
|
||||
* @return MICROBIT_OK on success MICROBIT_INVALID_PARAMETER
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -281,26 +344,35 @@ int MicroBitMessageBus::process(MicroBitEvent &evt, uint32_t mask)
|
|||
* @endcode
|
||||
*/
|
||||
|
||||
void MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent), uint16_t flags)
|
||||
int MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent), uint16_t flags)
|
||||
{
|
||||
if (handler == NULL)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
MicroBitListener *newListener = new MicroBitListener(id, value, handler, flags);
|
||||
|
||||
if(!add(newListener))
|
||||
if(add(newListener) == MICROBIT_OK)
|
||||
return MICROBIT_OK;
|
||||
|
||||
delete newListener;
|
||||
|
||||
return MICROBIT_NO_RESOURCES;
|
||||
|
||||
}
|
||||
|
||||
void MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg, uint16_t flags)
|
||||
int MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent, void*), void* arg, uint16_t flags)
|
||||
{
|
||||
if (handler == NULL)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
MicroBitListener *newListener = new MicroBitListener(id, value, handler, arg, flags);
|
||||
|
||||
if(!add(newListener))
|
||||
if(add(newListener) == MICROBIT_OK)
|
||||
return MICROBIT_OK;
|
||||
|
||||
delete newListener;
|
||||
|
||||
return MICROBIT_NO_RESOURCES;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -322,13 +394,15 @@ void MicroBitMessageBus::listen(int id, int value, void (*handler)(MicroBitEvent
|
|||
* uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitMessageBus::ignore(int id, int value, void (*handler)(MicroBitEvent))
|
||||
int MicroBitMessageBus::ignore(int id, int value, void (*handler)(MicroBitEvent))
|
||||
{
|
||||
if (handler == NULL)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
MicroBitListener listener(id, value, handler);
|
||||
remove(&listener);
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -350,14 +424,16 @@ void MicroBitMessageBus::ignore(int id, int value, void (*handler)(MicroBitEvent
|
|||
* uBit.MessageBus.ignore(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, onButtonBClick);
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitMessageBus::ignore(int id, int value, void (*handler)(MicroBitEvent, void*))
|
||||
int MicroBitMessageBus::ignore(int id, int value, void (*handler)(MicroBitEvent, void*))
|
||||
{
|
||||
if (handler == NULL)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// The remove function is not comparing the [arg] anyhow.
|
||||
MicroBitListener listener(id, value, handler, NULL);
|
||||
remove(&listener);
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -373,7 +449,7 @@ int MicroBitMessageBus::add(MicroBitListener *newListener)
|
|||
|
||||
//handler can't be NULL!
|
||||
if (newListener == NULL)
|
||||
return 0;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
l = listeners;
|
||||
|
||||
|
@ -387,7 +463,15 @@ int MicroBitMessageBus::add(MicroBitListener *newListener)
|
|||
methodCallback = (newListener->flags & MESSAGE_BUS_LISTENER_METHOD) && (l->flags & MESSAGE_BUS_LISTENER_METHOD);
|
||||
|
||||
if (l->id == newListener->id && l->value == newListener->value && (methodCallback ? *l->cb_method == *newListener->cb_method : l->cb == newListener->cb))
|
||||
return 0;
|
||||
{
|
||||
// We have a perfect match for this event listener already registered.
|
||||
// If it's marked for deletion, we simply resurrect the listener, and we're done.
|
||||
// Either way, we return an error code, as the *new* listener should be released...
|
||||
if(l->flags & MESSAGE_BUS_LISTENER_DELETING)
|
||||
l->flags &= ~MESSAGE_BUS_LISTENER_DELETING;
|
||||
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
l = l->next;
|
||||
}
|
||||
|
@ -397,7 +481,7 @@ int MicroBitMessageBus::add(MicroBitListener *newListener)
|
|||
if (listeners == NULL)
|
||||
{
|
||||
listeners = newListener;
|
||||
return 1;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
// We maintain an ordered list of listeners.
|
||||
|
@ -436,25 +520,24 @@ int MicroBitMessageBus::add(MicroBitListener *newListener)
|
|||
p->next = newListener;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a MicroBitListener from the list that matches the given listener.
|
||||
* @param listener The MicroBitListener to validate.
|
||||
* @return The number of listeners removed from the list.
|
||||
* Remove the given MicroBitListener from the list of event handlers.
|
||||
* @param listener The MicroBitListener to remove.
|
||||
* @return MICROBIT_OK if the listener is valid, MICROBIT_INVALID_PARAMETER otherwise.
|
||||
*/
|
||||
int MicroBitMessageBus::remove(MicroBitListener *listener)
|
||||
{
|
||||
MicroBitListener *l, *p;
|
||||
MicroBitListener *l;
|
||||
int removed = 0;
|
||||
|
||||
//handler can't be NULL!
|
||||
if (listener == NULL)
|
||||
return 0;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
l = listeners;
|
||||
p = NULL;
|
||||
|
||||
// Walk this list of event handlers. Delete any that match the given listener.
|
||||
while (l != NULL)
|
||||
|
@ -466,29 +549,20 @@ int MicroBitMessageBus::remove(MicroBitListener *listener)
|
|||
{
|
||||
if ((listener->id == MICROBIT_ID_ANY || listener->id == l->id) && (listener->value == MICROBIT_EVT_ANY || listener->value == l->value))
|
||||
{
|
||||
// Found a match. Remove from the list.
|
||||
if (p == NULL)
|
||||
listeners = l->next;
|
||||
else
|
||||
p->next = l->next;
|
||||
|
||||
// delete the listener.
|
||||
MicroBitListener *t = l;
|
||||
l = l->next;
|
||||
|
||||
delete t;
|
||||
// Found a match. mark this to be removed from the list.
|
||||
l->flags |= MESSAGE_BUS_LISTENER_DELETING;
|
||||
removed++;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p = l;
|
||||
l = l->next;
|
||||
}
|
||||
|
||||
return removed;
|
||||
if (removed > 0)
|
||||
return MICROBIT_OK;
|
||||
else
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -66,6 +66,16 @@ int MicroBitMultiButton::isSubButtonHeld(uint16_t button)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int MicroBitMultiButton::isSubButtonSupressed(uint16_t button)
|
||||
{
|
||||
if (button == button1)
|
||||
return status & MICROBIT_MULTI_BUTTON_SUPRESSED_1;
|
||||
|
||||
if (button == button2)
|
||||
return status & MICROBIT_MULTI_BUTTON_SUPRESSED_2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MicroBitMultiButton::setButtonState(uint16_t button, int value)
|
||||
{
|
||||
|
@ -105,6 +115,26 @@ void MicroBitMultiButton::setHoldState(uint16_t button, int value)
|
|||
}
|
||||
}
|
||||
|
||||
void MicroBitMultiButton::setSupressedState(uint16_t button, int value)
|
||||
{
|
||||
if (button == button1)
|
||||
{
|
||||
if (value)
|
||||
status |= MICROBIT_MULTI_BUTTON_SUPRESSED_1;
|
||||
else
|
||||
status &= ~MICROBIT_MULTI_BUTTON_SUPRESSED_1;
|
||||
}
|
||||
|
||||
if (button == button2)
|
||||
{
|
||||
if (value)
|
||||
status |= MICROBIT_MULTI_BUTTON_SUPRESSED_2;
|
||||
else
|
||||
status &= ~MICROBIT_MULTI_BUTTON_SUPRESSED_2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MicroBitMultiButton::onEvent(MicroBitEvent evt)
|
||||
{
|
||||
int button = evt.source;
|
||||
|
@ -119,29 +149,39 @@ void MicroBitMultiButton::onEvent(MicroBitEvent evt)
|
|||
|
||||
break;
|
||||
|
||||
case MICROBIT_BUTTON_EVT_UP:
|
||||
setButtonState(button, 0);
|
||||
setHoldState(button, 0);
|
||||
|
||||
if(isSubButtonPressed(otherButton))
|
||||
MicroBitEvent e(id, MICROBIT_BUTTON_EVT_UP);
|
||||
break;
|
||||
|
||||
case MICROBIT_BUTTON_EVT_CLICK:
|
||||
case MICROBIT_BUTTON_EVT_LONG_CLICK:
|
||||
setButtonState(button, 0);
|
||||
setHoldState(button, 0);
|
||||
if(isSubButtonPressed(otherButton))
|
||||
MicroBitEvent e(id, evt.value);
|
||||
|
||||
break;
|
||||
|
||||
case MICROBIT_BUTTON_EVT_HOLD:
|
||||
setHoldState(button, 1);
|
||||
if(isSubButtonHeld(otherButton))
|
||||
MicroBitEvent e(id, MICROBIT_BUTTON_EVT_HOLD);
|
||||
|
||||
break;
|
||||
|
||||
case MICROBIT_BUTTON_EVT_UP:
|
||||
if(isSubButtonPressed(otherButton))
|
||||
{
|
||||
MicroBitEvent e(id, MICROBIT_BUTTON_EVT_UP);
|
||||
|
||||
if (isSubButtonHeld(button) && isSubButtonHeld(otherButton))
|
||||
MicroBitEvent e(id, MICROBIT_BUTTON_EVT_LONG_CLICK);
|
||||
else
|
||||
MicroBitEvent e(id, MICROBIT_BUTTON_EVT_CLICK);
|
||||
|
||||
setSupressedState(otherButton, 1);
|
||||
}
|
||||
else if (!isSubButtonSupressed(button))
|
||||
{
|
||||
if (isSubButtonHeld(button))
|
||||
MicroBitEvent e(button, MICROBIT_BUTTON_EVT_LONG_CLICK);
|
||||
else
|
||||
MicroBitEvent e(button, MICROBIT_BUTTON_EVT_CLICK);
|
||||
}
|
||||
|
||||
setButtonState(button, 0);
|
||||
setHoldState(button, 0);
|
||||
setSupressedState(button, 0);
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,14 +66,20 @@ void MicroBitPin::disconnect()
|
|||
* Example:
|
||||
* @code
|
||||
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
|
||||
* P0.setDigitalValue(1); // P0 is now HI!
|
||||
* P0.setDigitalValue(1); // P0 is now HI
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
|
||||
* if the given pin does not have digital capability.
|
||||
* @endcode
|
||||
*/
|
||||
void MicroBitPin::setDigitalValue(int value)
|
||||
int MicroBitPin::setDigitalValue(int value)
|
||||
{
|
||||
//check if this pin has a digital mode...
|
||||
if(!(PIN_CAPABILITY_DIGITAL & capability) || value < 0 || value > 1)
|
||||
return;
|
||||
// Check if this pin has a digital mode...
|
||||
if(!(PIN_CAPABILITY_DIGITAL & capability))
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
|
||||
// Ensure we have a valid value.
|
||||
if (value < 0 || value > 1)
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
// Move into a Digital input state if necessary.
|
||||
if (!(status & IO_STATUS_DIGITAL_OUT)){
|
||||
|
@ -82,13 +88,15 @@ void MicroBitPin::setDigitalValue(int value)
|
|||
status |= IO_STATUS_DIGITAL_OUT;
|
||||
}
|
||||
|
||||
//write the value!
|
||||
// Write the value.
|
||||
((DigitalOut *)pin)->write(value);
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures this IO pin as a digital input (if necessary) and tests its current value.
|
||||
* @return 1 if this input is high, 0 otherwise.
|
||||
* @return 1 if this input is high, 0 if input is LO, or MICROBIT_NOT_SUPPORTED if the given pin does not have analog capability.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -100,12 +108,12 @@ int MicroBitPin::getDigitalValue()
|
|||
{
|
||||
//check if this pin has a digital mode...
|
||||
if(!(PIN_CAPABILITY_DIGITAL & capability))
|
||||
return MICROBIT_IO_OP_NA;
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
|
||||
// Move into a Digital input state if necessary.
|
||||
if (!(status & IO_STATUS_DIGITAL_IN)){
|
||||
disconnect();
|
||||
pin = new DigitalIn(name,PullDown); //pull down!
|
||||
pin = new DigitalIn(name,PullDown);
|
||||
status |= IO_STATUS_DIGITAL_IN;
|
||||
}
|
||||
|
||||
|
@ -113,20 +121,20 @@ int MicroBitPin::getDigitalValue()
|
|||
}
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analogue output (if necessary and possible).
|
||||
* Change the DAC value to the given level.
|
||||
* @param value the level to set on the output pin, in the range 0..255
|
||||
* @note We have a maximum of 3 PWM channels for this device - one is reserved for the display... the other two are reconfigured dynamically when they are required.
|
||||
* Configures this IO pin as an analog/pwm output, and change the output value to the given level.
|
||||
* @param value the level to set on the output pin, in the range 0 - 1024
|
||||
* @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER if value is out of range, or MICROBIT_NOT_SUPPORTED
|
||||
* if the given pin does not have analog capability.
|
||||
*/
|
||||
void MicroBitPin::setAnalogValue(int value)
|
||||
int MicroBitPin::setAnalogValue(int value)
|
||||
{
|
||||
//check if this pin has an analogue mode...
|
||||
if(!(PIN_CAPABILITY_ANALOG & capability))
|
||||
return;
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
|
||||
//sanitise the brightness level
|
||||
if(value < 0 || value > MICROBIT_PIN_MAX_OUTPUT)
|
||||
return;
|
||||
return MICROBIT_INVALID_PARAMETER;
|
||||
|
||||
float level = (float)value / float(MICROBIT_PIN_MAX_OUTPUT);
|
||||
|
||||
|
@ -140,25 +148,26 @@ void MicroBitPin::setAnalogValue(int value)
|
|||
//perform a write with an extra check! :)
|
||||
if(((DynamicPwm *)pin)->getPinName() == name)
|
||||
((DynamicPwm *)pin)->write(level);
|
||||
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configures this IO pin as an analogue input (if necessary and possible).
|
||||
* @return the current analogue level on the pin, in the range 0-0xFFFF
|
||||
* @return the current analogue level on the pin, in the range 0 - 1024, or MICROBIT_NOT_SUPPORTED if the given pin does not have analog capability.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* MicroBitPin P0(MICROBIT_ID_IO_P0, MICROBIT_PIN_P0, PIN_CAPABILITY_BOTH);
|
||||
* P0.getAnalogValue(); // P0 is a value in the range of 0 - 0xFFFF
|
||||
* P0.getAnalogValue(); // P0 is a value in the range of 0 - 1024
|
||||
* @endcode
|
||||
*/
|
||||
int MicroBitPin::getAnalogValue()
|
||||
{
|
||||
|
||||
//check if this pin has an analogue mode...
|
||||
if(!(PIN_CAPABILITY_ANALOG & capability))
|
||||
return MICROBIT_IO_OP_NA;
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
|
||||
// Move into an analogue input state if necessary.
|
||||
if (!(status & IO_STATUS_ANALOG_IN)){
|
||||
|
@ -209,7 +218,7 @@ int MicroBitPin::isAnalog()
|
|||
|
||||
/**
|
||||
* Configures this IO pin as a makey makey style touch sensor (if necessary) and tests its current debounced state.
|
||||
* @return 1 if pin is touched, 0 otherwise.
|
||||
* @return 1 if pin is touched, 0 if not, or MICROBIT_NOT_SUPPORTED if this pin does not support touch capability.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -224,7 +233,7 @@ int MicroBitPin::isTouched()
|
|||
{
|
||||
//check if this pin has a touch mode...
|
||||
if(!(PIN_CAPABILITY_TOUCH & capability))
|
||||
return MICROBIT_IO_OP_NA;
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
|
||||
// Move into a touch input state if necessary.
|
||||
if (!(status & IO_STATUS_TOUCH_IN)){
|
||||
|
@ -238,21 +247,28 @@ int MicroBitPin::isTouched()
|
|||
|
||||
/**
|
||||
* Configures the PWM period of the analog output to the given value.
|
||||
* If this pin is not configured as an analog output, the operation
|
||||
* has no effect.
|
||||
*
|
||||
* @param period The new period for the analog output in microseconds.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* given pin is not configured as an analog output.
|
||||
*/
|
||||
void MicroBitPin::setAnalogPeriodUs(int period)
|
||||
int MicroBitPin::setAnalogPeriodUs(int period)
|
||||
{
|
||||
if (status & IO_STATUS_ANALOG_OUT)
|
||||
if (!(status & IO_STATUS_ANALOG_OUT))
|
||||
return MICROBIT_NOT_SUPPORTED;
|
||||
|
||||
((DynamicPwm *)pin)->setPeriodUs(period);
|
||||
return MICROBIT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same thing as setAnalogPeriodUs, but with milliseconds.
|
||||
* Configures the PWM period of the analog output to the given value.
|
||||
*
|
||||
* @param period The new period for the analog output in microseconds.
|
||||
* @return MICROBIT_OK on success, or MICROBIT_NOT_SUPPORTED if the
|
||||
* given pin is not configured as an analog output.
|
||||
*/
|
||||
void MicroBitPin::setAnalogPeriod(int period)
|
||||
int MicroBitPin::setAnalogPeriod(int period)
|
||||
{
|
||||
setAnalogPeriodUs(period*1000);
|
||||
return setAnalogPeriodUs(period*1000);
|
||||
}
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
#include "MicroBit.h"
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_DBG)
|
||||
Serial pc(USBTX, USBRX);
|
||||
#endif
|
||||
|
||||
MicroBit uBit;
|
||||
InterruptIn resetButton(MICROBIT_PIN_BUTTON_RESET);
|
||||
|
||||
|
@ -16,17 +12,16 @@ int main()
|
|||
resetButton.fall(microbit_reset);
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_DBG)
|
||||
pc.baud(115200);
|
||||
|
||||
|
||||
// For diagnostics. Gives time to open the console window. :-)
|
||||
uBit.serial.baud(115200);
|
||||
for (int i=3; i>0; i--)
|
||||
{
|
||||
pc.printf("=== SUPERMAIN: Starting in %d ===\n", i);
|
||||
uBit.serial.printf("=== SUPERMAIN: Starting in %d ===\n", i);
|
||||
wait(1.0);
|
||||
}
|
||||
|
||||
pc.printf("micro:bit runtime DAL version %s\n", MICROBIT_DAL_VERSION);
|
||||
uBit.serial.printf("micro:bit runtime DAL version %s\n", MICROBIT_DAL_VERSION);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,6 +1,40 @@
|
|||
#include "MicroBit.h"
|
||||
|
||||
/**
|
||||
* Turn off warnings under gcc -Wall
|
||||
* We turn off unused-function for the entire compilation
|
||||
* unit as the compiler can't tell if a function is
|
||||
* unused until the end of the unit. The macro
|
||||
* expansion for SVCALL() in nrf_soc.h and nrf_srv.h
|
||||
* tries to leave unused-function turned off, but
|
||||
* It might be leaner to add
|
||||
* #pragram GCC system header
|
||||
* as the first line of nrf_soc.h, but that's a different
|
||||
* module ...
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* 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 ignored "-Wunused-function"
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#endif
|
||||
|
||||
#include "nrf_soc.h"
|
||||
|
||||
/*
|
||||
* Return to our predefined compiler settings.
|
||||
*/
|
||||
#if !defined(__arm)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Create new object that can sense temperature.
|
||||
|
|
|
@ -67,6 +67,7 @@ void MicroBitAccelerometerService::onDataWritten(const GattWriteCallbackParams *
|
|||
*/
|
||||
void MicroBitAccelerometerService::accelerometerUpdate(MicroBitEvent e)
|
||||
{
|
||||
(void) e; /* -Wunused-parameter */
|
||||
if (ble.getGapState().connected)
|
||||
{
|
||||
accelerometerDataCharacteristicBuffer[0] = uBit.accelerometer.getX();
|
||||
|
|
|
@ -51,6 +51,7 @@ MicroBitDFUService::MicroBitDFUService(BLEDevice &_ble) :
|
|||
|
||||
void MicroBitDFUService::onButtonA(MicroBitEvent e)
|
||||
{
|
||||
(void) e; /* -Wunused-parameter */
|
||||
if (flashCodeRequested)
|
||||
{
|
||||
releaseFlashCode();
|
||||
|
@ -63,6 +64,7 @@ void MicroBitDFUService::onButtonA(MicroBitEvent e)
|
|||
|
||||
void MicroBitDFUService::onButtonB(MicroBitEvent e)
|
||||
{
|
||||
(void) e; /* -Wunused-parameter */
|
||||
uBit.display.scroll("VERSION: TODO");
|
||||
showNameHistogram();
|
||||
}
|
||||
|
@ -117,7 +119,7 @@ void MicroBitDFUService::onDataWritten(const GattWriteCallbackParams *params)
|
|||
uBit.display.clear();
|
||||
|
||||
#if CONFIG_ENABLED(MICROBIT_DBG)
|
||||
pc.printf(" ACTIVATING BOOTLOADER.\n");
|
||||
uBit.serial.printf(" ACTIVATING BOOTLOADER.\n");
|
||||
#endif
|
||||
bootloader_start();
|
||||
}
|
||||
|
@ -126,7 +128,7 @@ void MicroBitDFUService::onDataWritten(const GattWriteCallbackParams *params)
|
|||
|
||||
case MICROBIT_DFU_OPCODE_START_PAIR:
|
||||
#if CONFIG_ENABLED(MICROBIT_DBG)
|
||||
pc.printf(" PAIRING REQUESTED.\n");
|
||||
uBit.serial.printf(" PAIRING REQUESTED.\n");
|
||||
#endif
|
||||
flashCodeRequested = true;
|
||||
break;
|
||||
|
@ -143,7 +145,7 @@ void MicroBitDFUService::onDataWritten(const GattWriteCallbackParams *params)
|
|||
if (lockCode == NRF_FICR->DEVICEID[0])
|
||||
{
|
||||
#if CONFIG_ENABLED(MICROBIT_DBG)
|
||||
pc.printf("MicroBitDFU: FLASHCODE AUTHENTICATED\n");
|
||||
uBit.serial.printf("MicroBitDFU: FLASHCODE AUTHENTICATED\n");
|
||||
#endif
|
||||
authenticated = true;
|
||||
}else{
|
||||
|
@ -158,7 +160,7 @@ void MicroBitDFUService::onDataWritten(const GattWriteCallbackParams *params)
|
|||
*/
|
||||
void MicroBitDFUService::showTick()
|
||||
{
|
||||
uBit.display.resetAnimation(0);
|
||||
uBit.display.stopAnimation();
|
||||
|
||||
uBit.display.image.setPixelValue(0,3, 255);
|
||||
uBit.display.image.setPixelValue(1,4, 255);
|
||||
|
@ -173,7 +175,7 @@ void MicroBitDFUService::showTick()
|
|||
*/
|
||||
void MicroBitDFUService::showNameHistogram()
|
||||
{
|
||||
uBit.display.resetAnimation(0);
|
||||
uBit.display.stopAnimation();
|
||||
|
||||
uint32_t n = NRF_FICR->DEVICEID[1];
|
||||
int ld = 1;
|
||||
|
|
|
@ -138,7 +138,7 @@ void MicroBitIOPinService::onDataWritten(const GattWriteCallbackParams *params)
|
|||
if (params->handle == ioPinServiceDataCharacteristic->getValueHandle())
|
||||
{
|
||||
// We have some pin data to change...
|
||||
int len = params->len;
|
||||
uint16_t len = params->len;
|
||||
IOData *data = (IOData *)params->data;
|
||||
|
||||
// There may be multiple write operaitons... take each in turn and update the pin values
|
||||
|
|
|
@ -59,7 +59,7 @@ void MicroBitLEDService::onDataWritten(const GattWriteCallbackParams *params)
|
|||
{
|
||||
for (int y=0; y<params->len; y++)
|
||||
for (int x=0; x<5; x++)
|
||||
uBit.display.image.setPixelValue(x, y, (data[y] & (0x01 << 4-x)) ? 255 : 0);
|
||||
uBit.display.image.setPixelValue(x, y, (data[y] & (0x01 << (4-x))) ? 255 : 0);
|
||||
}
|
||||
|
||||
else if (params->handle == textCharacteristicHandle)
|
||||
|
@ -94,7 +94,7 @@ void MicroBitLEDService::onDataRead(GattReadAuthCallbackParams *params)
|
|||
for (int x=0; x<5; x++)
|
||||
{
|
||||
if (uBit.display.image.getPixelValue(x, y))
|
||||
matrixCharacteristicBuffer[y] |= 0x01 << 4-x;
|
||||
matrixCharacteristicBuffer[y] |= 0x01 << (4-x);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,8 +48,7 @@ MicroBitMagnetometerService::MicroBitMagnetometerService(BLEDevice &_ble) :
|
|||
ble.gattServer().write(magnetometerPeriodCharacteristicHandle, (const uint8_t *)&magnetometerPeriodCharacteristicBuffer, sizeof(magnetometerPeriodCharacteristicBuffer));
|
||||
|
||||
ble.onDataWritten(this, &MicroBitMagnetometerService::onDataWritten);
|
||||
uBit.MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_DATA_UPDATE, this, &MicroBitMagnetometerService::magnetometerUpdate);
|
||||
|
||||
uBit.MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_DATA_UPDATE, this, &MicroBitMagnetometerService::magnetometerUpdate, MESSAGE_BUS_LISTENER_IMMEDIATE);
|
||||
uBit.MessageBus.listen(MICROBIT_ID_COMPASS, MICROBIT_COMPASS_EVT_CONFIG_NEEDED, this, &MicroBitMagnetometerService::samplePeriodUpdateNeeded);
|
||||
}
|
||||
|
||||
|
@ -70,6 +69,8 @@ void MicroBitMagnetometerService::onDataWritten(const GattWriteCallbackParams *p
|
|||
*/
|
||||
void MicroBitMagnetometerService::magnetometerUpdate(MicroBitEvent e)
|
||||
{
|
||||
(void) e; /* -Wunused-parameter */
|
||||
|
||||
if (ble.getGapState().connected)
|
||||
{
|
||||
magnetometerDataCharacteristicBuffer[0] = uBit.compass.getX();
|
||||
|
@ -91,6 +92,8 @@ void MicroBitMagnetometerService::magnetometerUpdate(MicroBitEvent e)
|
|||
*/
|
||||
void MicroBitMagnetometerService::samplePeriodUpdateNeeded(MicroBitEvent e)
|
||||
{
|
||||
(void) e; /* -Wunused-parameter */
|
||||
|
||||
// Reconfigure the compass. This might take a while...
|
||||
uBit.compass.setPeriod(magnetometerPeriodCharacteristicBuffer);
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@ MicroBitTemperatureService::MicroBitTemperatureService(BLEDevice &_ble) :
|
|||
*/
|
||||
void MicroBitTemperatureService::temperatureUpdate(MicroBitEvent e)
|
||||
{
|
||||
(void) e; /* -Wunused-parameter */
|
||||
|
||||
if (ble.getGapState().connected)
|
||||
{
|
||||
temperatureDataCharacteristicBuffer = uBit.thermometer.getTemperature();
|
||||
|
|
Loading…
Reference in New Issue