developer.mbed.org branch of Lancaster University's microbit library. The real home for this is https://github.com/lancaster-university/microbit

Dependencies:   microbit-dal

Dependents:   radio_receiver_test

Fork of microbit by Lancaster University

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MicroBit.h Source File

MicroBit.h

00001 /*
00002 The MIT License (MIT)
00003 
00004 Copyright (c) 2016 British Broadcasting Corporation.
00005 This software is provided by Lancaster University by arrangement with the BBC.
00006 
00007 Permission is hereby granted, free of charge, to any person obtaining a
00008 copy of this software and associated documentation files (the "Software"),
00009 to deal in the Software without restriction, including without limitation
00010 the rights to use, copy, modify, merge, publish, distribute, sublicense,
00011 and/or sell copies of the Software, and to permit persons to whom the
00012 Software is furnished to do so, subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included in
00015 all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00020 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00021 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00022 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00023 DEALINGS IN THE SOFTWARE.
00024 */
00025 
00026 #ifndef MICROBIT_H
00027 #define MICROBIT_H
00028 
00029 #include "mbed.h"
00030 
00031 #include "MicroBitConfig.h"
00032 #include "MicroBitHeapAllocator.h"
00033 #include "MicroBitDevice.h"
00034 #include "ErrorNo.h"
00035 #include "MicroBitSystemTimer.h"
00036 #include "Matrix4.h"
00037 #include "MicroBitCompat.h"
00038 #include "MicroBitComponent.h"
00039 #include "ManagedType.h"
00040 #include "ManagedString.h"
00041 #include "MicroBitImage.h"
00042 #include "MicroBitFont.h"
00043 #include "MicroBitEvent.h"
00044 #include "DynamicPwm.h"
00045 #include "MicroBitI2C.h"
00046 #include "NotifyEvents.h"
00047 
00048 #include "MicroBitButton.h"
00049 #include "MicroBitPin.h"
00050 #include "MicroBitCompass.h"
00051 #include "MicroBitCompassCalibrator.h"
00052 #include "MicroBitAccelerometer.h"
00053 #include "MicroBitThermometer.h"
00054 #include "MicroBitLightSensor.h"
00055 #include "MicroBitMultiButton.h"
00056 
00057 #include "MicroBitSerial.h"
00058 #include "MicroBitIO.h"
00059 #include "MicroBitMatrixMaps.h"
00060 #include "MicroBitDisplay.h"
00061 
00062 #include "MicroBitFiber.h"
00063 #include "MicroBitMessageBus.h"
00064 
00065 #include "MicroBitBLEManager.h"
00066 #include "MicroBitRadio.h"
00067 #include "MicroBitStorage.h"
00068 
00069 // MicroBit::flags values
00070 #define MICROBIT_INITIALIZED                    0x01
00071 // Disable BLE for Radio test
00072 #define MICROBIT_BLE_ENABLED    0
00073 
00074 /**
00075   * Class definition for a MicroBit device.
00076   *
00077   * Represents the device as a whole, and includes member variables that represent various device drivers
00078   * used to control aspects of the micro:bit.
00079   */
00080 class MicroBit
00081 {
00082     private:
00083 
00084     /**
00085       * A listener to perform actions as a result of Message Bus reflection.
00086       *
00087       * In some cases we want to perform lazy instantiation of components, such as
00088       * the compass and the accelerometer, where we only want to add them to the idle
00089       * fiber when someone has the intention of using these components.
00090       */
00091     void                        onListenerRegisteredEvent(MicroBitEvent evt);
00092 
00093     uint8_t                     status;
00094 
00095     public:
00096 
00097     // Serial Interface
00098     MicroBitSerial              serial;
00099 
00100     // Reset Button
00101     InterruptIn                 resetButton;
00102 
00103     // Persistent key value store
00104     MicroBitStorage             storage;
00105 
00106     // I2C Interface
00107     MicroBitI2C                 i2c;
00108 
00109     // Device level Message Bus abstraction
00110     MicroBitMessageBus          messageBus;
00111 
00112     // Member variables to represent each of the core components on the device.
00113     MicroBitDisplay             display;
00114     MicroBitButton              buttonA;
00115     MicroBitButton              buttonB;
00116     MicroBitMultiButton         buttonAB;
00117     MicroBitAccelerometer       accelerometer;
00118     MicroBitCompass             compass;
00119     MicroBitCompassCalibrator   compassCalibrator;
00120     MicroBitThermometer         thermometer;
00121 
00122     //An object of available IO pins on the device
00123     MicroBitIO                  io;
00124 
00125     // Bluetooth related member variables.
00126     MicroBitBLEManager          bleManager;
00127     MicroBitRadio               radio;
00128     BLEDevice                   *ble;
00129 
00130     /**
00131       * Constructor.
00132       *
00133       * Create a representation of a MicroBit device, which includes member variables
00134       * that represent various device drivers used to control aspects of the micro:bit.
00135       */
00136     MicroBit();
00137 
00138     /**
00139       * Post constructor initialisation method.
00140       *
00141       * This call will initialised the scheduler, memory allocator and Bluetooth stack.
00142       *
00143       * This is required as the Bluetooth stack can't be brought up in a
00144       * static context i.e. in a constructor.
00145       *
00146       * @code
00147       * uBit.init();
00148       * @endcode
00149       *
00150       * @note This method must be called before user code utilises any functionality
00151       *       contained by uBit.
00152       */
00153     void init();
00154 
00155     /**
00156       * Return the friendly name for this device.
00157       *
00158       * @return A ManagedString representing the friendly name of this device.
00159       *
00160       * @code
00161       * ManagedString name = uBit.getName();
00162       * @endcode
00163       */
00164     static ManagedString getName();
00165 
00166     /**
00167       * Return the serial number of this device.
00168       *
00169       * @return A ManagedString representing the serial number of this device.
00170       *
00171       * @code
00172       * ManagedString serialNumber = uBit.getSerial();
00173       * @endcode
00174       */
00175     static ManagedString getSerial();
00176 
00177     /**
00178       * Will reset the micro:bit when called.
00179       *
00180       * @code
00181       * uBit.reset();
00182       * @endcode
00183       */
00184     void reset();
00185 
00186     /**
00187       * Delay execution for the given amount of time.
00188       *
00189       * If the scheduler is running, this will deschedule the current fiber and perform
00190       * a power efficient, concurrent sleep operation.
00191       *
00192       * If the scheduler is disabled or we're running in an interrupt context, this
00193       * will revert to a busy wait.
00194       *
00195       * Alternatively: wait, wait_ms, wait_us can be used which will perform a blocking sleep
00196       * operation.
00197       *
00198       * @param milliseconds the amount of time, in ms, to wait for. This number cannot be negative.
00199       *
00200       * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER milliseconds is less than zero.
00201       *
00202       * @code
00203       * uBit.sleep(20); //sleep for 20ms
00204       * @endcode
00205       *
00206       * @note This operation is currently limited by the rate of the system timer, therefore
00207       *       the granularity of the sleep operation is limited to 6 ms unless the rate of
00208       *       the system timer is modified.
00209       */
00210     void sleep(uint32_t milliseconds);
00211 
00212     /**
00213       * Seed the pseudo random number generator using the hardware random number generator.
00214       *
00215       * @code
00216       * uBit.seedRandom();
00217       * @endcode
00218       */
00219     void seedRandom();
00220 
00221     /**
00222       * Seed the pseudo random number generator using the given value.
00223       *
00224       * @param seed The 32-bit value to seed the generator with.
00225       *
00226       * @code
00227       * uBit.seedRandom(0xBB5EED);
00228       * @endcode
00229       */
00230     void seedRandom(uint32_t seed);
00231 
00232 
00233     /**
00234       * Generate a random number in the given range.
00235       * We use a simple Galois LFSR random number generator here,
00236       * as a Galois LFSR is sufficient for our applications, and much more lightweight
00237       * than the hardware random number generator built int the processor, which takes
00238       * a long time and uses a lot of energy.
00239       *
00240       * KIDS: You shouldn't use this is the real world to generate cryptographic keys though...
00241       * have a think why not. :-)
00242       *
00243       * @param max the upper range to generate a number for. This number cannot be negative.
00244       *
00245       * @return A random, natural number between 0 and the max-1. Or MICROBIT_INVALID_VALUE if max is <= 0.
00246       *
00247       * @code
00248       * uBit.random(200); //a number between 0 and 199
00249       * @endcode
00250       */
00251     int random(int max);
00252 
00253     /**
00254       * Determine the time since this MicroBit was last reset.
00255       *
00256       * @return The time since the last reset, in milliseconds.
00257       *
00258       * @note This will value overflow after 1.6 months.
00259       */
00260       //TODO: handle overflow case.
00261     unsigned long systemTime();
00262 
00263     /**
00264       * Determine the version of the micro:bit runtime currently in use.
00265       *
00266       * @return A textual description of the version of the micro:bit runtime that
00267       *         is currently running on this device.
00268       */
00269     const char *systemVersion();
00270 
00271     /**
00272       * Triggers a microbit panic where an loop will display a panic face
00273       * and the status code, if provided.
00274       *
00275       * This loop will continue for panic_timeout iterations, defaults to 0 (infinite).
00276       *
00277       * panic_timeout can be configured via a call to microbit_panic_timeout.
00278       *
00279       * @param statusCode the status code of the associated error.
00280       *
00281       * @code
00282       * microbit_panic_timeout(4);
00283       *
00284       * // will display loop for 4 iterations.
00285       * uBit.panic(10);
00286       * @endcode
00287       */
00288     void panic(int statusCode = 0);
00289 
00290     /**
00291       * Add a component to the array of system components. This component will then receive
00292       * periodic callbacks, once every tick period in interrupt context.
00293       *
00294       * @param component The component to add.
00295       *
00296       * @return MICROBIT_OK on success or MICROBIT_NO_RESOURCES if the component array is full.
00297       *
00298       * @code
00299       * // heap allocated - otherwise it will be paged out!
00300       * MicroBitDisplay* display = new MicroBitDisplay();
00301       *
00302       * uBit.addSystemComponent(display);
00303       * @endcode
00304       *
00305       * @note This interface is now deprecated, and will be removed in the next major release. Please use system_timer_add_component().
00306       */
00307     int addSystemComponent(MicroBitComponent *component);
00308 
00309     /**
00310       * Remove a component from the array of system components. This component will no longer receive
00311       * periodic callbacks.
00312       *
00313       * @param component The component to remove.
00314       *
00315       * @return MICROBIT_OK on success or MICROBIT_INVALID_PARAMETER is returned if the given component has not been previously added.
00316       *
00317       * @code
00318       * // heap allocated - otherwise it will be paged out!
00319       * MicroBitDisplay* display = new MicroBitDisplay();
00320       *
00321       * uBit.addSystemComponent(display);
00322       *
00323       * uBit.removeSystemComponent(display);
00324       * @endcode
00325       *
00326       * @note This interface is now deprecated, and will be removed in the next major release. Please use system_timer_remove_component().
00327       */
00328     int removeSystemComponent(MicroBitComponent *component);
00329 
00330     /**
00331       * Adds a component to the array of idle thread components, which are processed
00332       * when the run queue is empty.
00333       *
00334       * The system timer will poll isIdleCallbackNeeded on each component to determine
00335       * if the scheduler should schedule the idle_task imminently.
00336       *
00337       * @param component The component to add to the array.
00338       *
00339       * @return MICROBIT_OK on success or MICROBIT_NO_RESOURCES if the fiber components array is full.
00340       *
00341       * @code
00342       * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
00343       *
00344       * // heap allocated - otherwise it will be paged out!
00345       * MicroBitAccelerometer* accelerometer = new MicroBitAccelerometer(i2c);
00346       *
00347       * fiber_add_idle_component(accelerometer);
00348       * @endcode
00349       *
00350       * @note This interface is now deprecated, and will be removed in the next major release. Please use fiber_add_idle_component().
00351       */
00352     int addIdleComponent(MicroBitComponent *component);
00353 
00354     /**
00355       * Remove a component from the array of idle thread components
00356       *
00357       * @param component The component to remove from the idle component array.
00358       *
00359       * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previously added.
00360       *
00361       * @code
00362       * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
00363       *
00364       * // heap allocated - otherwise it will be paged out!
00365       * MicroBitAccelerometer* accelerometer = new MicroBitAccelerometer(i2c);
00366       *
00367       * uBit.addIdleComponent(accelerometer);
00368       *
00369       * uBit.removeIdleComponent(accelerometer);
00370       * @endcode
00371       *
00372       * @note This interface is now deprecated, and will be removed in the next major release. Please use fiber_remove_idle_component().
00373       */
00374     int removeIdleComponent(MicroBitComponent *component);
00375 };
00376 
00377 /**
00378   * Return the friendly name for this device.
00379   *
00380   * @return A ManagedString representing the friendly name of this device.
00381   *
00382   * @code
00383   * ManagedString name = uBit.getName();
00384   * @endcode
00385   */
00386 inline ManagedString MicroBit::getName()
00387 {
00388     return ManagedString(microbit_friendly_name());
00389 }
00390 
00391 /**
00392   * Return the serial number of this device.
00393   *
00394   * @return A ManagedString representing the serial number of this device.
00395   *
00396   * @code
00397   * ManagedString serialNumber = uBit.getSerial();
00398   * @endcode
00399   */
00400 inline ManagedString MicroBit::getSerial()
00401 {
00402     // We take to 16 bit numbers here, as we want the full range of ID bits, but don't want negative numbers...
00403     int n1 = microbit_serial_number() & 0xffff;
00404     int n2 = (microbit_serial_number() >> 16) & 0xffff;
00405 
00406     // Simply concat the two numbers.
00407     ManagedString s1(n1);
00408     ManagedString s2(n2);
00409 
00410     return s1 + s2;
00411 }
00412 
00413 /**
00414   * Will reset the micro:bit when called.
00415   *
00416   * @code
00417   * uBit.reset();
00418   * @endcode
00419   */
00420 inline void MicroBit::reset()
00421 {
00422     if(ble && ble->getGapState().connected) {
00423 
00424         // We have a connected BLE peer. Disconnect the BLE session.
00425         ble->gap().disconnect(Gap::REMOTE_USER_TERMINATED_CONNECTION);
00426 
00427         // Wait a little while for the connection to drop.
00428         wait_ms(100);
00429     }
00430 
00431     microbit_reset();
00432 }
00433 
00434 /**
00435   * Delay execution for the given amount of time.
00436   *
00437   * If the scheduler is running, this will deschedule the current fiber and perform
00438   * a power efficient, concurrent sleep operation.
00439   *
00440   * If the scheduler is disabled or we're running in an interrupt context, this
00441   * will revert to a busy wait.
00442   *
00443   * Alternatively: wait, wait_ms, wait_us can be used which will perform a blocking sleep
00444   * operation.
00445   *
00446   * @param milliseconds the amount of time, in ms, to wait for. This number cannot be negative.
00447   *
00448   * @return MICROBIT_OK on success, MICROBIT_INVALID_PARAMETER milliseconds is less than zero.
00449   *
00450   * @code
00451   * uBit.sleep(20); //sleep for 20ms
00452   * @endcode
00453   *
00454   * @note This operation is currently limited by the rate of the system timer, therefore
00455   *       the granularity of the sleep operation is limited to 6 ms unless the rate of
00456   *       the system timer is modified.
00457   */
00458 inline void MicroBit::sleep(uint32_t milliseconds)
00459 {
00460     fiber_sleep(milliseconds);
00461 }
00462 
00463 /**
00464   * Generate a random number in the given range.
00465   * We use a simple Galois LFSR random number generator here,
00466   * as a Galois LFSR is sufficient for our applications, and much more lightweight
00467   * than the hardware random number generator built int the processor, which takes
00468   * a long time and uses a lot of energy.
00469   *
00470   * KIDS: You shouldn't use this is the real world to generate cryptographic keys though...
00471   * have a think why not. :-)
00472   *
00473   * @param max the upper range to generate a number for. This number cannot be negative.
00474   *
00475   * @return A random, natural number between 0 and the max-1. Or MICROBIT_INVALID_VALUE if max is <= 0.
00476   *
00477   * @code
00478   * uBit.random(200); //a number between 0 and 199
00479   * @endcode
00480   */
00481 inline int MicroBit::random(int max)
00482 {
00483     return microbit_random(max);
00484 }
00485 
00486 /**
00487   * Seed the pseudo random number generator using the hardware random number generator.
00488   *
00489   * @code
00490   * uBit.seedRandom();
00491   * @endcode
00492   */
00493 inline void MicroBit::seedRandom()
00494 {
00495     microbit_seed_random();
00496 }
00497 
00498 
00499 /**
00500   * Seed the pseudo random number generator using the given value.
00501   *
00502   * @param seed The 32-bit value to seed the generator with.
00503   *
00504   * @code
00505   * uBit.seedRandom(0xBB5EED);
00506   * @endcode
00507   */
00508 inline void MicroBit::seedRandom(uint32_t seed)
00509 {
00510     microbit_seed_random(seed);
00511 }
00512 
00513 
00514 /**
00515   * Add a component to the array of system components. This component will then receive
00516   * periodic callbacks, once every tick period in interrupt context.
00517   *
00518   * @param component The component to add.
00519   *
00520   * @return MICROBIT_OK on success or MICROBIT_NO_RESOURCES if the component array is full.
00521   *
00522   * @code
00523   * // heap allocated - otherwise it will be paged out!
00524   * MicroBitDisplay* display = new MicroBitDisplay();
00525   *
00526   * uBit.addSystemComponent(display);
00527   * @endcode
00528   *
00529   * @note This interface is now deprecated, and will be removed in the next major release. Please use system_timer_add_component().
00530   */
00531 inline int MicroBit::addSystemComponent(MicroBitComponent *component)
00532 {
00533     return system_timer_add_component(component);
00534 }
00535 
00536 /**
00537   * Remove a component from the array of system components. This component will no longer receive
00538   * periodic callbacks.
00539   *
00540   * @param component The component to remove.
00541   *
00542   * @return MICROBIT_OK on success or MICROBIT_INVALID_PARAMETER is returned if the given component has not been previously added.
00543   *
00544   * @code
00545   * // heap allocated - otherwise it will be paged out!
00546   * MicroBitDisplay* display = new MicroBitDisplay();
00547   *
00548   * uBit.addSystemComponent(display);
00549   *
00550   * uBit.removeSystemComponent(display);
00551   * @endcode
00552   *
00553   * @note This interface is now deprecated, and will be removed in the next major release. Please use system_timer_remove_component().
00554   */
00555 inline int MicroBit::removeSystemComponent(MicroBitComponent *component)
00556 {
00557     return system_timer_remove_component(component);
00558 }
00559 
00560 /**
00561   * Adds a component to the array of idle thread components, which are processed
00562   * when the run queue is empty.
00563   *
00564   * The system timer will poll isIdleCallbackNeeded on each component to determine
00565   * if the scheduler should schedule the idle_task imminently.
00566   *
00567   * @param component The component to add to the array.
00568   *
00569   * @return MICROBIT_OK on success or MICROBIT_NO_RESOURCES if the fiber components array is full.
00570   *
00571   * @code
00572   * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
00573   *
00574   * // heap allocated - otherwise it will be paged out!
00575   * MicroBitAccelerometer* accelerometer = new MicroBitAccelerometer(i2c);
00576   *
00577   * fiber_add_idle_component(accelerometer);
00578   * @endcode
00579   *
00580   * @note This interface is now deprecated, and will be removed in the next major release. Please use fiber_add_idle_component().
00581   */
00582 inline int MicroBit::addIdleComponent(MicroBitComponent *component)
00583 {
00584     return fiber_add_idle_component(component);
00585 }
00586 
00587 /**
00588   * Remove a component from the array of idle thread components
00589   *
00590   * @param component The component to remove from the idle component array.
00591   *
00592   * @return MICROBIT_OK on success. MICROBIT_INVALID_PARAMETER is returned if the given component has not been previously added.
00593   *
00594   * @code
00595   * MicroBitI2C i2c(I2C_SDA0, I2C_SCL0);
00596   *
00597   * // heap allocated - otherwise it will be paged out!
00598   * MicroBitAccelerometer* accelerometer = new MicroBitAccelerometer(i2c);
00599   *
00600   * uBit.addIdleComponent(accelerometer);
00601   *
00602   * uBit.removeIdleComponent(accelerometer);
00603   * @endcode
00604   *
00605   * @note This interface is now deprecated, and will be removed in the next major release. Please use fiber_remove_idle_component().
00606   */
00607 inline int MicroBit::removeIdleComponent(MicroBitComponent *component)
00608 {
00609     return fiber_remove_idle_component(component);
00610 }
00611 
00612 
00613 /**
00614   * Determine the time since this MicroBit was last reset.
00615   *
00616   * @return The time since the last reset, in milliseconds.
00617   *
00618   * @note This will value overflow after 1.6 months.
00619   */
00620 inline unsigned long MicroBit::systemTime()
00621 {
00622     return system_timer_current_time();
00623 }
00624 
00625 
00626 /**
00627   * Determine the version of the micro:bit runtime currently in use.
00628   *
00629   * @return A textual description of the version of the micro:bit runtime that
00630   *         is currently running on this device.
00631   */
00632 inline const char *MicroBit::systemVersion()
00633 {
00634     return microbit_dal_version();
00635 }
00636 
00637 /**
00638   * Triggers a microbit panic where an loop will display a panic face
00639   * and the status code, if provided.
00640   *
00641   * This loop will continue for panic_timeout iterations, defaults to 0 (infinite).
00642   *
00643   * panic_timeout can be configured via a call to microbit_panic_timeout.
00644   *
00645   * @param statusCode the status code of the associated error.
00646   *
00647   * @code
00648   * microbit_panic_timeout(4);
00649   *
00650   * // will display loop for 4 iterations.
00651   * uBit.panic(10);
00652   * @endcode
00653   */
00654 inline void MicroBit::panic(int statusCode)
00655 {
00656     //show error and enter infinite while
00657     microbit_panic(statusCode);
00658 }
00659 
00660 #endif